Python 是否将类变量用作实例变量?

Python 是否将类变量用作实例变量?,python,class,Python,Class,我想在这里做的是声明类变量,但实际上将它们用作实例的变量。我有一个class字段和一个class东西,如下所示: class Field(object): def __set__(self, instance, value): for key, v in vars(instance.__class__).items(): if v is self: instance.__dict__.update({key: val

我想在这里做的是声明类变量,但实际上将它们用作实例的变量。我有一个class
字段
和一个class
东西
,如下所示:

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()
new = Thing()
因此,当我实例化一个东西并设置属性foo时,它将被添加到实例中,而不是类中,类变量实际上从未被重新设置

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

到目前为止,这是可行的,但上面的字段代码相当笨拙。它还必须在类道具中查找字段对象实例,否则似乎无法知道
\uuuuuu set\uuuuu
\uuu get\uuuu
中属性的名称(
foo
)。有没有另一种更直接的方法来实现这一点?

最简单的方法是调用属性,而不是描述符变量的名称-最好从
\uu
开始,以表示它是一个实现细节。这样,您将得到:

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

def __get__(self, instance, owner):
    return getattr(instance, '_foo', None)
唯一的缺点是,您无法根据描述符使用的密钥来确定密钥的名称。如果与回路相比,增加的耦合不是问题,您可以使用:

否则,您可以将变量的名称传递到描述符的
\uuuu init\uuuu
中,以便:

class Thing:
    foo = Field('_foo')

当然,所有这些都假设最简单、最具Python风格的方法——使用一个实变量
Thing().foo
,在
Thing中设置为
None
。\uuuu init\uuu
,出于某种原因,它不是一个选项。如果这种方法对您有效,您应该更喜欢它。

最简单的方法是调用属性而不是描述符变量的名称-最好从
\uu
开始以表示其实现细节。这样,您将得到:

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

def __get__(self, instance, owner):
    return getattr(instance, '_foo', None)
唯一的缺点是,您无法根据描述符使用的密钥来确定密钥的名称。如果与回路相比,增加的耦合不是问题,您可以使用:

否则,您可以将变量的名称传递到描述符的
\uuuu init\uuuu
中,以便:

class Thing:
    foo = Field('_foo')

当然,所有这些都假设最简单、最具Python风格的方法——使用一个实变量
Thing().foo
,在
Thing中设置为
None
。\uuuu init\uuu
,出于某种原因,它不是一个选项。如果这种方法对你有效,你应该更喜欢它。

重读你的问题,意识到我错了:

要做到这一点,不需要重写默认的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

如果希望特定变量的默认值为“None”,则可以将类范围的值设置为None。也就是说,您必须为每个变量专门声明它。

重新阅读您的问题,并意识到我错了:

要做到这一点,不需要重写默认的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
如果希望特定变量的默认值为“None”,则可以将类范围的值设置为None。也就是说,您必须为每个变量专门声明它。

字段的每个实例(实际上)都有一个名称。它的名称是在
Thing
中引用它的属性名称(或键)。不必动态查找键,您可以在
Thing
中设置class属性时用名称实例化
字段
s:

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
它可以这样使用:

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()
new = Thing()
在设置
new.foo
之前,
new.foo
返回无:

print(new.foo)
# None
设置
new.foo
后,
'foo'
new
的实例属性:

new.foo = 'bar'
print(new.__dict__)
# {'foo': 'bar'}
您可以使用
Thing.foo
访问描述符(
字段
实例本身):

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

字段的每个实例(实际上)都有一个名称。它的名称是在
Thing
中引用它的属性名称(或键)。不必动态查找键,您可以在
Thing
中设置class属性时用名称实例化
字段
s:

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
它可以这样使用:

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()
new = Thing()
在设置
new.foo
之前,
new.foo
返回无:

print(new.foo)
# None
设置
new.foo
后,
'foo'
new
的实例属性:

new.foo = 'bar'
print(new.__dict__)
# {'foo': 'bar'}
您可以使用
Thing.foo
访问描述符(
字段
实例本身):

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

还不够。

这是2.7,vars()与dictOut of interest类似,它有什么可能的用途?它只返回“dict”,在某些情况下,我认为它看起来更干净。@Eelke当然,它比直接访问
\uu dict\uu要好得多。我仍然想知道你在这方面有什么用。在
\uuu init\uuuu
中只设置实例的属性有什么错?这是2.7,vars()类似于dictOut of interest,这有什么可能的用途?它只返回u dict\uuu,在某些情况下,我认为它看起来更干净。@Eelke,这比直接访问
\uu dict\uu
要好得多。我仍然想知道你在这方面有什么用。在
\uuu init\uuuu
中只设置实例的属性有什么错?@Lattyware编辑了我的答案(希望)来回答实际问题。好的,我删除了我的-1,虽然我很确定OP希望不这样做,但我不确定为什么。@Lattyware,编辑我的答案以(希望)回答实际问题。好的,我删除了我的-1,虽然我很确定OP希望这样做而不是这样做,但我不确定为什么。@Eelke:如果没有类装饰器,您将不得不编写
foo=Field('foo')
。这迫使您重复两次
foo
。我只使用了类装饰器,这样您就不必重复自己的操作。@Eelke:如果没有类装饰器,您将不得不编写
foo=Field('foo')
。这迫使您重复两次
foo
。我用了装饰课