__init__関数で記述子クラスを宣言すると、記述子の機能が壊れるのはなぜですか?
-
05-07-2019 - |
質問
下のクラスBでは、 B()。a
に値を割り当てるたびに、クラスAの __ set __
関数が呼び出されるようにしました。代わりに、値を B()。a
に設定すると、 B()。a
がその値で上書きされます。クラスCの C()。a
への割り当ては正しく機能しますが、ユーザークラスごとにAの個別のインスタンスが必要でした。つまり、C(の1つのインスタンスで 'a' )他のすべてのインスタンスで「a」を変更します。問題を説明するために、いくつかのテストを作成しました。 test1とtest2の両方に合格するクラスを定義できますか?
class A(object):
def __set__(self, instance, value):
print "__set__ called: ", value
class B(object):
def __init__(self):
self.a = A()
class C(object):
a = A()
def test1( class_in ):
o = class_in()
o.a = "test"
if isinstance(o.a, A):
print "pass"
else:
print "fail"
def test2( class_in ):
o1, o2 = class_in(), class_in()
if o1.a is o2.a:
print "fail"
else:
print "pass"
解決
ドキュメントによると:
次のメソッドは、を含むクラスのインスタンスが メソッド(いわゆる記述子 クラス)クラス辞書に表示されます 別の新しいスタイルのクラスの 所有者クラス。例では 以下、“属性”を参照 キーが名前である属性 所有者クラスのプロパティ’
__ dict __
。 記述子は次のようにのみ実装できます 新しいスタイルのクラス自体。
したがって、インスタンスに記述子を置くことはできません。
ただし、記述子はアクセスに使用されるインスタンスへの参照を取得するため、状態を保存するためのキーとしてそれを使用するだけで、インスタンスに応じて異なる動作を実行できます。
他のヒント
次のクラスは元のテストに合格できますが、ほとんどの状況では使用しないでください。それ自体のisinstanceテストに失敗します!
class E(object):
def __new__(cls, state):
class E(object):
a = A(state)
def __init__(self, state):
self.state = state
return E(state)
#>>> isinstance(E(1), E)
#False
記述子によって管理される属性を持つオブジェクトをクラス化したいという点で、同様の問題に悩まされました。これを行うと、すべてのオブジェクトで属性が上書きされ、個々の属性ではないことに気付きました。
SOの質問を提起し、その結果の答えはこちらです:理由もなく値を変更するクラス属性
記述子について説明している適切なドキュメントリンクは次のとおりです。 http://martyalchin.com/2007/nov/24/python-descriptors-part-2-of-2/
前述のリンクの記述子の例を以下に示します。
class Numberise(object):
def __init__(self, name):
self.name = name
def __get__(self, instance, owner):
if self.name not in instance.__dict__:
raise (AttributeError, self.name)
return '%o'%(instance.__dict__[self.name])
def __set__(self, instance, value):
print ('setting value to: %d'%value)
instance.__dict__[self.name] = value