2011-05-28 87 views
2

我從這張幻燈片學習Python的發電機:http://www.dabeaz.com/generators/Generators.pdf
這裏面一個例子,可以這樣描述:
你有一個日誌文件名爲log.txt,寫一個程序,看它的內容,如果有新的線添加到它,打印它們。有兩種解決方案:在這種情況下使用發電機有什麼好處?

1. with generator: 

    import time 

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

    logfile = open("log.txt") 
    loglines = follow(logfile) 
    for line in loglines: 
     print line 


2. Without generator: 

    import time 

    logfile = open("log.txt") 

    while True: 
     line = logfile.readline() 
     if not line: 
      time.sleep(0.1) 
      continue 
     print line 

什麼用發電機這裏有什麼好處?

回答

5

如果你只有一把錘子,一切看起來都像釘子

我幾乎只是想回答只以上報價這個問題。只因爲你可以並不意味着你需要所有的時間。

但從概念上講,生成器版本分離功能,跟隨功能用於在等待新輸入時封裝文件的連續讀取。這可以讓你在循環中用你想要的新線做任何事情。在第二個版本中,從文件讀取並打印出的代碼與控制循環混合在一起。這個小例子可能不是真正的問題,但這是你可能想要考慮的問題。

1

一個好處是能夠傳遞你的發電機(說到不同的功能),並通過調用.next()手動迭代。這是你最初的生成器的例子略加修改的版本:

import time 

def follow(file_name): 
    with open(file_name, 'rb') as f: 
     for line in f: 
      if not line: 
       time.sleep(0.1) 
       continue 
      yield line 

loglines = follow(logfile) 
first_line = loglines.next() 
second_line = loglines.next() 
for line in loglines: 
    print line 

首先我打開一個上下文管理器(with語句,該語句自動關閉文件,當你用它做的文件,或例外)。接下來,在我已經使用.next()方法演示的底部,允許您手動逐步瀏覽。如果您需要將邏輯從簡單的for item in gen循環中分離出來,這可能會有用。

+2

在Python 2.6及更高版本中,最好調用'next(gen)'而不是'gen.next()'。在Python 3.x中,後一種語法不再可用。 – 2011-05-28 14:32:57

+0

儘管我同意你幾乎總是希望使用'for'來迭代文件的行,而不是調用'readline',這是少數情況下你不知道的情況之一。 'for'循環會在第一次到達文件結尾時結束,它不會像調用readline()那樣給你重複的空字符串。 – Duncan 2011-05-28 14:36:48

0

理想的最環路的大致形式:

for element in get_the_next_value(): 
    process(element) 

但有時(如在你的例子#2),循環實際上是更爲複雜,因爲你可能會遇到一個元素,有時甚至沒有。這意味着在您的示例中,如果沒有元素,則會混合使用用於生成元素的代碼來處理元素。它在示例中沒有顯示得太清楚,因爲生成下一個值的代碼實際上並不是太複雜,處理只是一行,但示例1將這兩個概念更加乾淨地分開。

一個更好的例子可能是一個使用空行分隔每個段落的文件中的可變長度段落:嘗試爲帶有和不帶有生成器的代碼編寫代碼,您應該看到好處。

0

儘管您的示例可能會充分利用生成器,但我更喜歡使用生成器來封裝任何序列數據的生成,這些數據也存在某種數據過濾。它保持'我正在做的數據'代碼和'我如何獲取數據'代碼分開。

1

生成器函數的定義與普通函數類似,但無論何時需要生成值,它都會使用yield關鍵字而不是返回值。它的主要優點是它允許其代碼以產生一系列值的隨時間的,而不是在一次計算它們並將它們發送回像list.For示例

# A Python program to generate squares from 1 
# to 100 using yield and therefore generator 

# An infinite generator function that prints 
# next square number. It starts with 1 
def nextSquare(): 
    i = 1; 

    # An Infinite loop to generate squares 
    while True: 
     yield i*i     
     i += 1 # Next execution resumes 
       # from this point  

# Driver code to test above generator 
# function 
for num in nextSquare(): 
    if num > 100: 
     break 
    print(num) 

返回發送一個指定的值返回到它的調用者而收益率可以產生一系列值。當我們想迭代序列時,我們應該使用yield,但不希望將整個序列存儲在內存中。

相關問題