brython-dev / brython

Brython (Browser Python) is an implementation of Python 3 running in the browser
BSD 3-Clause "New" or "Revised" License
6.39k stars 511 forks source link

Issues with nonlocal keyword inside exec call #1472

Closed kmindspark closed 4 years ago

kmindspark commented 4 years ago

Code:

exec("""
myvar = 1
print(myvar)

def main_func():
  nonlocal myvar
  myvar = 3
  print(myvar)
  print("hello")

main_func()
print(myvar)
""")

When I run this inside another brython python function, I get the following error:

Traceback (most recent call last):
  File file:///Users/kaushikshivakumar/Documents/Ziro/ziro.html/__main__ line 241, in echo
    exec("""
  File <string>, line 12
    print(myvar)
SyntaxError: "no binding for nonlocal 'myvar' found"
brython.js:9146 Uncaught Error
    at _b_.SyntaxError.$factory (eval at $make_exc (brython.js:7929), <anonymous>:141:337)
    at Object._b_.SyntaxError.$factory (brython.js:7950)
    at Object.$B.$SyntaxError (brython.js:7710)
    at $B.parser.$_SyntaxError (brython.js:228)
    at $B.parser.$NonlocalCtx.transform (brython.js:3574)
    at $B.parser.$Node.transform (brython.js:332)
    at $B.parser.$Node.transform (brython.js:334)
    at $B.parser.$Node.transform (brython.js:334)
    at $B.parser.$Node.transform (brython.js:328)
    at Object.$B.py2js (brython.js:5087)

When I replace nonlocal with global, I get the following outputs.

1
<Javascript undefined>
hello
3

I was wondering if there is a bug going on here, and if not, if someone could explain to me why this is the intended behavior.

PierreQuentel commented 4 years ago

@kmindspark Thanks for the report. This is the intended behaviour, as you can see by running the same code with CPython.

It is because exec() executes code in an environment with a global namespace and a local namespace; in your code, myvar is bound in the global namespace, and the documentation says that "The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals"

kmindspark commented 4 years ago

Hi - thanks for the response. I had a one remaining question though.

Why does the global variable, inside the function, when printed, show as \<Javascript undefined>?

kmindspark commented 4 years ago

Solved by passing globals() to exec. Thank you.

PierreQuentel commented 4 years ago

Commit 86eb33e fixes the issue with global without having to explicitely pass globals() to exec.