__getattr__
いつ使用するか、またはを理解しようとしています__getattribute__
。記載されているドキュメントは__getattribute__
、新しいスタイルのクラスに適用されます。新しいスタイルのクラスとは何ですか?
8 に答える
__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'で始まる属性にアクセスしようとすると、 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)
or super().__getattribute__(item)
and notself.__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)
これは、 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
object
新しいスタイルのクラスは、、または別の新しいスタイルのクラスから継承します。
class SomeObject(object):
pass
class SubObject(SomeObject):
pass
古いスタイルのクラスはしません:
class SomeObject:
pass
これはPython2にのみ適用されます。Python3では、上記のすべてが新しいスタイルのクラスを作成します。
9.クラス(Pythonチュートリアル)、NewClassVsClassicClass、およびPythonの古いスタイルクラスと新しいスタイルクラスの違いは何ですか?を参照してください。詳細については。
新しいスタイルのクラスは、「オブジェクト」を(直接的または間接的に)サブクラス化するクラスです。それらには、__new__
クラスメソッドに加えて__init__
、やや合理的な低レベルの動作があります。
通常、オーバーライドする必要があります__getattr__
(どちらかをオーバーライドする場合)。そうしないと、メソッド内で「self.foo」構文をサポートするのに苦労します。