__getattr__
または__getattribute__
をいつ使用するかを理解しようとしています。 ドキュメント は、__getattribute__
が新しいスタイルのクラスに適用されることに言及しています。新しいスタイルのクラスとは何ですか?
__getattr__
と__getattribute__
の主な違いは、__getattr__
は、属性が通常の方法で見つからなかった場合にのみ呼び出されることです。これは、欠落している属性のフォールバックを実装するのに適していますが、おそらく2つのうちの1つです。
__getattribute__
は、オブジェクトの実際の属性を見る前に呼び出されるため、正しく実装するのは難しい場合があります。あなたは非常に簡単に無限の再帰で終わることができます。
新しいスタイルのクラスはobject
から派生し、古いスタイルのクラスは、明示的な基本クラスを持たないPython 2.xのクラスです。ただし、__getattr__
と__getattribute__
を選択する場合、古いスタイルのクラスと新しいスタイルのクラスの区別は重要ではありません。
ほぼ確実に__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'で始まる私の属性にアクセスしようとするたびに、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__
メソッドでの無限再帰を回避するために、その実装は常に同じ名前で基本クラスメソッドを呼び出して、必要な属性にアクセスする必要があります。たとえば、self.__dict__[item]
ではなく、object.__getattribute__(self, name)
またはsuper().__getattribute__(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)
新しいスタイルのクラスは、object
、または別の新しいスタイルのクラスから継承します。
class SomeObject(object):
pass
class SubObject(SomeObject):
pass
古いスタイルのクラスにはありません:
class SomeObject:
pass
これはPython 2にのみ適用されます-Python 3では、上記のすべてが新しいスタイルのクラスを作成します。
9。Classes(Pythonチュートリアル)、 NewClassVsClassicClass およびPythonの古いスタイルクラスと新しいスタイルクラスの違いは何ですか?.
これは、 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
が得られます
新しいスタイルのクラスは、「オブジェクト」を(直接または間接的に)サブクラス化するクラスです。これらには、__new__
に加えて__init__
クラスメソッドがあり、より合理的な低レベルの動作があります。
通常、__getattr__
をオーバーライドする必要があります(どちらかをオーバーライドする場合)。そうしないと、メソッド内で "self.foo"構文をサポートするのが難しくなります。