Change in interpreted behaviour upon introduction of del keyword

亡梦爱人 提交于 2021-01-28 13:41:58

问题


I wrote the following toy:

def foo():
    x = 5
    def foo2():
        print("Locals: ", locals())
        print("Vars: ", vars())
        print("dir: ", dir())
        print("CP 1")
        print("x =", x)
        print("CP 2")
        print("Locals: ", locals())
        print("Vars: ", vars())
        print("dir: ", dir())
    foo2()

foo()

print("-----------------------")

def foo():
    x = 5
    def foo2():
        print("Locals: ", locals())
        print("Vars: ", vars())
        print("dir: ", dir())
        print("CP 1")
        print("x =", x)
        print("CP 2")
        del x
        print("Locals: ", locals())
        print("Vars: ", vars())
        print("dir: ", dir())
    foo2()

foo()

which produces the following output:

Locals:  {'x': 5}
Vars:  {'x': 5}
dir:  ['x']
CP 1
x = 5
CP 2
Locals:  {'x': 5}
Vars:  {'x': 5}
dir:  ['x']
-----------------------
Locals:  {}
Vars:  {}
dir:  []
CP 1
Traceback (most recent call last):
  File "testing.py", line 34, in <module>
    foo()
  File "testing.py", line 32, in foo
    foo2()
  File "testing.py", line 26, in foo2
    print("x =", x)
UnboundLocalError: local variable 'x' referenced before assignment
>>> 

Notice how behaviour of the second edition is modified even in the areas of the code up to which the two editions are identical (and thus should produce identical outcomes). Since x, according to the first edition, does exist in the local namespace, the del statement shouldn't be an issue.

Questions:

1) Is the first or second edition 'right'? Should x exist in the namespace or not?

2) Is there an explanation for this behaviour or is it a bug?

(Follow up to 2: 3) Should the second edition run without an error or is it supposed to crash?)


回答1:


The del x triggers the interpreter into shadowing the non-local x variable defined outside foo2()'s frame.

The same effect would be obtained if you were to replace del x with x = ... at the very same position.

The reason for this is that x is actually on the same level as foo2() and when del x is reached during foo2(), the interpreter decides not that the name x should be reserved for a local variable x, and hence it does not update your locals() with the name from it's outer name. Moving the x assignment inside foo2() would let x be truly local and hence appear in locals():

def foo():
    def foo2():
        x = 5
        print("Locals: ", locals())
        print("Vars: ", vars())
        print("dir: ", dir())
        print("CP 1")
        print("x =", x)
        print("CP 2")
        del x
        print("Locals: ", locals())
        print("Vars: ", vars())
        print("dir: ", dir())
    foo2()

foo()
Locals:  {'x': 5}
Vars:  {'x': 5}
dir:  ['x']
CP 1
x = 5
CP 2
Locals:  {}
Vars:  {}
dir:  []

as well as declaring x to refer to the nonlocal variable explicitly inside foo2():

def foo():
    x = 5
    def foo2():
        nonlocal x
        print("Locals: ", locals())
        print("Vars: ", vars())
        print("dir: ", dir())
        print("CP 1")
        print("x =", x)
        print("CP 2")
        del x
        print("Locals: ", locals())
        print("Vars: ", vars())
        print("dir: ", dir())
    foo2()

foo()
Locals:  {'x': 5}
Vars:  {'x': 5}
dir:  ['x']
CP 1
x = 5
CP 2
Locals:  {}
Vars:  {}
dir:  []



回答2:


The following post solved it for me:

https://amir.rachum.com/blog/2013/07/09/python-common-newbie-mistakes-part-2/

I would like highlight:

"The first misconception is that Python, being an interpreted language (which is awesome, I think we can all agree), is executed line-by-line. In truth, Python is being executed statement-by-statement. To get a feel of what I mean, go to your favorite shell (you aren’t using the default one, I hope) and type the following:

def foo():

Press Enter. As you can see, the shell didn’t offer any output and it’s clearly waiting for you to continue with your function definition."

This was the source of my confusion.

Thanks to @norok2 for pointing me to a post which pointed me to this.

(https://docs.python.org/3.1/faq/programming.html?highlight=nonlocal#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value

was also helpful)



来源:https://stackoverflow.com/questions/62033352/change-in-interpreted-behaviour-upon-introduction-of-del-keyword

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!