Welcome, guest | Sign In | My Account | Store | Cart

Accessing the local namespace dict is already done by calling the builtin method locals(). However, the limitation of doing this is that modifying the dict returned by locals() is not considered 'safe'. Safe in the sense that any modifications are not guaranteed to be reflected in the actual namespace.

In order to implement a 'safe' reference and modification of the local dictionary, I use sys._getframe().f_locals. This gives me direct access to the local dict each time I use it. But beyond just having safe access to the local dict, I also would like a local __dict__ dict that acts exactly the way a class __dict__ would. Currently, there is not a local __dict__ available. So here is a way to create your own:

Python, 54 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#####################################
# locals.py
# Author: Derrick Wallace
#####################################
import sys

__all__ = ['local_dict']
bad = ['__init__', '__new__', '__repr__']


class __dict( dict ):
    """
    Wrapper to mimic a local dict.
    """

    def __init__( self, *args ):
        dict.__init__( self, *args )

        for attr in dict.__dict__:
            if callable( dict.__dict__[attr] ) and ( not attr in bad ):
                exec( 'def %s(self, *args): return dict.%s(sys._getframe(1).f_locals, *args)'%( attr, attr ) )
                exec( '__dict.%s = %s'%( attr, attr ) )

    # Must implement a custom repr to prevent recursion
    def __repr__( self, *args ):
        if sys._getframe(1).f_code == sys._getframe().f_code:
            return '{...}'
        return dict.__repr__( sys._getframe(1).f_locals, *args )


local_dict = __dict()


## Example Use ####################################

>>> from forum.locals import local_dict as __dict__
>>> __dict__
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__dict__': {...}}
>>> __dict__['foo'] = 'bar'
>>> foo
'bar'
>>> def Test(a, b=2):
...     print __dict__
...
>>> Test(1)
{'a': 1, 'b': 2}
>>> class Spam:
...     def Test(self, a, b=2):
...         print __dict__
...
>>> s=Spam()
>>> s.Test(100)
{'a': 100, 'self': <__main__.Spam instance at 0x008FD120>, 'b': 2}
>>>

As shown in the examples, the imported __dict__ can be used to reference the local namespace whether inside a function, a class method, or simply in the main script namespace. This is an excellent alternative to using the locals() function, in that it is safe to modify. Every call to the wrapper dict makes a fresh call to the local dict, ensuring as safe a modification as possible of the local dict. Enjoy. Please share comments/critiques.

5 comments

Sean Ross 17 years, 2 months ago  # | flag

flocals are read-only.

>>> from locals import local_dict as __dict__
>>> def f():
...     __dict__['a'] = 'a'
...     print a
...
>>> f()
Traceback (most recent call last):
  File "", line 1, in ?
  File "", line 3, in f
NameError: global name 'a' is not defined
>>> def f():
...     __dict__.a = 'a'
...     print a
...
>>> f()
Traceback (most recent call last):
  File "", line 1, in ?
  File "", line 3, in f
NameError: global name 'a' is not defined


You _can_ do this:
>>> def f():
...     __dict__['a'] = 'a'
...     print __dict__['a']
...
>>> f()
a

But that is not adding 'a' to f's local namespace.
Hamish Lawson 17 years, 2 months ago  # | flag

Suggested rewording in description. Would rewording "any modifications are not guaranteed to be reflected" as "any modifications are guaranteed not to be reflected" better convey what you mean? The first wording implies that modifications might be reflected in the local namespace, whereas the second states that they won't be, which is what I understand you are after.

Derrick Wallace (author) 17 years, 2 months ago  # | flag

Some other means needed. Sean, thank you for pointing this out. It was truly careless of me to not test the cases you posted. I have spent the past few days looking into other ways to access (or mimic access of) a local namespace. To date, I have found none.

I will leave the recipe as it is for now because there is some useful information in how I remapped the dict class. If and when a means of accessing a particular local namespace is found, it would only modify the __setitem__ method.

Derrick Wallace (author) 17 years, 2 months ago  # | flag

locals() mods can succeed. Hamish, the wording I used originally does accurately convey what I was intending. The reason is that in certain circumstances, I am able to modify that dict returned by locals(), and those modifications will be reflected in the local namespace. It turns out that the solution I have presented here succeeds and fails exactly where the locals() function does. Thank you for sharing your concern.

Oleg Sidorkin 13 years, 5 months ago  # | flag

Works under 2.4 and 2.5:

import sys
def f(**kw):
    for k,v in kw.iteritems():
        locals()[k]=v
    exec('pass') # apply locals ;)
    print x

f(x=1)
Created by Derrick Wallace on Wed, 8 Sep 2004 (PSF)
Python recipes (4591)
Derrick Wallace's recipes (3)

Required Modules

  • (none specified)

Other Information and Tasks