クラスごとではなく、インスタンスごとのレベルで定義されたプロパティを使用する

StackOverflow https://stackoverflow.com/questions/1632170

  •  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
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top