25

「python 属性ルックアップ プロセス」と言うとき、つまり x.foo と書くと python は何をしますか??

Web を検索しても、これに関するドキュメントはあまり見つかりませんでした。見つかった最高の論文の 1 つは、次の手順へのプロセスを再開しました (完全な記事はこちらで参照できます) 。

  1. attrname が objectname の特別な (つまり、Python が提供する) 属性である場合、それを返します。
  2. attrname の objectname.__class__.__dict__ を確認してください。存在し、データ記述子である場合は、記述子の結果を返します。objectname.__class__ のすべてのベースで同じケースを検索します。
  3. objectname.__dict__ で attrname を確認し、見つかった場合は戻ります。objectname がクラスの場合、そのベースも検索します。それがクラスであり、記述子がそのクラスまたはそのベースに存在する場合、記述子の結果を返します。
  4. attrname の objectname.__class__.__dict__ を確認してください。存在し、非データ記述子である場合は、記述子の結果を返します。存在し、記述子ではない場合は、それを返します。それが存在し、データ記述子である場合、ポイント 2 で戻ってきたので、ここにいるべきではありません。objectname.__class__ のすべてのベースで同じケースを検索します。
  5. AttributeError を発生させます。

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

この方法では説明できないサンプルがいくつか見つかりました。次の Python コードを検討してください。

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を検索していることを考慮して):

  • __getattribute__ は、< type 'type' > と < type 'object' > のインスタンスでは異なります。C.foo() の場合、C.__dict__ で最初に 'foo' が検索され、(type(C) を検索する代わりに) 見つかった場合に返され、x.foo() の場合、type(x).__dict__ で 'foo' が検索され、 x.__dict__ で。
  • __getattribute__ メソッドは常に type(x) で解決されます。ここで理解できないのは最後のケースです: c.__getattribute__、オブジェクトにはメソッド __getattribute__ が含まれていません (そして C はオブジェクトから継承されます)。呼ばれた。

誰かがこれを説明できますか?? または、これに関するドキュメントがどこにあるのか教えてください。ありがとうございます。

4

1 に答える 1

4

追加すると、次のようにprint("Metaclass getattribute invoked:", self, name)表示されます。

>>> 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__が呼び出され、 を出力できるようになります。reprc.__getattribute__C__name__

ところで、__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
于 2012-06-26T16:19:58.583 に答える