为什么我在 Python class 定义的生成器中得到这个 NameError?
Why do I get this NameError in a generator within a Python class definition?
在 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)
产生:
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)
NameError: name 'b' is not defined
为什么会出现此错误?为什么我在上一行没有得到这个错误?
我花了很长时间进行试验,并且我对为什么会出现此错误有一个理论。我不确定,但这确实解释了为什么它适用于 c
而不是 d
。我希望这对你有帮助,如果你不同意,请发表评论:)
def Tuple(this):
print(a) # this always works
try:
print(b) # this always gives an error
except NameError:
print("...b is not defined")
try:
return tuple(this) # this only gives an error for d and e
except NameError:
print("...couldn't make it a tuple")
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)
e = Tuple((i,j,k) for i in a for j in b for k in (5, 6))
f = Tuple((i,j,k) for j in b for i in (5, 6) for k in a)
print("\nc:", c,"\nd:", d,"\ne:", e,"\nf:", f)
发生了什么:每次我调用Tuple()
函数时,b
没有定义,但是a
总是被定义。这解释了为什么 d
和 e
出现错误,但它没有解释为什么 c
和 f
即使 b
是 'not defined' 也能工作]
我的理论: 第一个 for
循环是在将整个事物转换为元组之前计算的。例如,如果您尝试这样做:Tuple((a, b, c) for a in loop1, for b in loop2 for c in loop3)
,在 Foo class 中它会首先计算 for a in loop1
,然后它会移动到 foo 并计算循环 2 和 3。
总结:
- 先做for循环
- 移动到元组函数
- 做剩下的循环
- 如果第二个或第三个循环中的变量在 class Foo
中,则会发生错误
在我看来,错误的产生是因为b
被定义为class变量。要正确使用它,您需要这样对待它 (self.b
)。
另外,你应该使用构造函数:
a = (1, 2)
class Foo(object):
def __init__(self):
self.b = (3, 4)
self.c = tuple((i, j) for j in self.b for i in a)
self.d = tuple((i, j) for i in a for j in self.b)
这是一个更清晰的代码。它表现得很好。希望对你有帮助。
编辑:如果您不想使用 __init__
,也可以使用以下方法获得 c
和 d
:
a = (1, 2)
class Foo(object):
b = (3, 4)
def get_c(self):
return tuple((i, j) for j in self.b for i in a)
def get_d(self):
return tuple((i, j) for i in a for j in self.b)
这也很好用。
您可以像这样尝试这两种实现方式:
inst = Foo()
# 1st one
print(inst.c)
print(inst.d)
# 2nd one
print(inst.get_c())
print(inst.get_d())
这是因为表达式for i in a
有一个局部变量范围,而表达式for j in b
在范围内,因此,没有b
被发现。
实际上,如果你写 c = tuple((i, j) for i in a for j in b)
,它会抛出同样的异常。
解决方案将 b
放入 class 定义的范围(正如您已经做的那样)并通过 self.b
引用它。
针对您的具体情况的 解决方案 是使用 itertools:
d = tuple(itertools.product(a, b))
看似意外行为的解释是双重的:
裸 class 属性,例如 b
只能在 root class 范围 中访问。见 pep 227:
Names in class scope are not accessible. Names are resolved in the innermost enclosing function scope. If a class definition occurs in a chain of nested scopes, the resolution process skips class definitions.
生成器中的嵌套循环并不像您预期的那样运行。第一个循环实际上是最外层的,第二个是最内层的。来自 python docs:
Subsequent for clauses cannot be evaluated immediately since they may depend on the previous for loop. For example: (x*y for x in range(10) for y in bar(x)).
第二点可以用换行来说明。
d = tuple((i,j)
for i in a
for j in b)
这意味着 b
实际上是从内部循环(嵌套范围)引用的,因此抛出 NameError
。然而,在第一个生成器中,引用位于外部,它工作正常。
在 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)
产生:
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)
NameError: name 'b' is not defined
为什么会出现此错误?为什么我在上一行没有得到这个错误?
我花了很长时间进行试验,并且我对为什么会出现此错误有一个理论。我不确定,但这确实解释了为什么它适用于 c
而不是 d
。我希望这对你有帮助,如果你不同意,请发表评论:)
def Tuple(this):
print(a) # this always works
try:
print(b) # this always gives an error
except NameError:
print("...b is not defined")
try:
return tuple(this) # this only gives an error for d and e
except NameError:
print("...couldn't make it a tuple")
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)
e = Tuple((i,j,k) for i in a for j in b for k in (5, 6))
f = Tuple((i,j,k) for j in b for i in (5, 6) for k in a)
print("\nc:", c,"\nd:", d,"\ne:", e,"\nf:", f)
发生了什么:每次我调用Tuple()
函数时,b
没有定义,但是a
总是被定义。这解释了为什么 d
和 e
出现错误,但它没有解释为什么 c
和 f
即使 b
是 'not defined' 也能工作]
我的理论: 第一个 for
循环是在将整个事物转换为元组之前计算的。例如,如果您尝试这样做:Tuple((a, b, c) for a in loop1, for b in loop2 for c in loop3)
,在 Foo class 中它会首先计算 for a in loop1
,然后它会移动到 foo 并计算循环 2 和 3。
总结:
- 先做for循环
- 移动到元组函数
- 做剩下的循环
- 如果第二个或第三个循环中的变量在 class Foo 中,则会发生错误
在我看来,错误的产生是因为b
被定义为class变量。要正确使用它,您需要这样对待它 (self.b
)。
另外,你应该使用构造函数:
a = (1, 2)
class Foo(object):
def __init__(self):
self.b = (3, 4)
self.c = tuple((i, j) for j in self.b for i in a)
self.d = tuple((i, j) for i in a for j in self.b)
这是一个更清晰的代码。它表现得很好。希望对你有帮助。
编辑:如果您不想使用 __init__
,也可以使用以下方法获得 c
和 d
:
a = (1, 2)
class Foo(object):
b = (3, 4)
def get_c(self):
return tuple((i, j) for j in self.b for i in a)
def get_d(self):
return tuple((i, j) for i in a for j in self.b)
这也很好用。 您可以像这样尝试这两种实现方式:
inst = Foo()
# 1st one
print(inst.c)
print(inst.d)
# 2nd one
print(inst.get_c())
print(inst.get_d())
这是因为表达式for i in a
有一个局部变量范围,而表达式for j in b
在范围内,因此,没有b
被发现。
实际上,如果你写 c = tuple((i, j) for i in a for j in b)
,它会抛出同样的异常。
解决方案将 b
放入 class 定义的范围(正如您已经做的那样)并通过 self.b
引用它。
针对您的具体情况的 解决方案 是使用 itertools:
d = tuple(itertools.product(a, b))
看似意外行为的解释是双重的:
裸 class 属性,例如
b
只能在 root class 范围 中访问。见 pep 227:Names in class scope are not accessible. Names are resolved in the innermost enclosing function scope. If a class definition occurs in a chain of nested scopes, the resolution process skips class definitions.
生成器中的嵌套循环并不像您预期的那样运行。第一个循环实际上是最外层的,第二个是最内层的。来自 python docs:
Subsequent for clauses cannot be evaluated immediately since they may depend on the previous for loop. For example: (x*y for x in range(10) for y in bar(x)).
第二点可以用换行来说明。
d = tuple((i,j)
for i in a
for j in b)
这意味着 b
实际上是从内部循环(嵌套范围)引用的,因此抛出 NameError
。然而,在第一个生成器中,引用位于外部,它工作正常。