开发者

Implementing use of 'with object() as f' in custom class in python

I have to open a file-like object in python (it's a serial connection through /dev/) and then close it. This is done several times in several methods of my class. How I WAS doing it was opening the file in the constructor, and then closing it in the destructor. I'm getting weird errors though and I think it has to do with the garbage collector and such, I'm still not used to not knowing exactly when my objects are being deleted =\

The reason I was doing this is because I have to use tcsetattr with a bunch of parameters each time I open it and it gets annoying doing all that all over the place. So I want to implement an inner class to handle all that so I can use it doing

with Meter('/dev/ttyS2') as m:

I was looking online and I couldn't find a really good answer on how the with syntax is implemented. I saw that it uses the __enter__(self) and __exit(self)__ methods. But is all I have to do implement those methods and I can use the with syntax? Or is there more to it?

Is there either an example on how to do this or some documentation on how it's implemen开发者_运维知识库ted on file objects already that I can look at?


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

In __enter__ you have to return the file object after opening it and setting it up.

In __exit__ you have to close the file object. The code for writing to it will be in the with statement body.

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()


Easiest may be to use standard Python library module 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()

This doesn't make Meter itself a context manager (and therefore is non-invasive to that class), but rather "decorates" it (not in the sense of Python's "decorator syntax", but rather almost, but not quite, in the sense of the decorator design pattern;-) with a factory function themeter which is a context manager (which the contextlib.contextmanager decorator builds from the "single-yield" generator function you write) -- this makes it so much easier to separate the entering and exiting condition, avoids nesting, &c.


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

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

and the PEP explains it more precisely (but also more verbosely):

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