Изменение интерпретируемого поведения при введении ключевого слова del - PullRequest
1 голос
/ 27 мая 2020

Я написал следующую игрушку:

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()

, которая дает следующий результат:

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
>>> 

Обратите внимание, как поведение второго издания изменяется даже в областях кода вверх которому две редакции идентичны (и, следовательно, должны давать одинаковые результаты). Поскольку x, согласно первой редакции, действительно существует в локальном пространстве имен, оператор del не должен быть проблемой.

Вопросы:

1) Правильно ли первое или второе издание? Должен ли x существовать в пространстве имен или нет?

2) Есть ли объяснение такому поведению или это ошибка?

(продолжение до 2: 3) Должно ли второе издание работать без ошибок или оно должно взломать sh?)

Ответы [ 2 ]

1 голос
/ 27 мая 2020

Следующий пост решил эту проблему для меня:

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

Я хотел бы выделить:

«Первое заблуждение состоит в том, что Python, являющийся интерпретируемым языком (что замечательно, я думаю, мы все можем согласиться), выполняется построчно. По правде говоря, Python выполняется построчно. Чтобы понять, что я означает, go в вашу любимую оболочку (я надеюсь, вы не используете оболочку по умолчанию) и введите следующее:

def foo():

Нажмите Enter. Как видите, оболочка не предлагала любой результат, и он явно ждет, пока вы продолжите определение функции. "

Это было источником моего замешательства.

Спасибо @ norok2 за то, что он указал мне на сообщение, которое указывало мне на это.

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

также было полезно)

1 голос
/ 27 мая 2020

del x запускает интерпретатор для затенения нелокальной x переменной, определенной вне кадра foo2().

Тот же эффект был бы получен, если бы вы заменили del x на x = ... в той же позиции.

Причина этого в том, что x фактически находится на том же уровне, что и foo2(), и когда del x достигается во время foo2(), интерпретатор решает не что имя x должно быть зарезервировано для локальной переменной x, и, следовательно, оно не обновляет ваш locals() именем из внешнего имени. Перемещение присваивания x внутрь foo2() позволит x действительно быть local и, следовательно, появиться в 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:  []

, а также объявить x для ссылки на переменная nonlocal явно внутри 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:  []
...