如何从pdb控制台进入任意生成器函数调用?

时间:2014-12-12 12:33:21

标签: python pdb

我有一个行为不正常的生成器函数,我想从pdb控制台调用它,然后逐步完成它的每次迭代,看看它的哪个部分是错误的。我希望我能

(Pdb) !pdb.runcall(broken_function, with_arg)

但是因为函数是一个生成器所以我回来了

<generator object broken_function at 0x2badc30>

有没有人知道我现在能做些什么?

编辑:我之前应该已经说清楚了:我当然想在相关循环中设置一个断点,但是我正在运行一个(对我来说)只读文件系统的代码,使那不切实际。

4 个答案:

答案 0 :(得分:3)

编辑:简短版本:

选项:

  1. 使用pdb.run('my_module.my_method()')定位您的功能并逐步完成生成器。

  2. 将pdb作为脚本python -m pdb my_script.py调用。

  3. 使用测试文件yippy_dog.py:

    def yippy_dog():
        for i in range(10):
            print("YIP YIP!")
    
    yippy_dog()
    

    要从pdb控制台定位生成器,导入所需的模块,然后在调用相关方法时调用.run():

    >>> import pdb
    >>> import yippy_dog
    YIP YIP!
    ~~~
    YIP YIP!
    YIP YIP!
    >>> pdb.run('yippy_dog.yippy_dog()')
    > <string>(1)<module>()
    (Pdb) s
    --Call--
    > /private/tmp/yippy_dog.py(1)yippy_dog()
    -> def yippy_dog():
    (Pdb) s
    > /private/tmp/yippy_dog.py(2)yippy_dog()
    -> for i in range(10):
    (Pdb) s
    > /private/tmp/yippy_dog.py(3)yippy_dog()
    -> print("YIP YIP!")
    (Pdb) s
    YIP YIP!
    > /private/tmp/yippy_dog.py(2)yippy_dog()
    -> for i in range(10):
    (Pdb) s
    > /private/tmp/yippy_dog.py(3)yippy_dog()
    -> print("YIP YIP!")
    (Pdb) s
    YIP YIP!
    > /private/tmp/yippy_dog.py(2)yippy_dog()
    -> for i in range(10):
    (Pdb) s
    > /private/tmp/yippy_dog.py(3)yippy_dog()
    -> print("YIP YIP!")
    (Pdb) s
    YIP YIP!
    > /private/tmp/yippy_dog.py(2)yippy_dog()
    -> for i in range(10):
    (Pdb)
    

    要从命令行运行调用pdb作为脚本的生成器,请调用pdb模块并跳到相关框架:

    $ python -m pdb yippy_dog.py
    > /private/tmp/yippy_dog.py(1)<module>()
    -> def yippy_dog():
    (Pdb) step
    > /private/tmp/yippy_dog.py(5)<module>()
    -> yippy_dog()
    (Pdb) step
    --Call--
    > /private/tmp/yippy_dog.py(1)yippy_dog()
    -> def yippy_dog():
    (Pdb) step
    > /private/tmp/yippy_dog.py(2)yippy_dog()
    -> for i in range(10):
    (Pdb) step
    > /private/tmp/yippy_dog.py(3)yippy_dog()
    -> print("YIP YIP!")
    (Pdb) step
    YIP YIP!
    > /private/tmp/yippy_dog.py(2)yippy_dog()
    -> for i in range(10):
    (Pdb) step
    > /private/tmp/yippy_dog.py(3)yippy_dog()
    -> print("YIP YIP!")
    (Pdb) step
    YIP YIP!
    > /private/tmp/yippy_dog.py(2)yippy_dog()
    -> for i in range(10):
    

    当然,您可以通过将set_trace()置于生成器中来手动强制断点,但这需要修改/在目标代码中进行调试,这可能并不理想。

答案 1 :(得分:2)

这就是我想要的:

  1. 在发电机的主体中设置断点。
  2. 在pdb提示符下调用一个迭代生成器所有值的函数。
  3. 示例:

    def mygen():
      for e in ...:
        ...               -- set a break point here, for instance
        yield ...
    
    def testgen(g):       -- call this function from the pdb prompt
      for e in g: pass
    

    您也可以让testgen()直接致电mygen(),而不是要求您传递发电机。

答案 2 :(得分:2)

我试过这个。似乎工作,但也许它不是你想要的:

# gen.py

def gen():
    while True:
        yield "foo"

if __name__ == "__main__":
    g = gen()

然后我启动pdb:

$ python2.7 -m pdb gen.py 
> /home/elasand/prog/gen.py(1)<module>()
-> def gen():
(Pdb) s
> /home/elasand/prog/gen.py(5)<module>()
-> if __name__ == "__main__":
(Pdb) s
> /home/elasand/prog/gen.py(6)<module>()
-> g = gen()
(Pdb) s
--Return--
> /home/elasand/prog/gen.py(6)<module>()->None
-> g = gen()
(Pdb) !next(g)
'foo'

答案 3 :(得分:2)

您可以轻松进入任何生成器并逐步完成,我的回答与toes有些相似。

假设我们有一个功能

no = 4
def func(no):
    for i in range(0,no):
        yield i

要进入函数func并迭代它,可以使用pdb.runcall和迭代器next,因此我使用了两者并创建了函数debug_gen和这个函数有助于调试发生器。

def debug_gen(func,*args,**kwargs):
x = func(*args, **kwargs)
results = []
try:
    while True:
            result = pdb.runcall(next, x)
            results.append(result)
except StopIteration:
    return results

所以你只需要使用参数和关键字参数(如果有的话)将函数传递给debug_gen,之后,你必须在任何地方调用debug_gen函数来调试任何生成器函数。