使用生成器来编写文件的标题和正文是pythonic吗?

时间:2014-03-27 13:43:16

标签: python python-3.x file-io generator send

如果我要用这个内容写一个文件:

#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!

使用send使用生成器执行此操作会非常非pythonic吗?我从未见过其他地方使用的发电机。

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。

4 个答案:

答案 0 :(得分: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是一个协程。

答案 1 :(得分: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!
""")

我猜你的实际情况虽然不同......

答案 2 :(得分: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')

所以我不确定它的好处是什么。

答案 3 :(得分:0)

协程的意义在于.send()调用之间保存内部状态。

协程通常用于实现"消费者"模式(我很少使用它们来包装xlwt工作表:我需要跟踪要刷新它们的行数)。没有任何状态,你可以使用一个没有任何状态的简单函数(或文件对象的.write()方法)