Skip to main content
 首页 » 编程设计

Python 生成器 : Errors visible only after commenting

2025年05月04日16del

我正在尝试使用 python 代码来模拟 *nix 系统的“tail”命令。

import sys 
def tail(f): 
    print 'in tail with ',f 
    f.seek(0,2) 
    while True: 
        line = f.readline() 
        if not line: 
            time.sleep(0.1) 
            continue 
        yield line 
 
if(len(sys.argv) >= 2): 
    print 'calling tail' 
    tail(open(sys.argv[1],'r')) 
else: 
    print 'Give file path.\n' 

我犯了一个错误(错过了导入时间模块)。然而,奇怪的是没有错误被抛出并且程序正在静默退出。 输出(评论前):

$ python tail.py /var/log/dmesg  
calling tail 

但是,如果我在使用时间模块的行之后注释行,则会抛出错误。

import sys 
def tail(f): 
    print 'in tail with ',f 
    f.seek(0,2) 
    while True: 
        line = f.readline() 
        if not line: 
            time.sleep(0.1) 
        #     continue 
        # yield line 
 
if(len(sys.argv) >= 2): 
    print 'calling tail' 
    tail(open(sys.argv[1],'r')) 
else: 
    print 'Give file path.\n' 

输出(注释后)

$ python tail.py /var/log/dmesg  
calling tail 
in tail with  <open file '/var/log/dmesg', mode 'r' at 0x7fc8fcf1e5d0> 
Traceback (most recent call last): 
  File "tail.py", line 14, in <module> 
    tail(open(sys.argv[1],'r')) 
  File "tail.py", line 8, in tail 
    time.sleep(0.1) 
NameError: global name 'time' is not defined 

任何人都可以解释为什么在第一种情况下(在评论之前)没有抛出错误吗?不应该在解释器进入该行时立即抛出错误吗?

更正的程序:

import sys 
import time 
def tail(f): 
    print 'in tail with ',f 
    f.seek(0,2) 
    while True: 
        line = f.readline() 
        if not line: 
            time.sleep(0.1) 
            continue 
        yield line 
 
if(len(sys.argv) >= 2): 
    print 'calling tail' 
    t = tail(open(sys.argv[1],'r')) 
    for i in t: 
        print i 
else: 
    print 'Give file path.\n' 

输出:

$ python tail.py hello.txt  
calling tail 
in tail with  <open file 'hello.txt', mode 'r' at 0x7fac576b95d0> 
hello there 1 
 
hello there 2 
 
hello there 3 

感谢您的回复。

请您参考如下方法:

简答题

第一个是实例化生成器(但不将其分配给变量),第二个是函数调用。


长答案

这是因为 python 的动态类型检查,当你有 yield 语句时,你的函数表现为一个生成器,这一行 -

tail(open(sys.argv[1],'r')) 

意味着您正在实例化生成器而不是调用函数。当您将此实例分配给某个变量并调用生成器的 next 方法时,您会遇到该错误,该生成器实际上会启动它,即 -

t = tail(open(sys.argv[1],'r')) # t is a generator here  
t.next() 

另一种情况下,您删除了 yield 语句,它开始表现为正常函数,这意味着 - tail(open(sys.argv[1],'r')) 现在是一个函数调用,因此它抛出了一个错误。

我所说的动态是指 python 在到达该语句之前不会检查这些类型的错误,而在第一种情况下则不会。