我有一个文件类,你可以从中解析数据,写数据等。我想在任何类似的应用程序中使用它:
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
我试过了:
# it's in MyFileClass()
from contextlib import contextmanager
@contextmanager
def open(self):
try:
return open(os.path.join(self.directory, self.name), self.flags)
except Exception as e:
print(e.__traceback__)
但我在运行第一个代码后得到了
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
我想这不是上下文管理员的工作方式。怎么做我想要的?
答案 0 :(得分:7)
试试这个:
@contextmanager
def open(self):
try:
yield open(os.path.join(self.directory, self.name), self.flags)
except Exception as e:
print(e.__traceback__)
上下文管理器是生成器,而不是函数。
答案 1 :(得分:5)
要发表评论但事情变得太复杂而不能离开那里,但我确实有答案。
更正后的代码版本可以简化为
@contextmanager
def myopen(path):
try:
yield open(path)
except Exception as e:
print(e.__traceback__)
在我们尝试之前,让我们使用这个来计算打开的文件句柄:
>>> os.listdir('/proc/self/fd')
['0', '1', '2', '3']
现在使用我们的上下文管理器
>>> 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
对象,但是由于上下文管理器没有正确屈服,所以会像你之前看到的那样引发一个不同的异常。我不知道该推荐什么,但我建议记录错误(使用记录器),然后重新加载异常。您可以考虑返回某种虚拟对象,然后在读取时引发异常,或者不返回任何内容,但您需要确定最适合您案例的内容。