Adding to local namespace in Python?

2019-05-07 02:07发布

问题:

Is there a way in Python to add to the locals name-space by calling a function without explicitly assigning variables locally?

Something like the following for example (which of course doesn't work, because locals() return a copy of the local name-space) where the print statement would print '1'.

def A():
  B(locals())
  print x

def B(d):
  d['x'] = 1

回答1:

In Python 2.*, you can disable the normal optimizations performed by the Python compiler regarding local variable access by starting your function with exec ''; this will make the function very much slower (I just posted, earlier today, an answer showing how the local-variable optimization can easily speed code up by 3 or 4 times), but it will make your desired hack work. I.e., in Python 2.*:

def A():
  exec ''
  B(locals())
  print x

def B(d):
  d['x'] = 1

A()

will emit 1, as you desire.

This hack was disabled in Python 3.* (where exec is just a function, not a statement nor a keyword any more) -- the compiler now performs the local variable optimization unconditionally, so there is no longer any way to work around it and make such hacks work.



回答2:

Seems pretty horrible to rely on a hack like exec ''. What about communicating like this with the global statement, it seems to work:

>>> def outer():
...   global x
...   b()
...   print x
... 
>>> def b():
...   global x
...   x = 2
... 
>>> outer()
2

You could create a namespace for your variables instead:

class Namespace(object):
    pass

def A():
  names = Namespace()
  B(names)
  print names.x

def B(d):
  d.x = 1

Then use names.x or getattr(names, "x") to access the attributes.