104

Python でファイルのようなオブジェクト (/dev/ を介したシリアル接続) を開き、それを閉じる必要があります。これは、私のクラスのいくつかのメソッドで数回行われます。私がやっていた方法は、コンストラクタでファイルを開き、デストラクタでファイルを閉じることでした。私は奇妙なエラーが発生していますが、それはガベージコレクターなどに関係していると思います.オブジェクトがいつ削除されているのか正確にわからないことにまだ慣れていません=\

私がこれを行っていた理由はtcsetattr、それを開くたびにたくさんのパラメーターを使用する必要があり、そのすべてをあちこちで行うのが面倒だからです。だから私はそれをすべて処理するために内部クラスを実装したいので、それを使用することができます
with Meter('/dev/ttyS2') as m:

私はオンラインで探していましたが、with構文がどのように実装されているかについて本当に良い答えを見つけることができませんでした. __enter__(self)メソッドとメソッドを使用していることがわかりました__exit(self)__。しかし、これらのメソッドを実装する必要があり、 with 構文を使用できますか? それともそれ以上のものがありますか?

これを行う方法の例、またはファイルオブジェクトに既に実装されている方法に関するドキュメントがありますか?

4

3 に答える 3

140

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
    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()
于 2010-09-22T23:31:17.673 に答える
51

最も簡単なのは、標準の 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ファクトリ関数(デコレーターは、作成した「単一のyield」ジェネレーター関数から構築されます)-これにより、開始条件と終了条件を分離すること非常に簡単になり、回避できますネスティングなど。

于 2010-09-23T02:06:38.710 に答える
-10

最初の Google ヒット (私にとって) は、それを簡単に説明しています。

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

そしてPEPはそれをより正確に説明します(しかし、より冗長にも):

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

于 2010-09-22T23:28:59.780 に答える