web-dev-qa-db-ja.com

pythonのカスタムクラスに「with object()as f」の使用を実装する

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

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

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

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

59
Falmarri

これらのメソッドは、オブジェクトを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()
70
dekomote

最も簡単なのは、標準の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の「装飾構文」という意味ではなく、ほとんどの場合、デコレータのデザインパターンの意味で、完全ではありません。-)ファクトリ関数themeter whichisコンテキストマネージャ(contextlib.contextmanagerデコレータ作成した「single -yield」ジェネレーター関数からビルド)-これにより、soの開始と終了をはるかに簡単に分離できます条件、ネストを回避、&c。

22
Alex Martelli

(私にとって)最初のGoogleのヒットはそれを十分に単純に説明しています:

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

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

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

1
Glenn Maynard