这是一个可以接受的pythonic成语吗?

时间:2010-07-19 17:36:50

标签: python

我有一个帮助导入特殊类型文件的类,以及一个允许我批量执行这些操作的“工厂”类。工厂类使用生成器,因此客户端可以遍历导入器。 我的问题是,我是否正确使用了迭代器?这是一个可以接受的成语吗?我刚开始使用Python。

class FileParser:
  """ uses an open filehandle to do stuff """

class BatchImporter:
  def __init__(self, files):
    self.files=files

  def parsers(self):
    for file in self.files:
      try:
        fh = open(file, "rb")
        parser = FileParser(fh)
        yield parser
      finally:
        fh.close()

  def verifyfiles(
  def cleanup(

---

importer = BatchImporter(filelist)
for p in BatchImporter.parsers():
  p.method1()
  ...

4 个答案:

答案 0 :(得分:12)

你可以做一件事更简单:使用try块而不是finally ... with

with open(file, "rb") as fh:
    yield FileParser(fh)

只要剩下with块,就会自动为您关闭文件。

答案 1 :(得分:7)

像你一样拥有一个生成器的方法绝对没问题。我建议你把所有课程都改成新风格(如果你使用的是Python 2,要么在模块的开头设置__metaclass__ = type,要么将(object)添加到你的所有基础class }语句),因为遗产类是“邪恶的”;-);而且,为了清晰和简洁,我还建议不同地编码生成器...:

  def parsers(self):
    for afile in self.files:
        with open(afile, "rb") as fh:
            yield FileParser(fh)

但这些建议都没有以任何方式谴责使用发电机方法! - )

请注意使用afile代替file:后者是内置标识符,作为一般规则,最好习惯“隐藏“你自己的内置标识符(它不会在这里咬你,但除非你养成正确的习惯,否则它将来会以许多令人讨厌的方式!)。”。

答案 2 :(得分:1)

如果你问我,设计很好,虽然最后使用它的方式并不完全是惯用的。使用catch并且可能重新引发异常(使用raise关键字单独,否则你搞乱堆栈跟踪),并且对于奖励积分,不要捕获:但是捕获异常:(否则,你抓住SystemExit和KeyboardInterrupt)。

或者简单地使用Tim Pietzcker所示的with语句。

答案 3 :(得分:0)

通常,在产生将尝试读取它的解析器对象后关闭文件是不安全的。请考虑以下代码:

parsers = list(BatchImporter.parsers())
for p in parsers:
    # the file object that p holds will already be closed!

如果您没有编写长时间运行的守护程序进程,大多数情况下您不需要需要担心关闭文件 - 当程序退出时它们都会关闭,或者当文件对象被垃圾收集时。 (如果你使用CPython,那么只要对它们的所有引用都丢失,就会发生这种情况,因为CPython使用了引用计数。)

然而,注意释放资源是一个很好的习惯,所以我可能会这样编写FileParser类:

class FileParser:
    def __init__(self, file_or_filename, closing=False):
        if hasattr(file_or_filename, 'read'):
            self.f = file_or_filename
            self._need_to_close = closing
        else:
            self.f = open(file_or_filename, 'rb')
            self._need_to_close = True

    def close(self):
        if self._need_to_close:
            self.f.close()
            self._need_to_close = False

然后BatchImporter.parsers将成为

    def parsers(self):
        for file in self.files:
            yield FileParser(file)

或者,如果你喜欢函数式编程

    def parsers(self):
        return itertools.imap(FileParser, self.files)

暂且不说:如果您是Python的新手,我建议您查看Python style guide(也称为PEP 8)。两个空格的缩进看起来很奇怪。