クラスごとではなく、インスタンスごとのレベルで定義されたプロパティを使用する
-
06-07-2019 - |
質問
私が達成しようとしているのは次のようなものです:
class object:
def __init__(self):
WidthVariable(self)
print self.width
#Imagine I did this 60frames/1second later
print self.width
#output:
>>0
>>25
私がしたいこと(上記): WidthVariable
-クラスが作成されると、変数 width
がオブジェクト instance に追加されます。この変数は通常のプロパティのように機能しますが、この特定のケースでは読み取り専用です( fget
変数のみが設定されます)。また、 fget
は、 WidthVariable
で定義されている関数を呼び出します。この関数は、返す width
を決定します。
ただし、これを行う方法はわかりません。通常のプロパティを使用して試してみましたが、インスタンスごとではなくクラスでのみ動作することがわかりました-使用するコードは上記と可能な限り同じである必要があることに注意してください(つまり、 __ init __
WidthVariable
は、 width
変数を設定する必要があります。また、 self.width
は関数にすることはできません。 self.width()
のように呼び出すものではないため、 self.width
が必要です。 (それは私が持っているデザインの残りの部分を保持するためです)。
明確にするために、完全なコードは次のようになります。
class MyObject:
def __init__(self)
WidthVariable(self)
print self.width
class WidthVariable:
def __init__(self, object)
object.width = property(self.get_width)
def get_width(self):
value = #do_stuff
return value #The Value
#output:
>>25 #Whatever the Value was
解決
@Jonathanが言うように、記述子(プロパティを含む)はインスタンスごとではなくクラスごとであるため、異なるインスタンスごとの記述子を取得する唯一の方法は、各インスタンスが独自のクラスを個別化することです。メタプログラミングに関する限り、これは非常に浅くて簡単です;-)...:
class Individualistic(object_or_whatever_bases):
def __init__(self, whatever_args):
self.__class__ = type('GottaBeMe', (self.__class__, object), {})
# keep rocking...!-)
object
も明示的に追加します(Python 2。*
で必要なため、使用していると言います!!!)クラスnew-type。もはやレガシークラスを使用しないでください、プロパティやその他に関して正しく動作しません(そして後方互換性のために、Python 3ではレガシークラスが最終的に消滅したので、すべてのクラスはなしで新しいスタイルですオブジェクトから明示的に継承する必要があります!)。
現在、 self .__ class __.__ dict __
に配置された記述子は、この1つのインスタンスのみに影響し、他のインスタンスには影響しません。少しオーバーヘッドがあります(各 GottaBeMe
クラス、したがって各インスタンスには独自の __ dict __
などがあります)が、それほどひどいものはありません。
今、元の要求を満たすために必要なのは、変更することだけです:
class WidthVariable:
def __init__(self, object)
object.width = property(self.get_width)
(また、 object
argの名前を賢明に変更して組み込みの踏みつけを避け、常にすべてのクラスを新しいスタイルにする必要があるため、クラスを新しいスタイルにします;-)、
class WidthVariable(object):
def __init__(self, obj)
obj.__class__.width = property(self.get_width)
見ての通り、黒魔術的なものはありません!-)
他のヒント
サンプルを作成した方法がわかりません。また、「通常のプロパティ」の意味もわかりません。 「クラスで」のみ機能します。読み取り専用プロパティを作成する方法は次のとおりです。
class Foo(object):
# create read-only property "rop"
rop = property(lambda self: self._x)
def __init__(self):
self._x = 0
def tick(self):
self._x += 1
f = Foo()
print f.rop # prints 0
f.tick()
f.tick()
print f.rop # prints 2
f.rop = 4 # this will raise AtributeError
私はあなたの質問を理解したと思うし、あなたも運が悪い。
新しいスタイルのクラスの場合、暗黙的 特別なメソッドの呼び出しは 次の場合にのみ正常に動作することが保証されています ではなく、オブジェクトのタイプで定義されます オブジェクトのインスタンス辞書。
記述子(プロパティの実装に使用)は、クラスの __ dict __
に表示する必要があり、インスタンスの __ dict__には表示できません
。つまり、PythonはRubyではありません!
私は、敬godなPythonメタプログラマーからの訂正を喜んで待っていますが、私は正しいと思います。
あなたが望むものがあまり明確ではない?しかし、obj.widthをインスタンスごとにカスタマイズすることを想定しています プレーンプロパティを使用する簡単な方法を次に示します。widthプロパティは、インスタンスごとのコールバックによって返された値を返します
class MyClass(object):
def __init__(self, callback):
self.callback = callback
def get_width(self):
return self.callback()
width = property(get_width)
def w1(): return 0
def w2(): return 25
o1 = MyClass(w1)
o2 = MyClass(w2)
print o1.width
print o2.width
コールバックを渡すことができない場合、インスタンスに基づいて幅を返すWidthVariableにコールバックを割り当てることができます
class MyClass(object):
def __init__(self):
self.callback = WidthVariable(self)
def get_width(self):
return self.callback()
width = property(get_width)
class WidthVariable(object):
def __init__(self, obj):
self.obj = obj
def __call__(self):
return hash(self.obj)
o1 = MyClass()
o2 = MyClass()
print o1.width
print o2.width