List comprehension scope error from Python debugger

后端 未结 2 1158
鱼传尺愫
鱼传尺愫 2020-12-03 02:41

In debugging my code, I want to use a list comprehension. However, it seems I cannot evaluate a list comprehension from the debugger when I\'m inside a function.

I a

相关标签:
2条回答
  • 2020-12-03 02:56

    In Python 3, you have to use the interact command in pdb before you can access any non-global variables due to a change in the way comprehensions are implemented.

    >>> def foo(): [][0]
    ... 
    >>> foo()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 1, in foo
    IndexError: list index out of range
    >>> import pdb;pdb.pm()
    > <stdin>(1)foo()
    (Pdb) x = 4
    (Pdb) [x for _ in range(2)]
    *** NameError: name 'x' is not defined
    (Pdb) interact
    *interactive*
    >>> [x for _ in range(2)]
    [4, 4]
    >>> 
    
    0 讨论(0)
  • 2020-12-03 02:57

    pdb seems to be running the code with:

    eval(compiled_code, globals(), locals())
    

    (or maybe even just eval(string, globals(), locals())).

    Unfortunately, on compilation Python doesn't know of the local variables. This doesn't matter normally:

    import dis
    
    dis.dis(compile("x", "", "eval"))
    #>>>   1           0 LOAD_NAME                0 (x)
    #>>>               3 RETURN_VALUE
    

    but when another scope is introduced, such as with a list comprehension of lambda, this compiles badly:

    dis.dis(compile("(lambda: x)()", "", "eval"))
    #>>>   1           0 LOAD_CONST               0 (<code object <lambda> at 0x7fac20708d20, file "", line 1>)
    #>>>               3 LOAD_CONST               1 ('<lambda>')
    #>>>               6 MAKE_FUNCTION            0
    #>>>               9 CALL_FUNCTION            0 (0 positional, 0 keyword pair)
    #>>>              12 RETURN_VALUE
    
    # The code of the internal lambda
    dis.dis(compile("(lambda: x)()", "", "eval").co_consts[0])
    #>>>   1           0 LOAD_GLOBAL              0 (x)
    #>>>               3 RETURN_VALUE
    

    Note how that's a LOAD_GLOBAL where x is in the local scope.


    Here's a totally stupid hack to get around it:

    (Pdb) eval("(lambda: x)()", vars())
    [1, 2, 3, 3, 4]
    
    0 讨论(0)
提交回复
热议问题