2017-03-05 39 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