Skip to content Skip to sidebar Skip to footer

Calling Locals() In A Function Nested In A Class Method

Here is a snippet: class Foo(object): def bar(self, x): def baz(y): print locals()['self'] .. return baz(..) foo = Foo() foo.bar(..) I hav

Solution 1:

Admitting that you can compute the variables dict before running bad, you can use this:

classFoo(object):
    defbar(self, x):
        outer_locals = locals()
        defbaz(y):
            print outer_locals['self']
        ..
        return baz(..)

If, instead, you have to compute the dictionary at runtime (inside bad), this is the way to go:

import inspect

defouter_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

classFoo(object):
    defbar(self, x):
        defbaz(y):
            print outer_locals(1)
        return baz(...)

Note that if not overwritten in the baz function, all of bar locals are available in bad:

classFoo(object):
    defbar(self, x):
        defbaz(y):
            print self
        ..
        return baz(..)

Solution 2:

I get the same behavior you report in 2.7 using 2.6.6. However, I also get it using 2.5.2 and 2.4.6. (All Linux.)

Interestingly:

>>> classFoo(object):
    defbar(self, x):
        defbaz(y):
            print self.__class__.__name__
            printlocals()['self']
        return baz(4)
...
>>> Foo().bar(3)
Foo
<__main__.Foo object at 0x9801f4c>
>>>

Presumably there was some optimization or alteration of the process of computing the local symbol table whereby only names actually used in a given function's scope are added to its table, even if a given symbol would be accessible (and would not be a global!) were it to be explicitly referred to.

Changing the last line of bar() to return baz (rather than return baz(4)) we can see that self is not a local variable; it's a free variable:

>>> baz = Foo().bar(4)
>>> baz.func_code.co_nlocals, f.func_code.co_varnames, f.func_code.co_freevars
(1, ('y',), ('self',))

Even here, though, x has not been included among the free variables, because when the name isn't used in the interior function, it doesn't count as free there.

That explanation, though, makes the behavior you're describing under 2.5 on Vista sound like a bug.

Solution 3:

Hmmm, I believe the KeyError is correct; I get the same on Python 2.7.1 on OSX SnowLeopard.

Here's why. I modified your code to the following:

classFoo(object):

    defbar(self, x):
        quux = 4printlocals()

        defbaz(y):
            printlocals()#['self']return baz(3)

foo = Foo()
foo.bar(2)

and got

{'quux': 4, 'self': <__main__.Foo object at 0x1004945d0>, 'x': 2}
{'y': 3}

The issue is that in baz the locals dict should not include self which is defined in an outer scope.

I'm really puzzled why this found self in baz's locatls under Windows. Either it is a bug in 2.5 or in the Windows implementation, or the language spec has changed between 2.5 and 2.7.

Solution 4:

The local variables are always the ones defined within the current called function, the global variables are always the ones defined at the top of your program. In barself is a local variable. In bazself is somewhere inbetween the local and global variables. You can still reference it because Python will search for it in higher scopes as it's not defined in the local one, but you cannot access theese scopes' dictionary.

Post a Comment for "Calling Locals() In A Function Nested In A Class Method"