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


77

我必须在python中打开一个类似文件的对象(它是通过/ dev /的串行连接),然后关闭它。这是在我的课堂的几种方法中完成的。我的工作方式是在构造函数中打开文件,然后在析构函数中关闭文件。我遇到了奇怪的错误,我认为这与垃圾收集器有关,因此,我仍然不习惯于不确切知道何时删除对象= \

我这样做的原因是因为tcsetattr每次打开它时都必须使用大量参数,并且在整个地方进行所有操作都会很烦人。所以我想实现一个内部类来处理所有事情,这样我就可以使用它
with Meter('/dev/ttyS2') as m:

我当时在网上寻找,但找不到如何实现with语法的真正好答案。我看到它使用__enter__(self)__exit(self)__方法。但是,我要做的就是实现那些方法,并且可以使用with语法吗?还是还有更多呢?

是否已经有关于如何执行此操作的示例,或者是否已有文件说明了如何在我可以查看的文件对象上实现该文件?

Answers:


100

这些方法几乎是使对象与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()

22
def __enter__(self): return self如果要Meter在with块中引用。
Morgoth

37

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

import contextlib

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

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


1
这比基于类的方法要简单得多。
byxor

6
为了确保theobj.close()即使在发生异常的情况下也可以执行,可以包装yield theobj一个try...finally块。
akesfeden

1

Google的第一个热门歌曲(对我来说)足以说明问题:

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

PEP更准确地解释了它(但也更冗长):

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


2
我实际上看到了这些,根本不认为它们中的任何一个都非常清晰。第一个几乎说“有称为_ enter_和_ exit_的方法”,对它们几乎没有解释。PEP几乎只是在谈论新语法的必要性
Falmarri

不,通过示例和解释很简单。您需要再次阅读;这不是一个复杂的功能。
格伦·梅纳德

5
无论如何,您应该知道整个社区很少收到仅链接的答案。至少从支持您的断言的来源中分享一些东西。
IAbstract
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.