5

別の質問を解決しようとしているときに、これに少し驚きました。

これは私には非常に奇妙に思えたので、質問する価値があると思いました。で動作しない__getattr__ように見えるのはなぜwithですか?

このオブジェクトを作成すると:

class FileHolder(object):
    def __init__(self,*args,**kwargs):
        self.f= file(*args,**kwargs)

    def __getattr__(self,item):
        return getattr(self.f,item)

と一緒に使用するとwith

>>> a= FileHolder("a","w")
>>> a.write
<built-in method write of file object at 0x018D75F8>
>>> with a as f:
...   print f
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: __exit__
>>> a.__exit__
<built-in method __exit__ of file object at 0x018D75F8>

なぜこれが起こるのですか?

編集

>>> object.__exit__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'object' has no attribute '__exit__'

絶対に継承しない__exit__

4

3 に答える 3

6

withステートメント opcodeSETUP_WITHは、新しいスタイルのクラス (古いスタイルのクラスではなく)を__exit__無視する「特別なメソッド検索」として検索します。詳細については、このメーリング リスト スレッドを参照してください。そこでは、特別なメソッド ルックアップ セマンティクスの追加について議論されています (最終的にはそうします)。これらの特別なメソッドがこのように検索される理由の詳細については、新しいスタイルのクラスの特別なメソッドの検索も参照してください。__getattr____getattribute__with

特に、特別なメソッド ルックアップ__getattr__型オブジェクトをバイパスします。したがって、ドキュメントにはメソッドが として検索されると書かれていtype(mgr).__exit__ますが、このコードは機能しません。

class M(type):
    def __getattr__(*args): return lambda: 0

class X(object):
    __metaclass__ = M

x = X()
type(x).__exit__ # works, returns a lambda

with x: pass # fails, AttributeError
于 2012-09-28T02:51:34.883 に答える
5

確かなことは言えませんが、 with ステートメントを説明する PEP を読んだ後:

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

これは私に飛びつきました:

A new statement is proposed with the syntax:

    with EXPR as VAR:
        BLOCK

....

The translation of the above statement is:

    mgr = (EXPR)
    exit = type(mgr).__exit__  # Not calling it yet
    value = type(mgr).__enter__(mgr)

....

すぐそこに。with ステートメントは呼び出しませんが、存在しない__getattr__(__exit__)呼び出しtype(a).__exit__でエラーが発生します。

したがって、それらを定義するだけです:

class FileHolder(object):                                                                                                                 
    def __init__(self,*args,**kwargs):
        self.f= file(*args,**kwargs)

    def __enter__(self,*args,**kwargs):
        return self.f.__enter__(*args,**kwargs)

    def __exit__(self,*args,**kwargs):
        self.f.__exit__(*args,**kwargs)

    def __getattr__(self,item):
        return getattr(self.f,item)
于 2012-09-28T02:51:51.010 に答える