0

私がやりたいのはクラス変数の宣言ですが、実際にはそれらをインスタンスの変数として使用します。私は次のようなクラスFieldとクラスを持っていThingます:

class Field(object):
    def __set__(self, instance, value):
        for key, v in vars(instance.__class__).items():
            if v is self:
                instance.__dict__.update({key: value})

    def __get__(self, instance, owner):
        for key, v in vars(instance.__class__).items():
            if v is self:
                try:
                    return instance.__dict__[key]
                except:
                    return None


class Thing(object):
    foo = Field()

したがって、Thingをインスタンス化して属性fooを設定すると、クラスではなくインスタンスに追加され、クラス変数が実際に再設定されることはありません。

new = Thing()
new.foo = 'bar'
# (foo : 'bar') is stored in new.__dict__

これはこれまでのところ機能しますが、上記のFieldのコードはかなり扱いにくいものです。クラスpropsでFieldオブジェクトインスタンスを探しすぎています。そうしないと、とのプロパティ()の名前を知る方法がないようfooです。これを達成するための別のより簡単な方法はありますか?__set____get__

4

3 に答える 3

2

あなたの質問を読み直して、私が間違っていたことに気づきました:

これを行うために、デフォルトの Python 動作をオーバーライドする必要はありません。たとえば、次のことができます。

class Thing(object):
    foo = 5

>>> r = Thing()
>>> r.foo = 10
>>> s = Thing()
>>> print Thing.foo
5
>>> print r.foo
10
>>> print s.foo
5

特定の変数のデフォルトを「なし」にしたい場合は、クラス全体の値を「なし」に設定できます。つまり、変数ごとに具体的に宣言する必要があります。

于 2012-06-17T13:01:28.460 に答える
2

Field のすべてのインスタンスには (事実上) 名前があります。その名前は、 でそれを参照する属性名 (またはキー)Thingです。キーを動的に検索する代わりに、クラス属性が設定された時点での名前で s をインスタンス化 できます。FieldThing

class Field(object):
    def __init__(self, name):
        self.name = name

    def __set__(self, instance, value):
        instance.__dict__.update({self.name: value})

    def __get__(self, instance, owner):
        if instance is None:
            return self
        try:
            return instance.__dict__[self.name]
        except KeyError:
            return None

def make_field(*args):
    def wrapper(cls):
        for arg in args:
            setattr(cls, arg, Field(arg))
        return cls
    return wrapper

@make_field('foo')
class Thing(object):
    pass

そして、次のように使用できます。

new = Thing()

new.fooが設定される前に、 new.fooNone を返します。

print(new.foo)
# None

new.fooが設定された後、'foo'は のインスタンス属性ですnew:

new.foo = 'bar'
print(new.__dict__)
# {'foo': 'bar'}

Field次のコマンドを使用して、記述子 (インスタンス自体) にアクセスできますThing.foo

print(Thing.foo)
# <__main__.Field object at 0xb76cedec>

PS。ちゃんとした理由があると思います

class Thing(object):
    foo = None

十分ではありません。

于 2012-06-17T13:14:28.303 に答える
1

最も簡単な方法は、属性を記述子変数の名前以外の名前で呼び出すことです。できれば_、実装の詳細を知らせるために始めます。そうすれば、次のようになります。

def __set__(self, instance, value):
    instance._foo = value

def __get__(self, instance, owner):
    return getattr(instance, '_foo', None)

これの唯一の欠点は、記述子に使用されているものからキーの名前を判別できないことです。結合の増加がループと比較して問題にならない場合は、プロパティを使用できます。

class Thing:
    @property
    def foo(self):
       return getattr(self, '_foo', None)

    @foo.setter
    def foo(self, value):
       self._foo = value

それ以外の場合は、変数の名前を記述子の に渡すことができるため、次の__init__ようになります。

class Thing:
    foo = Field('_foo')

もちろん、これはすべて、最も単純で最も Pythonic な方法 (Thing().foo設定した実際の変数を使用する) が何らかの理由でオプションではないNoneことを前提としています。Thing.__init__その方法がうまくいくなら、それを好むべきです。

于 2012-06-17T13:00:03.020 に答える