4

say, I have very simple piece of code

py = """ a = 1 print (f'before all {a=}') def bar(n): print(f'bye {n=}') def foo(n): print(f'hello {n=}') bar(n) bar ('just works') foo ('sara') """ loc = {} glo = {} bytecode = compile(py, "script", "exec") exec(bytecode, glo, loc) 

as you can see I defined two functions: bar & foo and called both of them with results:

before all a=1 bye n='just works' hello n='sara' Traceback (most recent call last): File "/home/bla-bla/pythonProject/main_deco2.py", line 43, in <module> exec(bytecode, glo, loc) File "script", line 13, in <module> File "script", line 10, in foo NameError: name 'bar' is not defined 

and this leaves me puzzled, as I don't understand why function foo doesn't see bar when just a second ago I was able to call bar without a problem ?

1
  • 1
    As a lead: if you skip the foo parts in the code, and examine the dicts afterwards, you will find that a and bar end up in the locals dict, not the globals dict. Commented Oct 3, 2022 at 21:07

2 Answers 2

1

From the docs:

If exec gets two separate objects as globals and locals, the code will be executed as if it were embedded in a class definition.

That's not what you want, so don't provide a locals.

glo = {} exec(bytecode, glo) 

Output, for reference:

before all a=1 bye n='just works' hello n='sara' bye n='sara' 
Sign up to request clarification or add additional context in comments.

1 Comment

P.S. I haven't quite wrapped my head around why it's treated as if it were in a class definition, so if anyone could explain it, I'm all ears. I do understand that class scope is kinda weird though, so it's probably related to that.
1

An important diagnostic:

>>> dis.dis(bytecode) 2 0 LOAD_CONST 0 (1) 2 STORE_NAME 0 (a) 3 4 LOAD_NAME 1 (print) 6 LOAD_CONST 1 ('before all a=') 8 LOAD_NAME 0 (a) 10 FORMAT_VALUE 2 (repr) 12 BUILD_STRING 2 14 CALL_FUNCTION 1 16 POP_TOP 

I omitted most of the result, but the first few lines show what is going on. Accesses to a and bar use the LOAD_NAME and STORE_NAME opcodes, which use the locals first. (It cannot use LOAD_FAST because it is not a compiled function.) To work around this, simply mark the necessary names as global explicitly.

Unfortunately, I don't have a good answer for why it does this.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.