2

Suppose I have defined a function like this:

def calc():
    print x

And I want to inject var x into the function's local by some ways before I calling it.

This looks like I added a keyword x and I can use x in function calc() without defining it. And what x will be is defined by the outer function who calls the calc().

Maybe this is a silly question, but I just want to know is it possible to do that?

If we can't modify it's locals before calling it, can we try another way? That is suppose we use decorator or something else to modify the func()'s definition automatically to

def clac(x):
    print x

Maybe in this way, we need to play with the function's bytecode?

Can someone give some advise?

Myrfy
  • 575
  • 4
  • 11
  • Possible duplicate of [How to inject variable into scope with a decorator in python](http://stackoverflow.com/questions/17862185/how-to-inject-variable-into-scope-with-a-decorator-in-python) – Zero Piraeus Nov 23 '16 at 05:01
  • @Zero Piraeus I see, it seems like the same question but I found the answer below in my post is much better than the one you mentioned. – Myrfy Nov 24 '16 at 02:39

1 Answers1

4

This seems like a very perverse thing to do, but it is actually possible. A reference to an undefined name compiles as a global variable reference, so we just need to call the function with a different global environment. Unfortunately, the func_globals attribute of functions is read-only, so we have to play some tricks with the function's code object. Try this:

exec calc.func_code in {'x': 'blah'}

Note that the dictionary you pass will be modified by adding a '__builtins__' slot - this allows the function to access Python's built-in functions and constants.

jasonharper
  • 9,450
  • 2
  • 18
  • 42
  • That's cool. I like this answer. And I will try another way that will insert some bytecode before the calc.func_code and the build a new function with param x. I think that will also works. – Myrfy Nov 24 '16 at 02:44
  • The code as shown is for Python 2. For Python 3, the equivalent would be: `exec(calc.__code__, {'x': 'blah'})` – Jonathon Reinhart Aug 30 '22 at 21:37