__getattr__ と __getattribute__ の違い
-
17-09-2020 - |
質問
いつ使用するかを理解しようとしています __getattr__
または __getattribute__
. 。の ドキュメンテーション 言及 __getattribute__
新しいスタイルのクラスに適用されます。新しいスタイルの授業とは何ですか?
解決
主な違いは、 __getattr__
そして __getattribute__
それは? __getattr__
属性が通常の方法で見つからなかった場合にのみ呼び出されます。これは、欠落している属性のフォールバックを実装するのに適しており、おそらく必要な 2 つのうちの 1 つです。
__getattribute__
オブジェクトの実際の属性を確認する前に呼び出されるため、正しく実装するのが難しい場合があります。簡単に無限再帰に陥る可能性があります。
新しいスタイルのクラスの派生元 object
, 、古いスタイルのクラスは、明示的な基本クラスを持たない Python 2.x のクラスです。しかし、古いスタイルのクラスと新しいスタイルのクラスの区別は、どちらかを選択するときに重要なものではありません。 __getattr__
そして __getattribute__
.
ほぼ確実に欲しいです __getattr__
.
他のヒント
両方の簡単な例をいくつか見てみましょう __getattr__
そして __getattribute__
魔法の方法。
__getattr__
Python が呼び出します __getattr__
まだ定義されていない属性をリクエストするたびにメソッドを使用します。次の例では、私のクラスでは カウント ありません __getattr__
方法。両方にアクセスしようとするとメインになります obj1.mymin
そして obj1.mymax
属性はすべて正常に動作します。しかし、アクセスしようとすると obj1.mycurrent
属性 -- Python が与えてくれます AttributeError: 'Count' object has no attribute 'mycurrent'
class Count():
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.mycurrent) --> AttributeError: 'Count' object has no attribute 'mycurrent'
今私のクラス カウント もっている __getattr__
方法。今アクセスしようとすると obj1.mycurrent
属性 -- Python は、私が実装したものをすべて返します。 __getattr__
方法。この例では、存在しない属性を呼び出そうとすると、Python はその属性を作成し、整数値 0 に設定します。
class Count:
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
def __getattr__(self, item):
self.__dict__[item]=0
return 0
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.mycurrent1)
__getattribute__
では、見てみましょう __getattribute__
方法。あなたが持っている場合 __getattribute__
クラス内のメソッドを使用すると、Python は属性が存在するかどうかに関係なく、すべての属性に対してこのメソッドを呼び出します。では、なぜ必要なのか __getattribute__
方法?十分な理由の 1 つは、次の例に示すように、属性へのアクセスを防止して属性の安全性を高めることができるためです。
誰かが部分文字列で始まる私の属性にアクセスしようとするたびに 「カー」 Pythonはレイズします AttributeError
例外。それ以外の場合は、その属性を返します。
class Count:
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
self.current=None
def __getattribute__(self, item):
if item.startswith('cur'):
raise AttributeError
return object.__getattribute__(self,item)
# or you can use ---return super().__getattribute__(item)
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)
重要:無限再帰を避けるために __getattribute__
メソッドの実装では、必要な属性にアクセスするために常に同じ名前の基本クラス メソッドを呼び出す必要があります。例えば: object.__getattribute__(self, name)
または super().__getattribute__(item)
そしてそうではありません self.__dict__[item]
重要
クラスに両方が含まれている場合 取得属性 そして 属性の取得 それから魔法の方法 __getattribute__
が最初に呼び出されます。しかし、もし __getattribute__
上げるAttributeError
例外の場合、例外は無視され、 __getattr__
メソッドが呼び出されます。次の例を参照してください。
class Count(object):
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
self.current=None
def __getattr__(self, item):
self.__dict__[item]=0
return 0
def __getattribute__(self, item):
if item.startswith('cur'):
raise AttributeError
return object.__getattribute__(self,item)
# or you can use ---return super().__getattribute__(item)
# note this class subclass object
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)
これは、に基づいた単なる例です ネッド・バチェルダー氏の説明.
__getattr__
例:
class Foo(object):
def __getattr__(self, attr):
print "looking up", attr
value = 42
self.__dict__[attr] = value
return value
f = Foo()
print f.x
#output >>> looking up x 42
f.x = 3
print f.x
#output >>> 3
print ('__getattr__ sets a default value if undefeined OR __getattr__ to define how to handle attributes that are not found')
同じ例を使用すると、 __getattribute__
>>> が得られます RuntimeError: maximum recursion depth exceeded while calling a Python object
New-Styleクラスは、object
、または別の新しいスタイルクラスから継承します。
class SomeObject(object):
pass
class SubObject(SomeObject):
pass
.
オールドスタイルのクラスはありません:
class SomeObject:
pass
.
Python 2にのみ適用されます.Python 3では、上記のすべてが新しいスタイルのクラスを作成します。
9を参照してください.//"nofollownoreferrer"> 9。クラス (Pythonチュートリアル)、 NewClassvsClassicClass とhref="https://stackoverflowflow.com/questions/54867/what-is-the-difference-between-old-style-and-new-style-classes-in-pthon">古いスタイルの違いは何ですかそしてPythonの新しいスタイルクラス? 詳細は
New-Styleクラスは、 "オブジェクト"(直接または間接的に)サブクラス化されているものです。__new__
に加えて、一般的な低レベルの行動を持つことに加えて__init__
クラス法があります。
通常、__getattr__
を上書きしたいと思うでしょう(どちらも上書きしている場合)、それ以外の場合は、メソッド内の "self.foo"構文をサポートするのに苦労しています。
Bezley&Jones PCBを読んで、私は__getattr__
の明示的で実用的なユースケースにつまず、OPの質問の一部に答えるのに役立ちます。本から:
"__getattr__()
メソッドは属性検索用のキャッチアリのようなものです。コードが存在しない属性にアクセスしようとすると呼び出されるメソッドです。」私たちは上記の答えからこれを知っていますが、PCBレシピ8.15では、この機能は代表団デザインパターンを実装するために使用されます。オブジェクトAがオブジェクトBのすべてのオブジェクトBのメソッドをすべて再定義するのではなく、オブジェクトAのすべてのメソッドを再定義するのではなく、Object Aのすべてのメソッドを再定義するのではなく、次のように__getattr__()
メソッドを定義します。
def __getattr__(self, name):
return getattr(self._b, name)
.
ここで、_bはオブジェクトBであるオブジェクトAの属性の名前です。オブジェクトB上で定義されたメソッドがオブジェクトAで呼び出されると、参照チェーンの最後に__getattr__
メソッドが呼び出されます。別のオブジェクトに委任するためだけに定義されたメソッドのリストがないので、これはコードクリーナーを作るでしょう。
- getAttribute :インスタンスから属性を取得するために使用されます。 DOT表記またはgetAttr()組み込み関数を使用してインスタンス属性にアクセスするたびに、インスタンス属性にアクセスするたびにキャプチャします。
- getAttr :オブジェクトに属性が見つからない場合は、最後のリソースとして実行されます。デフォルト値を返すか、AttributionErrorを起動することを選択できます。
__ getAttribute __ 関数に戻る。デフォルトの実装がオーバーライドされていない場合。メソッドの実行時に次のチェックが行われます。
- MROチェーン内の任意のクラスで定義された同じ名前(属性名)の記述子があるかどうか(メソッドオブジェクト解決)
- はインスタンスの名前空間 を調べます
- その後クラス名前空間 に調べます。
- それから各ベースの名前空間などに。
- 最後に、見つからない場合、デフォルトの実装はインスタンスのフォールバック getattr ()メソッドを呼び出し、デフォルトの実装としてattributeError例外を発生させます。
これは、オブジェクトの実際の実装です.__ getAttribute__メソッド:
".. c:function :: pyObject * pyObject_genericGetAttr(PyObject * O、PyObject * name) タイプに入れることを意味する一般的な属性getter関数 オブジェクトのTP_GETATTROスロット。辞書内の記述子を探します オブジェクトのMROのクラスとオブジェクトの属性 :attr:〜オブジェクト。 dict (存在する場合)。概要:REF:記述子、 データ記述子はインスタンス属性よりも優先されますが、データは非データ ディスクリプタはしません。それ以外の場合は、:EXC:AttributionErrorが発生します。 "
私は誰もこの違いを言及していないことがわかります:
__getattribute__
にはデフォルトの実装がありますが、__getattr__
はそうではありません。
class A:
pass
a = A()
a.__getattr__ # error
a.__getattribute__ # return a method-wrapper
.
これは明確な意味を持ちます.__getattribute__
はデフォルトの実装をしているため、__getattr__
は、はっきりとPythonがユーザーに__getattr__
を実装することを奨励します。