Python:generator中的自定义“with open()”语句未生成

2024-09-30 16:38:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个文件类,你可以从中分析数据,写入数据等。我想从任何应用程序中使用它,如:

f = MyFileClass() # __init__ method puts a lot of default data in object
with f.open() as file: # where f.open() is custom MyFileClass method
    file.write("foo") # file should close automatically after this

我试过了:

^{pr2}$

但我在运行第一个代码后

line 22, in fill_new_file with f.open() as file: File "C:\Python34\lib\contextlib.py", line 61, in __enter__ raise RuntimeError("generator didn't yield") from None RuntimeError: generator didn't yield

我想这不是ContextManager的工作方式。怎么做我想要的?在


Tags: 文件数据in应用程序aswithlineopen
2条回答

试试这个:

@contextmanager
def open(self):
    try:
        yield open(os.path.join(self.directory, self.name), self.flags)
    except Exception as e:
        print(e.__traceback__)

上下文管理器是生成器,而不是函数。在

本打算发表评论,但事情变得太复杂了,不能就此置之不理,但我确实有答案。在

代码的修正版本可以简化为

@contextmanager
def myopen(path):
    try:
        yield open(path)
    except Exception as e:
        print(e.__traceback__)

在尝试之前,让我们使用以下命令获取打开文件句柄的计数:

^{pr2}$

现在使用我们的上下文管理器

>>> with myopen('/tmp/a_file') as f:
...     print(f.read())
...     print(os.listdir('/proc/self/fd'))
... 
Contents of file

['0', '1', '2', '3', '4']

是的,文件描述符计数增加了,但是现在我们已经脱离了上下文管理器,让我们看看

>>> print(os.listdir('/proc/self/fd'))
['0', '1', '2', '3', '4']

这就破坏了为文件设置上下文管理器的目的(我们希望使用默认的自动关闭功能,所以重新启动解释器,然后尝试这样做。在

@contextmanager
def myopen(path):
    try:
        with open(path) as f:
            yield f
    except Exception as e:
        print(e.__traceback__)

重新运行我们的测试

>>> with myopen('/tmp/a_file') as f:
...     print(f.read())
...     print(os.listdir('/proc/self/fd'))
... 
Contents of file

['0', '1', '2', '3', '4']

现在在上下文管理器之外

>>> print(os.listdir('/proc/self/fd'))
['0', '1', '2', '3']

是的,看起来它工作了(文件已成功关闭),但是如果有一个不存在的路径来查看异常处理呢?在

>>> with myopen('/tmp/no_path') as f:
...     print(f.read())
... 
<traceback object at 0x7f6b64b618c8>
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.4/contextlib.py", line 61, in __enter__
    raise RuntimeError("generator didn't yield") from None
RuntimeError: generator didn't yield

异常块确实触发了,请注意traceback对象,但是由于上下文管理器没有正确生成,因此会引发一个与您之前看到的不同的异常。我不知道该推荐什么,但我推荐的是记录错误(使用记录器),然后重新读取异常。您可以考虑返回某种类型的伪对象,该对象在读取时会引发异常,或者什么也不返回,但是您需要确定什么是最适合您的情况的。在

相关问题 更多 >