2017-07-08 8 views
1

`getattr`は` object .__ getattribute__`と `object .__ getattr__`にどのように関連していますか?

getattr(object, name[, default]) 

戻るにobjectの名前の属性の値

https://docs.python.org/3.6/library/functions.html#getattrから。名前は 文字列である必要があります。文字列がオブジェクトの属性の1つの名前である場合、 結果はその属性の値です。たとえば、 getattr(x, 'foobar')x.foobarに相当します。指定された属性に が存在しない場合は、 defaultが返されます。そうでない場合は、 AttributeErrorが生成されます。

はどのようにgetattrobject.__getattribute__にしてobject.__getattr__に関連していますか?

getattrobject.__getattribute__またはobject.__getattr__としますか?私は前者を推測するだろうか?

+2

これらのすべての「__getattr__」質問は、心配しています... –

答えて

1

getattr(foo, 'bar')(これは基本的foo.barある)__getattribute__を呼び出し、(存在する場合)が__getattr__から呼び出すことができる。

  1. AttributeError__getattribute__
  2. __getattribute__によって発生する明示的
それを呼び出します

からdocs

クラスも__getattr__()を定義する場合、後者は明示的に呼び出すか、 AttributeErrorを上げるのいずれか__getattribute__()ない限り 呼び出されません。

__getattr__を定義すると、ランダム属性アクセスで属性エラーを発生させたくない場合に役立ちます。 Mock libraryはそれの素晴らしい例です。

>>> from unittest.mock import Mock 
>>> m = Mock() 
>>> m.foo.bar.spam 
<Mock name='mock.foo.bar.spam' id='4367274280'> 

あなたが__getattr__のすべての時間を定義したり、あなたはデフォルト値を返すようにgetattr()の3引数形式を使用することができますいずれかAttributeErrorすべての時間を扱いたいしたくない場合は属性が見つからなかった場合、または使用hasattrの存在を確認してください。

>> getattr([], 'foo') 
--------------------------------------------------------------------------- 
AttributeError       Traceback (most recent call last) 
<ipython-input-60-f1834c32d3ce> in <module>() 
----> 1 getattr([], 'foo') 

AttributeError: 'list' object has no attribute 'foo' 
>>> getattr([], 'foo', 'default') 
'default' 

デモ:

class A: 
    def __getattr__(self, attr): 
     print('Inside A.__getattr__') 
     return 'eggs' 

print(A().foo) 

出力:データモデルのドキュメントがobject.__getattr__としてそれを指摘するが、それは意味しないこと

Inside A.__getattr__ 
eggs 

注意彼らはビルに存在するスズobjectタイプ。代わりに、それらは一般的なオブジェクトに存在することができます。この場合のオブジェクトは、オブジェクトの型に対してdunderメソッドを参照する型です。一般的に

+0

ありがとうございました。 '__getattr__'は' object'のメソッドですか?全てが 'object'を継承しているので、すべてにデフォルトで' __getattr__'がありますか? – Tim

+0

@Tim 'オブジェクト.__ getattr__'は存在しません(おそらく、そこに' __geattr__'がある点がないので、 'AttributeError'だけが必要です)。しかし、ユーザ定義のクラスは属性を扱うためにカスタム定義の' __getattr__'を持つことができますエラー。 '__getattr__'はPython 2の古いスタイルのクラスに存在します。 –

+0

'オブジェクト.__ getattr__'が存在します。https://docs.python.org/3/reference/datamodel.html#object.__getattr__ – Tim

5

要約回答

は、点線のルックアップが__getattribute__を呼び出します。

__getattribute__のコードで属性が見つからない場合は、__getattr__が定義されているかどうかを確認します。そうであれば、呼び出されます。そうでない場合はAttributeErrorが送出されます。

getattr()関数は、上記のメソッドを呼び出す代替方法です。たとえば、getattr(a, 'x')a.xに相当します。

getattr()の機能は、属性の名前が事前にわかっていない(変数に格納されている)ときに主に役立ちます。たとえば、k = 'x'; getattr(a, k)a.xに相当します。

類推し、それを考えるために、高レベルのポイント・オブ・ビュー

最良の方法は、__getattribute__最初に呼ばれる主要な方法であると__getattr__は、属性が欠落しているときに呼び出され、フォールバックであるということです。このようにして、辞書の角括弧検索の場合は、__getitem____missing__の関係に非常によく似ています。ここ

実証コード

が働いアウト例である:

>>> class A(object): 
    x = 10 
    def __getattribute__(self, attr): 
     print(f'Looking up {attr!r}') 
     return object.__getattribute__(self, attr) 
    def __getattr__(self, attr): 
     print(f'Invoked the fallback method for missing {attr!r}') 
     return 42 

>>> a = A() 
>>> a.x 
Looking up 'x' 
10 
>>> a.y 
Looking up 'y' 
Invoked the fallback method for missing 'y' 
42 

>>> # Equivalent calls with getattr() 
>>> getattr(a, 'x') 
Looking up 'x' 
10 
>>> getattr(a, 'y') 
Looking up 'y' 
Invoked the fallback method for missing 'y' 
42 

公式ドキュメントここ

は、ドキュメントの関連部分である:

オブジェクト.__ GETATTR __( self、name)属性ルックアップが にあり、usuの属性が見つからない場合に呼び出されます場所(すなわち、 インスタンス属性でも、selfのクラスツリーでも見つかりません)。名前 が属性名です。このメソッドは、(計算された) 属性値を返すか、AttributeError例外を発生させる必要があります。

属性が通常のメカニズムで見つかった場合、 __getattr __()は呼び出されません。これは、__getattr __()と__setattr __()の間の意図的な非対称性です。これは、効率の理由から、__getattr __()がインスタンスの他の属性にアクセスする手段を持たないためです。少なくとも インスタンス変数の場合は、 の値をインスタンス属性辞書に挿入しないで、代わりに を別のオブジェクトに挿入することで、完全な制御を偽ることができます。実際に属性アクセスを完全に制御するには、 の方法については__getattribute __()メソッドを参照してください。

オブジェクト.__ getattribute __(self、name) に無条件に呼び出され、クラスのインスタンスの属性アクセスが実装されます。クラス に__getattr __()も定義されている場合、 __getattribute __()は明示的に呼び出すか、AttributeErrorを呼び出さない限り、後者は呼び出されません。このメソッドは、(計算された)属性 の値を返すか、AttributeError例外を送出します。無限の の再帰を避けるため、その実装では、 に必要なすべての属性にアクセスするために、同じ名前の基本クラスメソッド を常に呼び出す必要があります。たとえば、オブジェクト.__ getattribute __(self、name)です。

関連する問題