【问题标题】:Python Generators and yield : How to know which line the program is atPython 生成器和产量:如何知道程序在哪一行
【发布时间】:2011-09-15 21:38:16
【问题描述】:

假设你在 Python 中有一个像这样的简单生成器:

更新:

def f(self):        
    customFunction_1(argList_1)
    yield
    customFunction_2(argList_2)
    yield
    customFunction_3(argList_3)
    yield
    ...

我在另一个脚本中调用 f(),例如:

    h=f()
    while True:
        try:
            h.next()
            sleep(2)
        except KeyboardInterrupt:
                              ##[TODO] tell the last line in f() that was executed

有没有办法可以完成上面的 [TODO] 部分?那就是知道在键盘中断发生之前执行的 f() 中的最后一行?

【问题讨论】:

    标签: python generator yield


    【解决方案1】:

    可以使用 enumerate() 来计数:

    def f():
    
        ...
        yield
        ...
        yield
        ... 
    
    
    for step, value in enumerate(f()):
        try:
            time.sleep(2)
        except KeyboardInterrupt:
            print(step) # step holds the number of the last executed function
    

    (因为在您的示例中 yield 不会产生值,value 当然会是 None)

    或使用详细指示非常明确:

    def f():
    
        ...
        yield 'first function finished'
        ...
        yield 'almost done'
        ... 
    
    
    for message in f():
        try:
            time.sleep(2)
        except KeyboardInterrupt:
            print(message)
    

    【讨论】:

    • 我已经更新了我的代码中实际上没有的函数定义。但我猜我仍然可以使用你的方法..
    • 只是让您更轻松,并使用 enumerate() 将计数器移至 for 循环
    【解决方案2】:

    如果您想知道行号以进行调试,那么在 CPython 中您可以使用h.gi_frame.f_lineno。这是接下来将执行的行,并且是 1-indexed。我不确定这是否适用于 CPython 以外的 Python 实现。

    h=f()
    while True:
        try:
            h.next()
            sleep(2)
        except KeyboardInterrupt:
            print h.gi_frame.f_lineno - 1 # f_lineno is the line to be executed next.
    

    如果您不想出于调试目的而知道这一点,那么 Remi's enumerate solution 会更简洁。

    【讨论】:

      【解决方案3】:

      你为什么不从 f() 中产生 i 并使用它?

      val = h.next()
      

      【讨论】:

        【解决方案4】:
        def f(self):        
            sleep(10)
            yield
            sleep(10)
            yield
            sleep(10)
            yield
        
        
        h=f()
        while True:
            try:
                h.next()
            except KeyboardInterrupt:
                stack_trace = sys.exc_info()[2]    # first traceback points into this function where the exception was caught
                stack_trace = stack_trace.tb_next  # now we are pointing to where it happened (in this case)
                line_no = stack_trace.tb_lineno    # and here's the line number
                del stack_trace                    # get rid of circular references
        

        我将对sleep() 的调用移至f,因为这仅在f() 内部发生异常时才有效。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-09-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-01-18
          • 1970-01-01
          • 1970-01-01
          • 2017-10-09
          相关资源
          最近更新 更多