2012-06-26 17 views
24

私は "python属性の参照処理"と言っています。つまり、x.fooを書くときにPythonは何をしますか?属性名がある場合、私はこのことについて多くのドキュメントに見つからなかったウェブを検索python属性ルックアッププロセスの仕組みは?

、私が見つけた最高の論文の一つは、次の手順にproccessを再開し

  1. (あなたは、記事全文hereを見ることができます) objectnameの特殊な(つまりPythonが提供する)属性は、それを返します。
  2. attrnameのobjectname .__ class __.__ dict__を確認してください。それが存在し、データ記述子である場合は、記述子の結果を返します。同じ場合には、objectname .__ class__のすべての基底を検索します。
  3. attrnameにobjectname .__ dict__をチェックし、見つかった場合は戻します。 objectnameがクラスの場合は、そのベースも検索します。それがクラスであり、記述子がそのクラスまたはその基底に存在する場合は、記述子の結果を返します。
  4. attrnameのobjectname .__ class __.__ dict__を確認してください。存在し、非データ記述子である場合は、記述子の結果を返します。それが存在し、記述子でない場合は、ただそれを返します。それが存在し、データ記述子である場合は、ポイント2に戻ってきたのでここにはいけません。objectname .__ class__のすべてのベースを検索して同じケースを探します。
  5. Raise AttributeError。

最初はこれが正しいと思われるかもしれませんが、属性ルックアッププロセスは少し複雑です。たとえばx.fooの場合、xがクラスまたはインスタンスの場合は同じ動作をしません。

このように説明できないサンプルがいくつか見つかりました。

class Meta(type): 
    def __getattribute__(self, name): 
     print("Metaclass getattribute invoked:", self) 
     return type.__getattribute__(self, name) 

    def __getattr__(self, item): 
     print('Metaclass getattr invoked: ', item) 
     return None 

class C(object, metaclass=Meta): 
    def __getattribute__(self, name): 
     print("Class getattribute invoked:", args) 
     return object.__getattribute__(self, name) 

c=C() 

今すぐ対応する出力で次の行をチェックします:

>> C.__new__ 
Metaclass getattribute invoked: <class '__main__.C'> 
<built-in method __new__ of type object at 0x1E1B80B0> 

>> C.__getattribute__ 
Metaclass getattribute invoked: <class '__main__.C'> 
<function __getattribute__ at 0x01457F18> 

>> C.xyz 
Metaclass getattribute invoked: <class '__main__.C'> 
Metaclass getattr invoked: xyz 
None 

>> c.__new__ 
Class getattribute invoked: (<__main__.C object at 0x013E7550>, '__new__') 
<built-in method __new__ of type object at 0x1E1B80B0> 

>> c.__getattribute__ 
Class getattribute invoked: (<__main__.C object at 0x01438DB0>, '__getattribute__') 
Metaclass getattribute invoked: <class '__main__.C'> 
<bound method C.__getattribute__ of <__main__.C object at 0x01438DB0>> 

>> 

を私は(私たちはx.fooを探している考慮して)されてきた結論:

次のPythonコードを考えてみましょう
  • __getattribute__は<タイプ 'type'>と<タイプ 'object'>のインスタンスでは異なります。 C.foo()の場合は、最初にC .__ dict__で 'foo'が検索され、見つかった場合(タイプCを検索する代わりに)検索され、x.foo()の場合、 'foo'がタイプ(x).__ dict__で検索され、 x .__ dict__で。
  • __getattribute__メソッドは常にタイプ(x)で解決されますが、ここで理解できないのは最後のケースです:c .__ getattribute__、__getattribute__メソッド(オブジェクトから継承したC)を含むオブジェクトではないので、なぜメタクラスgetattributeメソッドが呼び出されます。

誰かがこれを説明できますか?または、これについてのいくつかの文書をどこで見つけることができますか、あまり教えてください、ありがとう。

答えて

4

あなたが​​を追加した場合、あなたが見たい:

>>> c.__getattribute__ 
Class getattribute invoked: <__main__.C object at 0x2acdbb1430d0> __getattribute__ 
Metaclass getattribute invoked: <class '__main__.C'> __name__ 
<bound method C.__getattribute__ of <__main__.C object at 0x2acdbb1430d0>> 

メタクラス__getattribute__は、それがC__name__を印刷することができるように、表現c.__getattribute__reprを構築するために呼び出さなっています。

btw、__getattribute__は、クラスとメタクラスで同じように動作します。そのインスタンスの属性が最初に検索され、次にインスタンスの型が検索されます。

>>> Meta.foo = 1 
>>> C.foo 
('Metaclass getattribute invoked:', <class '__main__.C'>, 'foo') 
1 
>>> c.foo 
('Class getattribute invoked:', <__main__.C object at 0x2acdbb1430d0>, 'foo') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 5, in __getattribute__ 
AttributeError: 'C' object has no attribute 'foo' 
>>> C.bar = 2 
>>> c.bar 
('Class getattribute invoked:', <__main__.C object at 0x2acdbb1430d0>, 'bar') 
2 
+2

Pythonの種類とオブジェクトhttp://www.cafepy.com/article/python_types_and_objects/ – amirouche