How can I modify the local namespace of a function in python? I know that locals() returns the local namespace of the function when called inside it, but I want to do something like this (I have a reason why I want to do this where g is not accessible to f, but it's quicker to give a trivial, stupid example to illustrate the problem):
def g():
pass
def f():
g()
f.add_to_locals({'g':g})
What is a local namespace in Python? A local namespace is defined for a class, a function, a loop, or any block of code. The names defined in a block of code or a function are local to it. The variable names cannot be accessed outside the block of code or the function in which they are defined.
Every package, module, class, function and method occupies a Python namespace in which variable names are set. A namespace gets created automatically when a module or package starts execution. Hence, create namespace in python, all you have to do is call a function/ object or import a module/package.
We can define namespace as a collection of names associated with the address in the main memory. There are three types of namespaces in python - Built-in Namespace, Global Namespace, and Local Namespace. The scope of variables in python is associated with the namespace in python.
Use vars() to convert your namespace to a dictionary, then use dict. get('your key') which will return your object if it exists, or a None when it doesn't.
You've a couple of options. First, note that g in your example isn't actually a local to the function (ie. not assigned within it), it's a global (ie hasn't been assigned to a local variable). This means that it will be looked up in the module the function is defined in. This is fortunate, as there's no way of altering locals externally (short of patching the bytecode), as they get assigned when the function runs, not before.
One option is simply to inject your function into the function's module's namespace. This will work, but will affect every function in that module that accesses the variable, rather than just the one function.
To affect just the one function, you need to instead point that func_globals somewhere else. Unfortunately, this is a read-only property, but you can do what you want by recreating the function with the same body, but a different global namespace:
import new
f = new.function(f.func_code, {'g': my_g_function}, f.func_name, f.func_defaults, f.func_closure)
f will now be indentical, except that it will look for globals in the provided dict. Note that this rebinds the whole global namespace - if there are variables there that f does look up, make sure you provide them too. This is also fairly hacky though, and may not work on versions of python other than cpython.
Since the function isn't invoked, it has no "local" stack frame, yet. The most simple solution is to use a global context:
handler = None
def f():
handler()
def g(): pass
handler = g
Or you could set g on the function object:
f.g = g
But I'm not sure how you can get the function object from within the function itself. If it was a method, you would use self
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With