Python范围规则究竟是什么?
如果我有一些代码:
code1
class Foo:
code2
def spam.....
code3
for code4..:
code5
x()
Run Code Online (Sandbox Code Playgroud)
在哪里x找到?一些可能的选择包括以下列表:
在执行期间,当函数spam在其他地方传递时,也存在上下文.也许lambda函数的传递方式有点不同?
某处必须有简单的参考或算法.对于中级Python程序员来说,这是一个令人困惑的世界.
理解与范围界定有一些意想不到的相互作用.这是预期的行为吗?
我有一个方法:
def leave_room(self, uid):
u = self.user_by_id(uid)
r = self.rooms[u.rid]
other_uids = [ouid for ouid in r.users_by_id.keys() if ouid != u.uid]
other_us = [self.user_by_id(uid) for uid in other_uids]
r.remove_user(uid) # OOPS! uid has been re-bound by the list comprehension above
# Interestingly, it's rebound to the last uid in the list, so the error only shows
# up when len > 1
Run Code Online (Sandbox Code Playgroud)
冒着抱怨的风险,这是一个残酷的错误来源.当我编写新代码时,我偶尔会发现由于重新绑定而导致非常奇怪的错误 - 即使现在我知道这是一个问题.我需要制定一个规则,比如"总是用下划线列出列表推导中的临时变量",但即使这样也不是万无一失的.
这种随机定时炸弹等待的事实否定了列表理解的所有"易用性".
解释我的问题的最好方法是举个例子:
example.py:
class A(object):
integers = [1, 2, 3]
singles = [i for i in integers]
class B(object):
integers = [1, 2, 3]
pairs = [(i, j) for i in integers for j in integers]
Run Code Online (Sandbox Code Playgroud)
当我在python 2下运行它时工作正常,但在python 3下我得到一个NameErrorfor class B(但不是class A):
$ python example.py
Traceback (most recent call last):
File "example.py", line 6, in <module>
class B(object):
File "example.py", line 8, in B
pairs = [(i, j) for i in integers for j in integers]
File …Run Code Online (Sandbox Code Playgroud) 我刚刚阅读了这个问题的答案:从类定义中的列表解析中访问类变量
它帮助我理解为什么以下代码导致NameError: name 'x' is not defined:
class A:
x = 1
data = [0, 1, 2, 3]
new_data = [i + x for i in data]
print(new_data)
Run Code Online (Sandbox Code Playgroud)
在NameError因为出现x在列表理解的特殊范围没有定义.但我无法理解为什么下面的代码没有任何错误.
class A:
x = 1
data = [0, 1, 2, 3]
new_data = [i for i in data]
print(new_data)
Run Code Online (Sandbox Code Playgroud)
我得到了输出[0, 1, 2, 3].但是我期待这个错误:NameError: name 'data' is not defined因为我期望就像在前面的例子中一样,名称x没有在列表推导的范围中定义,类似地,名称data也不会在列表推导的范围中定义.
能否帮助我理解为什么x列表理解范围没有定义但是data?
我在一个文件中有这个代码
class Sudoku(dict):
COLUMNS = [
{(x, y) for y in xrange(9)} for x in xrange(9)
]
Run Code Online (Sandbox Code Playgroud)
当我跑步时python broken.py,我得到追溯:
Traceback (most recent call last):
File "U:\broken.py", line 1, in <module>
class Sudoku(dict):
File "U:\broken.py", line 3, in Sudoku
{(x, y) for y in xrange(9)} for x in xrange(9)
File "U:\broken.py", line 3, in <setcomp>
{(x, y) for y in xrange(9)} for x in xrange(9)
NameError: global name 'x' is not defined
[Finished in 0.1s with exit code 1] …Run Code Online (Sandbox Code Playgroud) 我正在运行Python 2.7.8(Anaconda Distribution),这段代码失败了.这看起来像Python实现中的一个错误,但我错过了什么?
class C:
x = {2 : 1}
y = {w for w in x if x[w]==1}
Run Code Online (Sandbox Code Playgroud)
运行此代码会出现以下错误消息:
NameError:未定义全局名称"x"
错误信息对我来说似乎也是错误的.
请注意,以下两个非常相似的代码片段可以正常工作:
# this works fine:
class C:
x = {2 : 1}
y = [w for w in x if x[w]==1]
# this works fine too:
x = {2 : 1}
y = {w for w in x if x[w]==1}
Run Code Online (Sandbox Code Playgroud) 在Python 3.5.0中这段代码:
a = (1,2)
class Foo(object):
b = (3,4)
c = tuple((i,j) for j in b for i in a)
d = tuple((i,j) for i in a for j in b)
Run Code Online (Sandbox Code Playgroud)
生产:
Traceback (most recent call last):
File "genexprtest.py", line 2, in <module>
class Foo(object):
File "genexprtest.py", line 5, in Foo
d = tuple((i,j) for i in a for j in b)
File "genexprtest.py", line 5, in <genexpr>
d = tuple((i,j) for i in a for j in b) …Run Code Online (Sandbox Code Playgroud) 在下面的代码中,该mc分配在Python 2和3中正常工作.
cc在类中使用相同列表推导的赋值在Python 2中有效,但在Python 3中失败.
什么解释了这种行为?
ml1 = "a b c".split()
ml2 = "1 2 3".split()
mc = [ i1 + i2 for i1 in ml1 for i2 in ml2 ]
class Foo(object):
cl1 = ml1
cl2 = ml2
cc1 = [ i1 for i1 in cl1 ]
cc2 = [ i2 for i2 in cl2 ]
cc = [ i1 + i2 for i1 in cl1 for i2 in cl2 ]
print("mc = ", mc)
foo …Run Code Online (Sandbox Code Playgroud) 在引用全局变量时,可以看到函数和类以不同方式处理它.第一个很好,第二个导致错误:
x = 10
class Foo():
x = x + 1
a = foo()
Run Code Online (Sandbox Code Playgroud)
VS:
x = 10
def faa():
x = x + 1
faa()
Run Code Online (Sandbox Code Playgroud)
在 Python执行模型中,这被描述为:
类定义是可以使用和定义名称的可执行语句.这些引用遵循名称解析的常规规则,但在全局命名空间中查找未绑定的局部变量.
但为什么?
唯一的其他提示我所遇到的是该位:
然后使用新创建的本地命名空间和原始全局命名空间,在新的执行框架中执行类的套件(请参阅命名和绑定一节).(通常,套件仅包含函数定义.)当类的套件完成执行时,其执行帧将被丢弃,但其本地名称空间将被保存.4然后使用基类的继承列表和属性字典的已保存本地名称空间创建类对象.
这仍然没有解释为什么这应该导致在全局命名空间中查找未绑定的本地人.
这两个链接都来自这个答案,虽然没有详细说明原因.
是否有任何python大师能够解释为什么这段代码不起作用:
def f(code_str):
exec(code_str)
code = """
g = 5
x = [g for i in range(5)]
"""
f(code)
Run Code Online (Sandbox Code Playgroud)
错误:
Traceback (most recent call last):
File "py_exec_test.py", line 9, in <module>
f(code)
File "py_exec_test.py", line 2, in f
exec(code_str)
File "<string>", line 3, in <module>
File "<string>", line 3, in <listcomp>
NameError: name 'g' is not defined
Run Code Online (Sandbox Code Playgroud)
虽然这个工作正常:
code = """
g = 5
x = [g for i in range(5)]
"""
exec(code)
Run Code Online (Sandbox Code Playgroud)
我知道它与locals和globals有关,就好像我从我的主范围传递exec函数locals和globals它工作正常,但我不完全理解发生了什么.
这可能是Cython的一个错误吗?
编辑:尝试使用python 3.4.0和python 3.4.3
python ×10
scope ×4
class ×2
python-3.x ×2
attributes ×1
binding ×1
cpython ×1
function ×1
generator ×1
nameerror ×1
python-2.7 ×1
python-3.4 ×1
python-3.5 ×1
python-exec ×1
scoping ×1