Steven D'Aprano wrote: > I have to dynamically generate some code inside a function using exec, > but I'm not sure if it is working by accident or if I can rely on it. > > Here is a trivial example: > > > py> def spam(): > ... exec( """x = 23""" ) > ... return x > ... > py> spam() > 23 > > > (My real example is more complex than this.) > > According to the documentation of exec, I don't think this should > actually work, and yet it appears to. The documentation says: > > The default locals act as described for function locals() > below: modifications to the default locals dictionary should > not be attempted. Pass an explicit locals dictionary if you > need to see effects of the code on locals after function > exec() returns. > > http://docs.python.org/3.4/library/functions.html#exec > > > I *think* this means that if I want to guarantee that a local variable x > is created by exec, I need to do this instead: > > py> def eggs(): > ... mylocals = {} > ... exec( """x = 23""", globals(), mylocals) > ... x = mylocals['x'] > ... return x > ... > py> eggs() > 23 > > The fact that it works in spam() above is perhaps an accident of > implementation? Yes no maybe?
eggs() should work in Python 2 and 3, spam() should work in Python 2, but not in Python 3. Fun fact: Python 2 tweaks the bytecode (LOAD_NAME instead of LOAD_GLOBAL) to make spam() work: >>> def spam(): ... return x ... >>> dis.dis(spam) 2 0 LOAD_GLOBAL 0 (x) 3 RETURN_VALUE >>> def spam(): ... exec "" ... return x ... >>> dis.dis(spam) 2 0 LOAD_CONST 1 ('') 3 LOAD_CONST 0 (None) 6 DUP_TOP 7 EXEC_STMT 3 8 LOAD_NAME 0 (x) 11 RETURN_VALUE -- https://mail.python.org/mailman/listinfo/python-list