程序在修改本地变量字典后表现出奇怪的行为

huangapple go评论92阅读模式
英文:

Strange behaviour of the program after modifying the dictionary of local variables

问题

  1. 为什么 'num_0' 可以成功打印,而 'num_1' 不能? (已解决)

  2. 为什么 'num_1' 可以在 pdb 中打印,但 'print(num_1)' 无法执行? (已解决)

结果:

python test.py
-----
0
-> print(num_1)
(pdb) p num_1
1
(pdb) c
Traceback (most recent call last):
  File "test.py", line 13, in <module>
    lc()
  File "test.py", line 9, in lc
    print(num_1)
NameError: name 'num_1' is not defined

实际上,我有一些想法,但不太确定。我查看了全局变量的字典,并发现 'num_0' 在其中。因此,我猜第一个问题是因为解释器不知道 'num_1' 在局部变量字典中,而 'num_0' 不仅在局部字典中,还在全局字典中。至于第二个问题,我猜测 pdb 知道修改后的局部字典,所以它可以成功打印 'num_1'。

希望有人可以帮助解释这两个问题或提供一些参考资料。

英文:

I find some strange behavior in my program after modifying the dictionary of local variables, and it makes me confused. If we execute the code below, we will get the result as the image I attached. And now I know I shouldn't modify the local variables using locals().

i=0
locals()[f'num_{i}'] = i
print(num_0)

def lc():
    i=1
    locals()[f'num_{i}'] = i
    import pdb; pdb.set_trace()
    print(num_1)


if __name__ == '__main__':
    lc()

My questions are:

  1. Why 'num_0' can be printed successfully while 'num_1' cant? (solved)

  2. Why 'num_1' can be printed in pdb but 'print(num_1)' cant be executed? (solved)

Result:

python test.py
-----
0
-> print(num_1)
(pdb) p num_1
1
(pdb) c
Traceback (most recent call last):
  File "test.py", line 13, in <module>
    lc()
  File "test.py", line 9, in lc
    print(num_1)
NameError: name 'num_1' is not defined

Actually, I have a few ideas but I am not sure. I checked the dictionary of global variables, and 'num_0' is in it. So I suppose the first question is because the interpreter doesn't know that 'num_1' is in the dictionary of local variables, while 'num_0' is not only in the local dictionary but also in the global dictionary. As to the second question, I suppose pdb will know the modified local dictionary, so it can print 'num_1' successfully.

I hope someone can help to explain the two questions or give me some reference materials.

答案1

得分: 1

You are using locals() in a function scope

> If you read the actual documentation, you'll see the following:
>
> > Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by
> the interpreter.

你在函数范围内使用了 locals()

> 如果你阅读实际的文档,你会看到以下内容:
>
> > 注意:不应修改此字典的内容;更改可能不会影响解释器使用的本地和自由变量的值。


> The documentation makes no promises about what modifying the
> dictionary will do.
>
> At function scope, the dictionary locals() returns is not the primary
> representation of the local scope. It's a separate dictionary attached
> to the stack frame. Calling locals() updates that dictionary with the
> current values of local variables and returns the dictionary.
>
> At function scope, changing the dictionary will usually not update
> local variables, but in some special circumstances (mostly related to
> debugging), Python will copy values from the dictionary back to local
> variables.
>
> At function scope, changing local variables will usually not update
> the dictionary, unless you call locals() again or something accesses
> the frame object's f_locals attribute. Debuggers access f_locals to
> read local variable values, so code that uses locals() will often
> break in a debugger.

https://stackoverflow.com/a/71467339/6251742

为什么 pdb 可以成功打印 'num_1'?

因为调试器读取本地变量,在您询问 pdb 值时更新字典。您可以使用 breakpoint() 实现相同的行为

>>> def f():
...     x = 1
...     y = locals()
...     x = 2
...     breakpoint()  # 更新本地变量的内部字典
...     x = 3  # 本地变量的内部字典不会更改
...     print(y['x'])  # 因此它打印了在上次更新本地变量时存在的值
>>> f()
> <input>(6)f()
(Pdb) >? continue
2
英文:

You are using locals() in a function scope

> If you read the actual documentation, you'll see the following:
>
> > Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by
> the interpreter.


> The documentation makes no promises about what modifying the
> dictionary will do.
>
> At function scope, the dictionary locals() returns is not the primary
> representation of the local scope. It's a separate dictionary attached
> to the stack frame. Calling locals() updates that dictionary with the
> current values of local variables and returns the dictionary.
>
> At function scope, changing the dictionary will usually not update
> local variables, but in some special circumstances (mostly related to
> debugging), Python will copy values from the dictionary back to local
> variables.
>
> At function scope, changing local variables will usually not update
> the dictionary, unless you call locals() again or something accesses
> the frame object's f_locals attribute. Debuggers access f_locals to
> read local variable values, so code that uses locals() will often
> break in a debugger.

https://stackoverflow.com/a/71467339/6251742

why pdb can print 'num_1' successfully?

Because the debugger reads the locals, updating the dictionnary when you ask pdb the value. You can achieve the same behavior with breakpoint()

>>> def f():
...     x = 1
...     y = locals()
...     x = 2
...     breakpoint()  # update locals internal dict
...     x = 3  # locals internal dict doesn't change
...     print(y['x'])  # so it print values that were in locals at the last update
>>> f()
> <input>(6)f()
(Pdb) >? continue
2

huangapple
  • 本文由 发表于 2023年3月9日 20:01:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/75684328.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定