[英]Python generators: Errors visible only after commenting
我正在嘗試遵循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在到達該語句之前不會檢查這些類型的錯誤,在第一種情況下不是這樣。
在函數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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.