集合推导式(set comprehension)行为不符合预期问题求助
为什么集合推导式和列表推导式的
locals()行为不一致? 这个问题的核心原因在于Python 2中列表推导式和集合推导式的作用域规则不同,具体拆解如下:
1. 列表推导式的作用域(Python 2)
Python 2的列表推导式不会创建新的作用域,它的代码直接在当前的外部作用域中执行。这意味着你在列表推导式里调用locals()时,拿到的是外部作用域的局部变量字典——里面包含了你之前定义的a=1、v=["a","b","c"]这些变量。
所以当循环到e="a"时,locals().get("a")会返回1(不是None),因此"a"被过滤掉,最终得到['b', 'c'],符合你的预期。
2. 集合推导式的作用域(Python 2)
集合推导式(Python 2.7新增)和生成器表达式、字典推导式一样,会创建一个嵌套的新作用域,就像一个临时的小函数内部环境。在这个作用域里,locals()返回的是推导式自身的局部变量字典——里面只有循环变量e,完全不包含外部作用域的a变量。
所以当循环到e="a"时,locals().get("a")会返回None,满足条件,因此"a"被保留在集合结果中,最终得到set(['a', 'c', 'b'])。
直观验证差异
你可以在推导式里打印locals(),直接看到两种推导式的环境区别:
集合推导式中打印locals()
>>> a = 1 >>> v = ["a", "b", "c"] >>> {e for e in v if print(locals()) or locals().get(e) is None} {'e': 'a'} {'e': 'b'} {'e': 'c'} set(['a', 'c', 'b'])
每次循环时,locals()里只有e这一个键,完全没有外部的a。
列表推导式中打印locals()
>>> [e for e in v if print(locals()) or locals().get(e) is None] {'__builtins__': <module '__builtin__' (built-in)>, 'a': 1, 'v': ['a', 'b', 'c'], 'e': 'a'} {'__builtins__': <module '__builtin__' (built-in)>, 'a': 1, 'v': ['a', 'b', 'c'], 'e': 'b'} {'__builtins__': <module '__builtin__' (built-in)>, 'a': 1, 'v': ['a', 'b', 'c'], 'e': 'c'} ['b', 'c']
这里的locals()包含了外部定义的a,所以能正确过滤掉"a"。
补充:Python 3中的变化
如果是在Python 3中,列表推导式也会创建新的作用域,这时候两种推导式的结果会一致——都会返回包含"a"的集合/列表:
>>> a = 1 >>> v = ["a", "b", "c"] >>> {e for e in v if locals().get(e) is None} {'a', 'b', 'c'} >>> [e for e in v if locals().get(e) is None] ['a', 'b', 'c']
内容的提问来源于stack exchange,提问作者zhaomin
相关产品推荐
相关产品推荐

