在嵌套在类方法中的函数中调用locals()

时间:2011-07-30 05:29:01

标签: python

这是一个片段:

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上失败。

4 个答案:

答案 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范围的字典。