【问题标题】:all variables are undefined in python debuggerpython调试器中的所有变量都未定义
【发布时间】:2023-04-03 06:54:01
【问题描述】:

我在 Python 3.6 上遇到了一个非常奇怪的问题。在我的代码中间,我调用import pdb; pdb.set_trace() 来调试一些代码。

然后我无法正确调试,例如:

(Pdb) abc = 3
(Pdb) [abc for _ in range(2)]
*** NameError: name 'abc' is not defined
(Pdb) [abc, abc]
[3, 3]

似乎每当我使用列表推导时,都会出现未定义变量的问题。但是,如果我在打开 Python 后立即调用调试器,我不会观察到这种行为,一切运行正常。

任何想法为什么我会遇到这个问题?

【问题讨论】:

  • 有解决方法来执行命令 likc this。 eval("(lambda: x)()", vars())

标签: python python-3.x debugging pdb


【解决方案1】:

发生这种情况是因为列表推导(大部分)在嵌套范围内进行评估,而在 pdb 中创建的嵌套范围无法访问被检查范围的局部变量。但是,它们可以访问全局变量,并且当您在打开 Python 后立即启动 pdb 时,您将在全局范围内运行它,因此您创建的 abc 是全局变量。

exec 和类语句中的列表推导也会发生这种情况。不幸的是,没有比“不要在那里使用列表推导式”更好的解决方法了。

【讨论】:

  • 这是特定于 Python 3 的吗?我没有观察到 Python 2 的问题。
  • @dhokas:在 Python 2 中,列表推导式不会在嵌套范围内进行评估。不过,我相信您仍然会在 Python 2 中使用 genexps 和 dict/set 推导式看到它。
【解决方案2】:

这被归档为b.p.o. issue #21161,但关闭为“不会修复”。

根本问题正是user2357112's answer 所说的:理解1通过定义然后运行隐藏的嵌套函数来工作,但是在框架内的 pdb 中定义的函数不是真正的嵌套函数,并且可以'不访问框架范围内的变量。

有一些变通办法(其中一些在 b.p.o 问题中提到,或与该问题相关的地方),但它们都只是其中之一的巧妙变体:

  • (lambda abc: [abc for _ in range(2)])(abc)(换句话说,定义一个函数并显式传递本地值作为参数而不是捕获它们。)
  • [abc_ for abc_ in [abc] for _ in range(2)](换句话说,使用最外层的可迭代对象是参数这一事实。2
  • [loc['abc'] for loc in [locals()] for _ in range(2)](换句话说,使用locals()['name']而不是name,并像上面一样获取本地人。)
  • exec 中使用exec 以及任何已知的同样可怕的解决方法来理解。
  • 不要像 user2357112 建议的那样使用推导式。

1。在 Python 2.x 中,这不适用于列表推导,只有 set 和 dict 推导以及生成器表达式。但是 Python 3 更改了列表推导以使它们与其他推导保持一致。

2。推导式的隐藏嵌套函数几乎捕获了封闭范围内的所有名称——但最外层的可迭代(第一个 for 中的那个)是特殊的;它实际上是隐藏函数的参数,表达式在封闭范围内计算并作为参数值传递。

【讨论】:

  • [locals()['abc'] for _ in range(2)] 不起作用 - 涉及locals() 的解决方法需要在外部范围内调用locals,而不是在理解范围内。
  • @user2357112 哎呀,你是对的;你需要传入一个当地人的字典;我会编辑。
  • 当您尝试调试问题时会很困惑,而且调试器的工作方式与您的代码不同。现在您必须调试调试器。我希望这能得到解决。
【解决方案3】:

你可以试试下面的代码:

(Pdb) !import code; code.interact(local=vars())
Python 3.6.6 |Anaconda, Inc.| (default, Jun 28 2018, 17:14:51) 
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> [abc for _ in range(2)]

使用 Ctrl-D 返回到常规 pdb 提示符。

【讨论】:

    【解决方案4】:

    类似于李攀峰的回答,但更简单的方法是在 pdb 中使用interact

    以下是 pdb 失败和 interact 在同一上下文中工作的示例。

    Python 3.6.3 (default, Oct  4 2017, 06:09:05)
    [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> def do_comp():
    ...   abc = 3
    ...   import pdb; pdb.set_trace()
    ...
    >>> do_comp()
    --Return--
    > <stdin>(3)do_comp()->None
    (Pdb) [abc for _ in range(2)]
    *** NameError: name 'abc' is not defined
    (Pdb) interact
    *interactive*
    >>> [abc for _ in range(2)]
    [3, 3]
    

    【讨论】:

    • 非常感谢这个简化版?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 2019-06-13
    • 2021-12-11
    • 1970-01-01
    • 2011-04-29
    相关资源
    最近更新 更多