在python中的自定义类中实现'with object()为f'的使用

Fal*_*rri 53 python file-io with-statement

我必须在python中打开一个类似文件的对象(它是通过/ dev /的串行连接),然后关闭它.这在我班上的几种方法中已经完成了好几次.我是如何做的是在构造函数中打开文件,然后在析构函数中关闭它.虽然我得到了奇怪的错误,我认为它与垃圾收集器有关,所以,我仍然不习惯不知道我的对象何时被删除= \

我这样做的原因是因为tcsetattr每次打开它时我都必须使用一堆参数,并且在整个地方做这一切都很烦人.所以我想实现一个内部类来处理所有这些,所以我可以用它来做
with Meter('/dev/ttyS2') as m:

我在网上看,我找不到一个关于如何实现with语法的非常好的答案.我看到它使用__enter__(self)__exit(self)__方法.但是,我是否必须实现这些方法,我可以使用with语法?或者还有更多吗?

是否有关于如何执行此操作的示例或有关如何在文件对象上实现它的一些文档我可以查看?

小智 76

这些方法几乎就是使对象与with语句一起工作所需的全部方法.

__enter__打开文件对象并进行设置后,必须返回文件对象.

__exit__你必须关闭文件对象.写入它的代码将在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.fd
    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.read()
Run Code Online (Sandbox Code Playgroud)

  • `def __enter __(self):如果你想在with块中引用`Meter`,则返回self`. (9认同)

Ale*_*lli 23

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

import contextlib

@contextlib.contextmanager
def themeter(name):
    theobj = Meter(name)
    yield theobj
    theobj.close()  # or whatever you need to do at exit
Run Code Online (Sandbox Code Playgroud)

这不会使Meter自己成为一个上下文管理器(因此对该类是非侵入性的),而是"装饰"它(不是在Python的"装饰器语法"意义上,而是在某种意义上几乎,但不是很完整)装饰设计模式;-)有出厂功能的themeter一个上下文管理器(它的contextlib.contextmanager装饰,从"单建立yield你写的"发生器功能) -这使得它如此更容易的进入和退出条件分开,避免了嵌套,&c.

  • 为了确保即使在发生异常的情况下也会执行“theobj.close()”,您可以使用“try...finally”块包装“yield theobj”。 (7认同)