Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/322.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用列表生成器时,Python3中的pdb模块中可能存在错误_Python_Python 3.x_Generator_Pdb_Ipdb - Fatal编程技术网

使用列表生成器时,Python3中的pdb模块中可能存在错误

使用列表生成器时,Python3中的pdb模块中可能存在错误,python,python-3.x,generator,pdb,ipdb,Python,Python 3.x,Generator,Pdb,Ipdb,在Python 3中运行此代码后: import pdb def foo(): nums = [1, 2, 3] a = 5 pdb.set_trace() foo() 以下表达式有效: (Pdb) print(nums) [1, 2, 3] (Pdb) print(a) 5 (Pdb) [x for x in nums] [1, 2, 3] 但以下表达式失败: (Pdb) [x*a for x in nums] *** NameError: global n

在Python 3中运行此代码后:

import pdb

def foo():
    nums = [1, 2, 3]
    a = 5
    pdb.set_trace()

foo()
以下表达式有效:

(Pdb) print(nums)
[1, 2, 3]

(Pdb) print(a)
5

(Pdb) [x for x in nums]
[1, 2, 3]
但以下表达式失败:

(Pdb) [x*a for x in nums]
*** NameError: global name 'a' is not defined
上述内容在Python2.7中运行良好

这是一个错误还是我遗漏了什么


更新:查看新的已接受答案。这确实是一个bug(或一个有问题的设计),现在已经通过在pdb中引入一个新的命令和模式来解决了。

我不明白,如果您希望为seq中的每个元素生成一个Trues列表,那么为什么不[True for x in seq]-我想在尝试这类操作之前,您需要先分配一个本地副本。

它工作得非常好:

>>> import pdb
>>> def f(seq):
...     pdb.set_trace()
... 
>>> f([1,2,3])
--Return--
> <stdin>(2)f()->None
(Pdb) [x for x in seq]
[1, 2, 3]
(Pdb) [x in seq for x in seq]
[True, True, True]
注意字节码如何包含一个FOR ITER的
循环。另一方面,在python3中,列表理解实际上是具有自己堆栈框架的函数:

>>> def test(): [x in seq2 for x in seq]
... 
>>> dis.dis(test)
  1           0 LOAD_CONST               1 (<code object <listcomp> at 0xb6fef160, file "<stdin>", line 1>) 
              3 MAKE_FUNCTION            0 
              6 LOAD_GLOBAL              0 (seq) 
              9 GET_ITER             
             10 CALL_FUNCTION            1 
             13 POP_TOP              
             14 LOAD_CONST               0 (None) 
             17 RETURN_VALUE      
这里
.0
是函数的唯一参数
x
是循环的局部变量,
seq2
全局变量。请注意,列表理解参数
.0
,是从
seq
获取的iterable,而不是
seq
本身。(参见上文
dis
输出中的
GET_ITER
操作码)。通过一个更复杂的示例,这一点更为清楚:

>>> def test():
...     [x in seq for x in zip(seq, a)]
... 
>>> dis.dis(test)
  2           0 LOAD_CONST               1 (<code object <listcomp> at 0xb7196f70, file "<stdin>", line 2>) 
              3 MAKE_FUNCTION            0 
              6 LOAD_GLOBAL              0 (zip) 
              9 LOAD_GLOBAL              1 (seq) 
             12 LOAD_GLOBAL              2 (a) 
             15 CALL_FUNCTION            2 
             18 GET_ITER             
             19 CALL_FUNCTION            1 
             22 POP_TOP              
             23 LOAD_CONST               0 (None) 
             26 RETURN_VALUE 
>>> test.__code__.co_consts[1].co_varnames
('.0', 'x')
它失败是因为定义
test2
时,
seq
变量被视为全局变量,但实际上它是
test
函数中的局部变量,因此无法访问

您看到的行为类似于以下场景:

#python 2 no error
>>> class A(object):
...     x = 1
...     L = [x for _ in range(3)]
... 
>>> 

#python3 error!
>>> class A(object):
...     x = 1
...     L = [x for _ in range(3)]
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in A
  File "<stdin>", line 3, in <listcomp>
NameError: global name 'x' is not defined
因为列表理解在字节码中被“扩展”。在python3中,它失败是因为您实际上正在定义一个函数,并且无法从嵌套函数范围访问类范围:

>>> class A(object):
...     x = 1
...     def test():
...             print(x)
...     test()
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in A
  File "<stdin>", line 4, in test
NameError: global name 'x' is not defined
如您所见,
listcomp
的字节码在
seq2
上有一个显式的
for ITER
。 此显式
FOR ITER
在listcomp函数中,因此作用域限制仍然适用(例如
seq2
作为全局加载)

事实上,我们可以使用pdb来确认这一点:

