簡體   English   中英

Python生成器:錯誤僅在注釋后可見

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM