Can I define a function which, when called, inserts new locals into the caller's scope? I have a feeling that passing the caller's locals() into the function might work, but is there a way to do what I want without having to do this?
Check out the inspect module, it is used by minimock to mock the caller's scope.
This code ought to do what you want exactly:
import inspect
def mess_with_caller():
stack = inspect.stack()
try:
locals_ = stack[1][0].f_locals
finally:
del stack
locals_['my_new_function'] = lambda : 'yaaaaaay'
mess_with_caller()
print my_new_function()
>>> Output: 'yaaaaaay'
By Python's rules, you cannot alter your caller's locals
; in the current implementations, if you try (e.g. with the black magic Anurag suggests) you will not get an exception (though I'd like to add that error check to some future version), but it will be essentially inoperative if your caller is a function (not if your caller is module top-level code) -- the caller's actual local variables won't in fact be affected. This holds whether the caller's locals
are explicitly passed in, or fetched through black magic: they still need to be treated as a read-only dict if your code is to have any sanity.
Rather, you could have the caller pass in an explicit, real, normal dict (which could be initialized from locals()
if you want), and all alterations your code does in that dict will still be there for the caller's use -- just not as "new barenames" in the caller's local scope of course, but the functionality is the same whether the caller needs to use x['foo']
or x.foo
or (as you'd prefer) just barename foo
.
BTW, to use attribute-access syntax rather than dict indexing syntax, you can do:
class Bunch(object): pass
...
# caller code
b = Bunch()
thefun(b)
print b.foo
...
# called function
def thefun(b):
b.foo = 23
This also covers, with a tiny variation, the case in which thefun
wants to work with dict indexing syntax (say its body is b['foo'] = 23
instead of b.foo = 23
): in that case, the caller just needs to use thefun(vars(b))
instead of the plain thefun(b)
, but it can keep working with the b.foo
access syntax afterwards.
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