>>> import pdb
>>> def test(seq1, seq2): pdb.set_trace()
... 
>>> test([1,2,3], [4,5,6])
--Return--
> <stdin>(1)test()->None
(Pdb) [x + y for x in seq1 for y in seq2]
*** NameError: global name 'seq2' is not defined
(Pdb) [x + y for x in non_existent for y in seq2]
*** NameError: name 'non_existent' is not defined
导入pdb >>>def测试(seq1,seq2):pdb.set_trace() ... >>>测试([1,2,3],[4,5,6]) --返回-- >(1)测试()->无 (Pdb)[x+y代表序列1中的x代表序列2中的y] ***NameError:未定义全局名称“seq2” (Pdb)[x+y表示序列2中的x不存在表示序列2中的y] ***NameError:未定义名称“不存在”

注意
namererror
是关于
seq2
而不是
seq1
(作为函数参数传递),并注意将第一个可引用名称更改为不存在的名称如何更改
namererror
(这意味着在第一种情况下
seq1
成功传递).

如果您在[i]pdb会话中键入
interact
,您将获得一个交互式会话,并且列表理解在此模式下按预期工作


来源:

奇怪,这对我来说确实适用于
ipdb==0.7
ipython==0.13.2
它在IPython3 0.12.1和Python 3.2.3中失败了。弹出这个提示:奇怪地尝试一下,它在Python 2.7.3中也确实有效(默认,2012年8月1日,05:14:39)[GCC 4.6.3],但在Python 3.2.3中失败(默认,2012年10月19日,20:10:41)[GCC 4.6.3]。希望这足够详细。我将把这些细节添加到问题中。@Loax更新了我的答案。这种不同的行为是由于在python3中如何实现列表理解的范围问题造成的。@Baruriu感谢您的回答。这无疑为这个问题提供了很多线索。我编辑了这个问题,并添加了我认为更好的例子。阅读您的答案后,有两个后续问题:1)在更新问题中给出的示例中,“nums”和“a”都是局部变量。在pdb的列表理解中,似乎只有出现在“for”之前的局部变量是有问题的。这是否意味着'nums'作为参数传递给列表理解函数,但'a'被认为是全局的?2)Python支持闭包,pdb是否可能传递对当前stackframe的引用(假设它实际上不在堆栈中)这样定义的函数就可以从该框架中查找非局部变量了?遗憾的是,这个“功能”使得pdb在Python 3中几乎不可用。我试图理解为什么一个看起来非常好的表达式在pdb中失败。给定的代码示例除了帮助理解正在发生的事情之外没有任何其他用途。如何退出交互模式?
#python 2 no error
>>> class A(object):
...     x = 1
...     L = [x for _ in range(3)]
... 
>>> 

#python3 error!
>>> class A(object):
...     x = 1
...     L = [x for _ in range(3)]
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in A
  File "<stdin>", line 3, in <listcomp>
NameError: global name 'x' is not defined
>>> class A(object):
...     x = 1
...     L = []
...     for _ in range(3): L.append(x)
... 
>>> class A(object):
...     x = 1
...     def test():
...             print(x)
...     test()
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in A
  File "<stdin>", line 4, in test
NameError: global name 'x' is not defined
>>> import pdb
>>> def test(seq): pdb.set_trace()
... 
>>> test([1,2,3])
--Return--
> <stdin>(1)test()->None
(Pdb) list(x in seq for x in seq)
*** Error in argument: '(x in seq for x in seq)'
>>> import dis
>>> def test(): [x + y for x in seq1 for y in seq2]
... 
>>> dis.dis(test)
  1           0 LOAD_CONST               1 (<code object <listcomp> at 0xb71bf5c0, file "<stdin>", line 1>) 
              3 MAKE_FUNCTION            0 
              6 LOAD_GLOBAL              0 (seq1) 
              9 GET_ITER             
             10 CALL_FUNCTION            1 
             13 POP_TOP              
             14 LOAD_CONST               0 (None) 
             17 RETURN_VALUE         
>>> # The only argument to the listcomp is seq1
>>> import types
>>> func = types.FunctionType(test.__code__.co_consts[1], globals())
>>> dis.dis(func)
  1           0 BUILD_LIST               0 
              3 LOAD_FAST                0 (.0) 
        >>    6 FOR_ITER                29 (to 38) 
              9 STORE_FAST               1 (x) 
             12 LOAD_GLOBAL              0 (seq2) 
             15 GET_ITER             
        >>   16 FOR_ITER                16 (to 35) 
             19 STORE_FAST               2 (y) 
             22 LOAD_FAST                1 (x) 
             25 LOAD_FAST                2 (y) 
             28 BINARY_ADD           
             29 LIST_APPEND              3 
             32 JUMP_ABSOLUTE           16 
        >>   35 JUMP_ABSOLUTE            6 
        >>   38 RETURN_VALUE        
>>> import pdb
>>> def test(seq1, seq2): pdb.set_trace()
... 
>>> test([1,2,3], [4,5,6])
--Return--
> <stdin>(1)test()->None
(Pdb) [x + y for x in seq1 for y in seq2]
*** NameError: global name 'seq2' is not defined
(Pdb) [x + y for x in non_existent for y in seq2]
*** NameError: name 'non_existent' is not defined