4

動的プロパティを持つクラスを作成しようとしています。2 つの読み取り専用プロパティを持つ次のクラスを考えてみましょう。

class Monster(object):
    def __init__(self,color,has_fur):
        self._color = color
        self._has_fur = has_fur

    @property
    def color(self): return self._color

    @property
    def has_fur(self): return self._has_fur

これを一般化して__init__、任意の辞書を取得し、辞書内の各項目から読み取り専用プロパティを作成できるようにします。私はこのようにすることができます:

class Monster2(object):
    def __init__(self,traits):
        self._traits = traits

        for key,value in traits.iteritems():
            setattr(self.__class__,key,property(lambda self,key=key: self._traits[key]))

ただし、これには重大な欠点があります。 の新しいインスタンスを作成するたびにMonster、実際にはMonsterクラスを変更しています。新しいインスタンスのプロパティを作成する代わりに、 のすべてのインスタンスにMonsterプロパティを効果的に追加しています。これを見るには:Monster

>>> hasattr(Monster2,"height")
False
>>> hasattr(Monster2,"has_claws")
False
>>> blue_monster = Monster2({"height":4.3,"color":"blue"})
>>> hasattr(Monster2,"height")
True
>>> hasattr(Monster2,"has_claws")
False
>>> red_monster = Monster2({"color":"red","has_claws":True})
>>> hasattr(Monster2,"height")
True
>>> hasattr(Monster2,"has_claws")
True

プロパティをクラス属性として明示的に追加したため、これはもちろん理にかなっていますsetattr(self.__class__,key,property(lambda self,key=key: self._traits[key]))。ここで必要なのは、インスタンスに追加できるプロパティです。(つまり、「インスタンス プロパティ」)。残念ながら、私が読んで試したすべてのことによると、プロパティは常にクラス属性であり、インスタンス属性ではありません。たとえば、これは機能しません。

class Monster3(object):
    def __init__(self,traits):
        self._traits = traits

        for key,value in traits.iteritems():
            self.__dict__[key] = property(lambda self,key=key: self._traits[key])

>>> green_monster = Monster3({"color":"green"})
>>> green_monster.color
<property object at 0x028FDAB0>

だから私の質問はこれです:「インスタンスプロパティ」は存在しますか? そうでない場合、その理由は何ですか?Python でプロパティがどのように使用されているかについては多くのことを見つけることができましたが、プロパティがどのように実装されているかについてはほとんど知りませんでした。「インスタンス プロパティ」が意味をなさない場合は、その理由を理解したいと思います。

4

6 に答える 6

0

必要なことを行う別の方法は、モンスター クラスを動的に作成することです。例えば

def make_monster_class(traits):
    class DynamicMonster(object):
        pass

    for key, val in traits.items():
        setattr(DynamicMonster, key, property(lambda self, val=val: val))

    return DynamicMonster()

blue_monster = make_monster_class({"height": 4.3, "color": "blue"})
red_monster = make_monster_class({"color": "red", "has_claws": True})
for check in ("height", "color", "has_claws"):
    print "blue", check, getattr(blue_monster, check, "N/A")
    print "red ", check, getattr(red_monster, check, "N/A")

出力:

blue height 4.3
red  height N/A
blue color blue
red  color red
blue has_claws N/A
red  has_claws True
于 2013-11-06T21:56:33.733 に答える