这是一个片段:
class Foo(object):
def bar(self, x):
def baz(y):
print locals()['self']
..
return baz(..)
foo = Foo()
foo.bar(..)
我有2个盒子。在使用Python 2.5的Windows Vista上调用foo.bar(..)
有效。在Ubuntu上使用Python 2.7调用foo.bar(..)
会引发KeyError
,无法在locals()dict中找到self
。
有什么想法吗?
编辑:我要道歉;在尝试构建问题时,我似乎误导了你。嵌套函数中的实际代码会评估来自DSL的字符串:
r = re.compile(r'\$(\w+)')
eval_string = r.sub(r'self.player.stats["\1"]', s)
result = eval(eval_string)
它运行Vista / Python 2.5,在Ubuntu / Python 2.7上失败。
答案 0 :(得分:1)
承认你可以在运行bad之前计算变量dict,你可以使用:
class Foo(object):
def bar(self, x):
outer_locals = locals()
def baz(y):
print outer_locals['self']
..
return baz(..)
相反,如果你必须在运行时(bad
内)计算字典,这就是要走的路:
import inspect
def outer_locals(depth=0):
"""
With depth=0 behaves like locals(), depth=1 are the locals of the
containing frame, depth=2 the locals of the frame containing the containing
frame and so on...
"""
return inspect.getouterframes(inspect.currentframe())[depth+1][0].f_locals
class Foo(object):
def bar(self, x):
def baz(y):
print outer_locals(1)
return baz(...)
请注意,如果未在baz
函数中覆盖,则bar
中的所有bad
本地人都可用:
class Foo(object):
def bar(self, x):
def baz(y):
print self
..
return baz(..)
答案 1 :(得分:1)
我使用2.6.6获得了在2.7中报告的相同行为。但是,我也使用2.5.2和2.4.6获取它。 (所有Linux。)
有趣的是:
>>> class Foo(object):
def bar(self, x):
def baz(y):
print self.__class__.__name__
print locals()['self']
return baz(4)
...
>>> Foo().bar(3)
Foo
<__main__.Foo object at 0x9801f4c>
>>>
可能有一些优化或更改计算本地符号表的过程,即只有给定函数范围内实际使用的名称才会添加到其表中,即使给定符号 可以访问(并且不会是全球性的!)是它被明确引用。
将bar()的最后一行更改为return baz
(而不是return baz(4)
),我们可以看到self
不是局部变量;这是一个自由变量:
>>> baz = Foo().bar(4)
>>> baz.func_code.co_nlocals, f.func_code.co_varnames, f.func_code.co_freevars
(1, ('y',), ('self',))
即使在这里,x
也没有包含在自由变量中,因为when the name isn't used in the interior function, it doesn't count as free there。
然而,这种解释使得你在Vista上描述的2.5以下的行为听起来像一个bug。
答案 2 :(得分:0)
KeyError
是正确的;我在OSX SnowLeopard上的Python 2.7.1上也是如此。
这就是原因。我将您的代码修改为以下内容:
class Foo(object):
def bar(self, x):
quux = 4
print locals()
def baz(y):
print locals()#['self']
return baz(3)
foo = Foo()
foo.bar(2)
得到了
{'quux': 4, 'self': <__main__.Foo object at 0x1004945d0>, 'x': 2}
{'y': 3}
问题在于baz
locals
dict应该不包含self
,这是在外部范围内定义的。
我真的很困惑为什么在self
的Windows下的baz
位置发现了{{1}}。它是2.5或Windows实现中的错误,或者语言规范在2.5和2.7之间变化。
答案 3 :(得分:0)
局部变量总是在当前被调用函数中定义的变量,全局变量始终在程序顶部定义的变量。
在bar
中,是一个局部变量。在baz
self 位于本地变量和全局变量之间。你仍然可以引用它,因为Python会在更高的范围内搜索它,因为它没有在本地范围内定义,但是
你不能访问theese范围的字典。