__getattr__
またはを使用するタイミングを理解しようとしています__getattribute__
。ドキュメントには言及し__getattribute__
新しいスタイルのクラスに適用されます。新しいスタイルのクラスとは何ですか?
__getattr__
またはを使用するタイミングを理解しようとしています__getattribute__
。ドキュメントには言及し__getattribute__
新しいスタイルのクラスに適用されます。新しいスタイルのクラスとは何ですか?
回答:
主な違い__getattr__
とは__getattribute__
つまり__getattr__
属性は、通常の方法で見つからなかった場合にのみ呼び出されます。これは、欠落している属性のフォールバックを実装するのに適しており、おそらく必要な2つのうちの1つです。
__getattribute__
オブジェクトの実際の属性を調べる前に呼び出されるため、正しく実装するのが難しい場合があります。あなたは非常に簡単に無限再帰に終わることができます。
から派生した新しいスタイルのクラスobject
、古いスタイルのクラスは、明示的な基本クラスのないPython 2.xのクラスです。ただし、古いスタイルのクラスと新しいスタイルのクラスの違いは、__getattr__
とを選択する際に重要ではありません__getattribute__
。
あなたはほぼ確実に欲しいです__getattr__
。
__getattribute__
アクセスごと__getattr__
に呼び出され、を__getattribute__
発生させた時間に呼び出されAttributeError
ます。すべてを1つにまとめないのはなぜですか?
__getattribute__
。
objec.__getattribute__
呼び出しますmyclass.__getattr__
。
__getattr__
と__getattribute__
マジックメソッドの簡単な例をいくつか見てみましょう。
__getattr__
Pythonは__getattr__
、まだ定義されていない属性をリクエストするたびにメソッドを呼び出し ます。次の例では、クラスCountに__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'
これで、クラスCountに__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つの正当な理由は、属性へのアクセスを防止し、属性をより安全にすることができることです。
誰かが部分文字列'cur'で始まる私の属性にアクセスしようとすると、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]
あなたのクラスが両方含まれている場合GETATTRとのgetAttribute魔法の方法を、次に __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)
__getattribute__
ませんが、確かにそうではありません。あなたの例によれば、オブジェクトの属性がそこにない場合、あなたがしているすべて__getattribute__
はAttributeError
例外を発生させているだけ__dict__
です。ただし、これはのデフォルトの実装で__getattribute__
あり、実際に__getattr__
はフォールバックメカニズムとして必要なものなので、実際には必要ありません。
current
のインスタンス上で定義されたCount
(参照__init__
)ので、単純に上げAttributeError
、それがに延期-属性はかなり何が起こっていないが存在していない場合__getattr__
のために、すべてを含め、名前「CUR」を起動current
するだけでなく、curious
、curly
...
これは、Ned Batchelderの説明に基づく例にすぎません。
__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
__getattr__()
実装では、無効な属性名を発生させることにより、有効な属性名の有限セットのみを受け入れるため、微妙でデバッグが困難な問題AttributeError
を回避できます。この例では、すべての属性名を無条件に有効として受け入れます。奇妙な(そして率直に言ってエラーが発生しやすい)の誤用です__getattr__()
。この例のように属性の作成を「完全に制御」したい場合は、__getattribute__()
代わりに必要です。
defaultdict
です。
__getattr__
に呼び出されることです。これは、の直接のサブクラスでは問題ありません。本当に気にする唯一のメソッドはとにかくインスタンスを無視する魔法のメソッドがあるためですが、より複雑な継承構造の場合は、親から何かを継承する機能を完全に削除します。object
新しいスタイルのクラスはobject
、または別の新しいスタイルのクラスから継承します。
class SomeObject(object):
pass
class SubObject(SomeObject):
pass
古いスタイルのクラスにはありません:
class SomeObject:
pass
これはPython 2にのみ適用されます-Python 3では、上記のすべてが新しいスタイルのクラスを作成します。
9.クラス(Pythonチュートリアル)、NewClassVsClassicClassおよびPythonの古いスタイルと新しいスタイルのクラスの違いは何ですか?を参照してください。詳細については。
新しいスタイルのクラスは、「オブジェクト」を(直接または間接に)サブクラス化するクラスです。これらは、__new__
クラスメソッドに加えて__init__
、より合理的な低レベルの動作を持っています。
通常、__getattr__
(どちらかをオーバーライドする場合は)オーバーライドする必要があります。そうしないと、メソッド内で「self.foo」構文をサポートするのが難しくなります。
追加情報:http : //www.devx.com/opensource/Article/31482/0/page/4
Beazley&Jones PCBを読む__getattr__
ときに、OPの質問の「いつ」の部分に答えるのに役立つ明示的かつ実用的なユースケースに遭遇しました。本から:
「この__getattr__()
メソッドは、属性ルックアップのキャッチオールのようなものです。存在しない属性にコードがアクセスしようとした場合に呼び出されるメソッドです。」これは上記の回答からわかりますが、PCBレシピ8.15では、この機能を使用して委任設計パターンを実装しています。オブジェクトAにオブジェクトBのメソッドを呼び出すためだけにオブジェクトAのすべてのオブジェクトBのメソッドを再定義するのではなく、オブジェクトAが委任する多くのメソッドを実装する属性オブジェクトBがある場合、__getattr__()
メソッドを次のように定義します。
def __getattr__(self, name):
return getattr(self._b, name)
ここで、_bはオブジェクトBであるオブジェクトAの属性の名前です。オブジェクトBで定義された__getattr__
メソッドがオブジェクトAで呼び出されると、メソッドはルックアップチェーンの最後で呼び出されます。別のオブジェクトに委譲するためだけに定義されたメソッドのリストがないので、これによりコードもきれいになります。