在 python 中自定义类中实现使用‘ with object() as f’

我必须在 python 中打开一个类似文件的对象(它是通过/dev/的串行连接) ,然后关闭它。这在我的类的几个方法中进行了多次。我是这样做的: 在构造函数中打开文件,然后在析构函数中关闭它。虽然我得到了奇怪的错误,我认为这与垃圾收集器等,我仍然不习惯不知道确切的时候,我的对象被删除 =

我之所以这样做是因为每次打开 tcsetattr时,我必须使用带有一大堆参数的 tcsetattr,而且这样做很烦人。因此,我想实现一个内部类来处理所有这些问题,这样我就可以使用它来完成
with Meter('/dev/ttyS2') as m:

我在网上查找,但是我找不到一个关于 with语法是如何实现的好答案。我看到它使用 __enter__(self)__exit(self)__方法。但是我需要做的就是实现这些方法并且使用 with 语法吗?还是还有别的原因?

有没有关于如何做到这一点的例子,或者有关于如何在文件对象上实现这一点的文档,我已经看过了?

57089 次浏览

The first Google hit (for me) explains it simply enough:

Http://effbot.org/zone/python-with-statement.htm

PEP 解释得更加精确(但也更加冗长) :

Http://www.python.org/dev/peps/pep-0343/

Those methods are pretty much all you need for making the object work with with statement.

__enter__中,必须在打开并设置文件对象之后返回该文件对象。

__exit__中,必须关闭 file 对象。写入它的代码将在 with语句体中。

class Meter():
def __init__(self, dev):
self.dev = dev
def __enter__(self):
#ttysetattr etc goes here before opening and returning the file object
self.fd = open(self.dev, MODE)
return self
def __exit__(self, type, value, traceback):
#Exception handling here
close(self.fd)


meter = Meter('dev/tty0')
with meter as m:
#here you work with the file object.
m.fd.read()

最简单的方法可能是使用标准的 Python 库模块 Contextlib:

import contextlib


@contextlib.contextmanager
def themeter(name):
theobj = Meter(name)
try:
yield theobj
finally:
theobj.close()  # or whatever you need to do at exit




# usage
with themeter('/dev/ttyS2') as m:
# do what you need with m
m.read()

这并不意味着 Meter本身就是一个上下文管理器(因此对于这个类来说是非侵入性的) ,而是“装饰”它(不是在 Python 的“装饰语法”的意义上,而是几乎,但不完全,在装饰设计模式的意义上; ——使用一个工厂函数 themeter,其中 是一个上下文管理器(contextlib.contextmanager装饰器从你编写的“ single-yield”生成器函数构建)——这使得 所以更容易分离进入和退出条件,避免嵌套等。