2017-03-05 35 views
1

我在尝试下面的python代码来模拟* nix系统的'tail'命令。Python生成器:错误只能在评论后才可见

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 

感谢您的答复。

+0

if条件是否满足(在第二次通话中)只有当你不屈服时才行? – Peaceful

回答

3

简短回答

第一个是实例化一个发电机(但它不赋值给一个变量)和第二个是一个函数调用。


长的答案

这是因为Python的动态类型检查的,当你有yield声明,你的函数用作发电机和这条线 -

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

手段你是实例化发生器不调用函数

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

在将删除了yield声明的其他情况下,它开始 - 当你将这个实例变量的一些和调用next方法发生器,它实际上火灾它即你会得到这个错误表现为正常功能,这意味着 - tail(open(sys.argv[1],'r'))现在是一个函数调用,因此它抛出了一个错误。

我的意思是动态是python不检查这些类型的错误,直到它达到该声明,在第一种情况下不是。

+0

非常清晰,简洁。谢谢。 – dheerajSuthar

3

yield的函数中,它是一个生成器。发生器函数仅在请求下一个值时执行其包含的代码。简单地调用生成器函数只会创建该生成器对象。如果你这样做而没有对这个对象做任何事情,比如循环播放,什么都不会发生。

删除yield使得函数急切地评估,所以它的代码实际上被执行。

如果您实际上遍历了生成器,那么当readline()生成一条空行时,它将产生一个错误。由于这样的空行只能出现在文件的末尾(看起来空白行实际上包含单个换行符),因此将其放入循环中无论如何都是没有意义的。取而代之的是:

while True: 
    line = f.readline() 
    if not line: 
     time.sleep(0.1) 
     continue 
    yield line 

使用此:

for line in f: 
    yield line 

,而是这个:

if(len(sys.argv) >= 2): 
    print 'calling tail' 
    tail(open(sys.argv[1],'r')) 

你应该实际执行生成的内容,像这样的东西:

if(len(sys.argv) >= 2): 
    print 'calling tail' 
    for line in tail(open(sys.argv[1],'r')): 
     print line 
+0

感谢您的回复。延迟和循环在那里等待输入,以便它的行为类似于Linux上的tail命令,如'tail -f hello.txt'。请在输出中查看原始帖子中的编辑内容。我同时在另一个终端的文件hello.txt中添加文本。 – dheerajSuthar