class Some(object):
tokens = [ ... list of strings ... ]
untokenized = [tokens.index(a) for a in [... some other list of strings ...]]
... etc ...
some = Some()
Run Code Online (Sandbox Code Playgroud)
这适用于Python2.7.然而python3说:
Traceback (most recent call last):
File "./test.py", line 17, in <module>
class Some(object):
File "./test.py", line 42, in Some
untokenized = [tokens.index(a) for a in [... some other list of strings ...]]
File "./test.py", line 42, in <listcomp>
untokenized = [tokens.index(a) for a in [... some other list of strings ...]]
NameError: global name 'tokens' is not defined
Run Code Online (Sandbox Code Playgroud)
虽然我可以解决这个问题,但我真的想知道Python2和Python3之间的区别.我已经阅读了python 2-> 3更改文档,但我无法识别与我的问题相关的任何描述.此外2to3工具不抱怨在我的代码什么.
顺便说一句,虽然我现在无法回忆起这种情况,但我也只有类似python2 (我甚至没有尝试过3),我认为这应该有效(在一个类中):
def some_method(self):
return {a: eval("self." + a) for a in dir(self) if not a.startswith("_")}
Run Code Online (Sandbox Code Playgroud)
然而它导致python2说:NameError: name 'self' is not defined
我还没有用python3尝试过这个,但是例如这有效:
[eval("self." + a) for a in dir(self) if not a.startswith("_")]
Run Code Online (Sandbox Code Playgroud)
如果我将前一个示例的相关部分更改为此示例(确定示例本身有点愚蠢,但它至少显示我的问题).现在我很好奇,为什么self似乎没有为第一个例子定义,但它是第二个?看来,我有类似的问题,我的原始问题是关于,但使用列表生成器表达它可以工作,但不是在python3.嗯......
在我的python2 - > 3问题之后我提到了这一点,因为所有这些似乎都是关于根据python解释器没有定义某些东西的问题(也许我的问题的第二部分是无关的?).我现在感到很困惑.请告诉我我的错误(因为我确信我当然错过了一些东西).
eca*_*mur 14
正如Wooble所说,问题是类没有词法范围(实际上,在Python 2或Python 3中).相反,它们具有不构成范围的本地命名空间.这意味着类定义中的表达式可以访问命名空间的内容:
class C:
a = 2
b = a + 2 # b = 4
Run Code Online (Sandbox Code Playgroud)
但是在类体内引入的范围无法访问其命名空间:
class C:
a = 2
def foo(self):
return a # NameError: name 'a' is not defined, use return self.__class__.a
Run Code Online (Sandbox Code Playgroud)
Python 2和Python 3之间的区别在于,在Python 2中,列表推导不会引入新的范围:
[a for a in range(3)]
print a # prints 2
Run Code Online (Sandbox Code Playgroud)
而在Python 3中他们做:
[a for a in range(3)]
print(a) # NameError: name 'a' is not defined
Run Code Online (Sandbox Code Playgroud)
这在Python 3中有所改变,原因有两个,包括使列表推导的行为与generator-expressions(genexps)相同; (a for a in range(3))在Python 2和Python 3中都有自己的范围.
因此,在类的主体内,Python 2 genexp或Python 3 listcomp或genexp引入了新的作用域,因此无法访问类定义本地名称空间.
使genexp/listcomp访问类定义命名空间中的名称的方法是使用函数或lambda引入新范围:
class C:
a = 2
b = (lambda a=a: [a + i for i in range(3)])()
Run Code Online (Sandbox Code Playgroud)
eval问题您的eval示例的问题是eval默认情况下在本地范围内计算其参数; 因为Python 2列表eval推导具有共享封闭范围的上述行为,可以访问方法范围,但是genexp或Python 3 listcomp本地范围只有编译器可以从封闭范围中知道的任何内容(因为genexp/listcomp范围)是封闭):
def bar(x):
return list(eval('x') + x for i in range(3))
bar(5) # returns [10, 10, 10]
def baz(x):
return list(eval('x') for i in range(3))
baz(5) # NameError: name 'x' is not defined
Run Code Online (Sandbox Code Playgroud)
正如Martijn所说,而不是eval你应该使用getattr.
| 归档时间: |
|
| 查看次数: |
1610 次 |
| 最近记录: |