2014-03-27 37 views
11

如果我寫這個內容的文件:使用生成器來編寫文件頭和文本體是pythonic嗎?

#You have been defeated! 
#It's merely a flesh wound! 
We are the knights who say Ni! 
We are the knights who say Ni! 
We are the knights who say Ni! 

難道則是非常不Python的使用發送發電機辦呢?我從來沒有見過其他地方使用這種發電機。

def write(file, header): 

    with open(file,'w') as f: 
     f.write(header) 
     line = (yield) 
     while True: 
      f.write(line) 
      line = (yield) 

    return 

file='holygrail.txt' 
header="#You have been defeated!\n#It's merely a flesh wound!\n" 
generator = write(file,header) 
generator.send(None) 
for i in range(3): 
    generator.send('We are the knights who say Ni!\n') 
generator.close() 

我問,因爲上面的方法將是我帶來許多有益的,而不是在contextlib堆棧打開多個不同的文件流。如果我這樣寫我的文件,我根本不必使用contextlib模塊。

我從來沒有問過這樣的問題,我不知道,它是否屬於stackoverflow或不。

+3

我不知道發電機可以這樣使用!我不知道爲什麼這是投票。 –

+2

[我可以在這裏問什麼主題?](http:// stackoverflow。com/help/on-topic) – Bonifacio2

+0

我有幾個擔心:一,你如何停止迭代,即文件什麼時候關閉?二,''generator.send(None)'似乎不必要,如果你交換'while True'循環中兩行的順序並刪除第一行'(yield)'。 – chepner

回答

10

我喜歡你的解決方案的創造性,但我的主觀意見是使用contextlib.ExitStack()看起來更乾淨,比使用發生器更具可讀性,因爲每個發生器需要使用generator.send(None)啓動並明確關閉。


順便說一句,(雖然我認爲contextlib會導致更短,更可讀的代碼),write可以簡化一點:

def write(file, header): 
    with open(file, 'w') as f: 
     f.write(header) 
     while True: 
      line = (yield) 
      f.write(line) 
    return 

注意你只需要一個line = (yield)代替二。

此外,而不是引發的發電機generator.send(None)你可以使用coroutine裝飾:

def coroutine(func): 
    """ http://www.python.org/dev/peps/pep-0342/ """ 
    def wrapper(*args, **kw): 
     gen = func(*args, **kw) 
     gen.send(None) 
     return gen 
    return wrapper 

這是把一個發電機爲一個協程通常理解的成語(PEP0342David Beazley talk)。所以用它來裝飾你的發生器也可以達到廣告的目的,write是一個協程。

+0

執行generator.close()會足夠嗎? –

+0

@ tommy.carstensen:是的,這也可以,但是那真的是「Pythonic」?似乎沒有任何好處超過'f = open(...); f.write(...); f.close()'。 – unutbu

+0

我不需要處理contextlib.ExitStack()作爲堆棧:f = stack.enter_context(open(...))執行清理代碼嗎?我使用contextlib,因爲我需要打開多個文件。如果我可以在生成器中打開每個文件,這將非常優雅。 –

0

我覺得這個問題有點主觀,但我相信「Pythonic」也意味着保持簡單。而對於你的具體情況,這將可能是一些沿

open("blah.txt", 'w').write("""\ 
#You have been defeated! 
#It's merely a flesh wound! 
We are the knights who say Ni! 
We are the knights who say Ni! 
We are the knights who say Ni! 
""") 

行我猜你實際的情況是,雖然不同的...

0

你的代碼是不是更短,並沒有什麼清晰的,比

file='holygrail.txt' 
header="#You have been defeated!\n#It's merely a flesh wound!\n" 
with open(file, w) as fh: 
    fh.write(header) 
    for i in range(3): 
     fh.write('We are the knights who say Ni!\n') 

所以我不確定是什麼好處。

+0

我想問題是真正的輸入來自其他地方。 – ElmoVanKielmo

+0

是的,真正的輸入來自其他地方。來自一個文件的頭文件,可以很容易地保存在內存中,以及來自多個其他文件的數據/文本,這些文件都太大而無法保存在內存中。 –

0

協程的要點是在.send()調用之間保存內部狀態。 (我很少使用它們來包裝xlwt工作表:我需要跟蹤行數來刷新它們)。沒有任何狀態,你可以使用沒有任何狀態的簡單函數(或文件對象的.write()方法)