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

Python 如何从pdb控制台进入任意生成器函数调用?,python,pdb,Python,Pdb,我有一个行为不正常的生成器函数,我想从pdb控制台调用它,然后逐步遍历它的每个迭代,看看它的哪个部分是错误的。我希望我能 (Pdb) !pdb.runcall(broken_function, with_arg) 但由于函数是一个发生器,我得到的只是 <generator object broken_function at 0x2badc30> 有人知道我现在能做什么吗 编辑:我应该早点说清楚:我当然想在相关的循环中设置一个断点,但是我正在运行一个for me只读文件系统的代码,

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

(Pdb) !pdb.runcall(broken_function, with_arg)
但由于函数是一个发生器,我得到的只是

<generator object broken_function at 0x2badc30>
有人知道我现在能做什么吗


编辑:我应该早点说清楚:我当然想在相关的循环中设置一个断点,但是我正在运行一个for me只读文件系统的代码,这使得它不实用。

这就是我要尝试的:

在发电机主体中设置断点。 在pdb提示符下调用一个函数,该函数遍历生成器的所有值。 例如:

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,而不需要您传入生成器。

这就是我要尝试的:

在发电机主体中设置断点。 在pdb提示符下调用一个函数,该函数遍历生成器的所有值。 例如:

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,而无需将生成器传入。

编辑:简短版本:

选项:

使用pdb定位函数。运行“my_模块.my_方法”并逐步完成生成器

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
将pdb作为脚本调用python-m pdb my_script.py

使用测试文件yippy_dog.py:

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

yippy_dog()
要从pdb控制台以生成器为目标,请导入所需的模块,然后调用。在调用相关方法时运行:

>>> 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来手动强制断点,但这需要在目标代码中进行修改/放置调试,这可能并不理想。

Edit:Short version:

选项:

使用pdb定位函数。运行“my_模块.my_方法”并逐步完成生成器

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
将pdb作为脚本调用python-m pdb my_script.py

使用测试文件yippy_dog.py:

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

yippy_dog()
要从pdb控制台以生成器为目标,请导入所需的模块,然后调用。在调用相关方法时运行:

>>> 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来手动强制断点,但这需要在目标代码中进行修改/放置调试,这可能并不理想。

我尝试过这个方法。似乎有效,但可能不是你想要的:

# 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'

我试过这个。似乎有效,但可能不是你想要的:

# 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'

你可以很容易地进入任何一个发电机,并逐步通过它,我的答案有点类似于

假设我们有一个函数

no = 4
def func(no):
    for i in range(0,no):
        yield i
要进入函数func并对其进行迭代,接下来可以使用pdb.runcall和迭代器,因此我使用了这两个函数并创建了一个函数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函数来调试任何生成器函数。

您可以轻松地进入任何生成器并逐步完成它,我的答案与之类似

假设我们有一个函数

no = 4
def func(no):
    for i in range(0,no):
        yield i
要进入函数func并对其进行迭代,接下来可以使用pdb.runcall和迭代器,因此我使用了这两个函数并创建了一个函数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函数来调试任何生成器函数。

问题是,我正在从只读目录运行代码,因此很遗憾,修改代码不是一个选项!我想我应该已经指定了。也许你可以在mygen:pass中调用pdb.runfor e,而不是定义testgen。你可能可以从pdb中调用nextthe_gen?问题是,我是从只读目录运行代码的,所以很遗憾,修改代码不是一个选项!我想我应该指定它。也许你可以调用MyGEN中的PDBRunEe:通过而不是定义TestGEN。你可以调用PDB中的NEXTHEY GEGEN。我看到了你的编辑,并给我的答案添加了一个编辑,使答案变得清晰,而不是在示例的中间。你不需要在相关的循环中设置断点。我看到了你的编辑,并给我的答案添加了一个编辑,使答案变得清晰,而不是让它处于例子的中间。您不需要在相关循环中设置断点。当yippy_dog是生成器函数时,这似乎不起作用,因为它会随生成器立即返回。这似乎不起作用
当yippy_dog是一个生成器函数时,因为它会立即返回生成器。不确定这个答案是否是OP想要的,但这为我解决了问题。在ipython中,您可以通过导入生成器函数,获取一个生成器,例如g=gen,然后在下一个方法上调用ipdb.runcall,例如ipdb.runcallg.next。不确定这个答案是否是OP想要的,但这为我解决了问题。在ipython中,您可以通过导入生成器函数,获取一个生成器(例如g=gen),然后在下一个方法(例如ipdb.runcallg.next)上调用ipdb.runcall来实现这一点。这似乎是最干净的解决方案。我不再有这个问题了,但我会接受你的答案,除非有人强烈反对谢谢,谢谢。这似乎是最干净的解决方案。我不再有这个问题了,但我会接受你的答案,除非有人强烈反对谢谢,谢谢。