简体   繁体   English

如何在Python中获取生成器执行的最后一行

[英]How to get last line executed by a generator in Python

I am trying to get number of last line that has been executed by a generator in Python. 我试图获取由Python生成器执行的最后一行的编号。 I find a ways to get it in several cases: 在几种情况下,我找到了一种获取方法:

  • generator suspended by yield , 发电机因yield停产,
  • generator failed with an exception (not the StopIteration ), 生成器因异常(不是StopIteration )而失败,
  • generator returned by explicit raising of the StopIteration . 通过显式提高StopIteration返回的生成器。

But I am asking for an advice about how to get the line number in case of the StopIteration is raised automatically after the generator executed return statement or just reached last line of corresponding function. 但是我正在寻求有关在生成器执行return语句后或刚到达相应函数的最后一行后StopIteration自动升高的情况下如何获取行号的建议。

A simplified code example I used is listed below. 下面列出了我使用的简化代码示例。

from sys import exc_info

def gen1():
    print("1.1")
    yield
    print("1.2")
    raise StopIteration()

def gen2():
    print("2.1")
    yield
    print("2.2")
    return

def gen3():
    print("3.1")
    yield
    print("3.2")
    raise RuntimeError()

for gen in [ g for n, g in globals().items() if n.startswith("gen") ]:
    g = gen() # launch the generator
    while True:
        try:
            next(g)
        except StopIteration: # generator normally returned
            tb = exc_info()[2].tb_next
            if tb is None:
                print("How to get last line?")
            else:
                print("last line: %s" % tb.tb_frame.f_lineno)
            break
        except BaseException: # generator failure
            tb = exc_info()[2].tb_next
            print("last line: %s" % tb.tb_frame.f_lineno)
            break
        else:
            print("last line: %s" % g.gi_frame.f_lineno)

Execution of this code returns: 执行此代码将返回:

3.1
last line: 17
3.2
last line: 19
2.1
last line: 11
2.2
How to get last line?
1.1
last line: 5
1.2
last line: 7

The information you want is in the frame object. 所需的信息在框架对象中。

But the frame object has already been garbage collected. 但是框架对象已经被垃圾回收了。 The reference to it in g.gi_frame is set to None when the function returns. 函数返回时, g.gi_frameg.gi_frame的引用将设置为None

The traceback won't help you, because the traceback comes from the machinery inside the interpreter after the function has returned, so it has nowhere to get it (and you've already seen that it doesn't even try). 追溯不会对您有帮助,因为该追溯来自函数返回后的解释器内部的机械,因此它无处可寻(您已经看到它甚至没有尝试过)。


But if you can change your code to grab a reference to the gi_frame object while the generator is running and hold onto it after it finishes, you'll keep that—and all of the other associated garbage—alive. 但是,如果您可以更改代码以在生成器运行时获取对gi_frame对象的引用,并在完成后保留该引用,那么您以及所有其他相关的垃圾将保持有效。

Which means f_lineno may be valid, as used in your last case that never happens. 这意味着f_lineno可能是有效的,就像您上一次从未发生过的情况一样。 I don't know if there's any way to check when f_lineno is and isn't meaningful, but the traceback-generating code might know that if you dive into its source. 我不知道是否有任何方法可以检查f_lineno是有意义的,但是如果生成了回溯代码,您可能会知道。

If not, f_lasti will definitely be the bytecode offset of the RETURN_VALUE op. 如果不是,则f_lasti肯定是RETURN_VALUE op的字节码偏移量。 Python of course doesn't guarantee anywhere that it doesn't do anything funky with the lasti before releasing the frame, but it doesn't in any version yet, and it's hard to see what reason there would be to do so in the future. 当然,Python不能保证在发布框架之前它不会对lasti做任何时髦的事情,但是它并没有在任何版本中进行,而且很难知道将来会有什么原因。 So it should always be correct to use the information in f_code.co_lnotab to generate the line number for f_lasti . 因此,它应该永远是正确使用信息f_code.co_lnotab产生的行号f_lasti See the dis module for help on that. 请参阅dis模块以获取帮助。 (If your Python is new enough, it exposes a findlinestarts that does it for you; if not, read the source of the module. Or write your own lnotab parser from the docs in the Objects directory of the interpreter source, if you want some real fun.) (如果您的Python足够新,它将公开一个findlinestarts为您完成;否则,请读取模块的源代码。或者,如果需要的话,可以从解释器源的Objects目录中的docs中编写自己的lnotab解析器。真有趣。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM