0

我想做的是声明类变量,但实际上将它们用作实例的变量。我有一个 classField和一个 class 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()

因此,当我实例化一个事物并设置属性foo时,它将被添加到实例中,而不是类中,类变量实际上永远不会被重新设置。

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

到目前为止,这是可行的,但是上面的 Field 代码相当尴尬。它也需要在类 props 中查找 Field 对象实例,否则似乎无法知道 and 中的属性 ( )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.foonew.foo返回 None:

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 回答