在类方法上使用Property()?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (22)

我有一个带有两个类方法(使用classMethod()函数)的类,用于获取和设置本质上是静态变量的内容。我试着用属性()函数来处理这些函数,但是它会导致一个错误。我能够在解释器中使用以下内容再现错误:

class Foo(object):
    _var = 5
    @classmethod
    def getvar(cls):
        return cls._var
    @classmethod
    def setvar(cls, value):
        cls._var = value
    var = property(getvar, setvar)

我可以演示类方法,但它们不作为属性工作:

>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable

可以使用带有类方法修饰函数的Property()函数吗?

提问于
用户回答回答于

属性是在类上创建的,但会影响实例。因此,如果您想要一个classMethod属性,请在元类上创建该属性。

>>> class foo(object):
    _var = 5
    class __metaclass__(type):
        pass
    @classmethod
    def getvar(cls):
        return cls._var
    @classmethod
    def setvar(cls, value):
        cls._var = value


>>> foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func)
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

但是,由于您使用的是元类,所以如果您将类方法移到其中,它会读得更好。

>>> class foo(object):
    _var = 5
    class __metaclass__(type):
        @property
        def var(cls):
            return cls._var
        @var.setter
        def var(cls, value):
            cls._var = value


>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3
用户回答回答于

我认为规定的解决方案是将ClassProperty创建为属性的子类。

class ClassProperty(property):
    def __get__(self, cls, owner):
        return self.fget.__get__(None, owner)()

class foo(object):
    _var=5
    def getvar(cls):
        return cls._var
    getvar=classmethod(getvar)
    def setvar(cls,value):
        cls._var=value
    setvar=classmethod(setvar)
    var=ClassProperty(getvar,setvar)

assert foo.getvar() == 5
foo.setvar(4)
assert foo.getvar() == 4
assert foo.var == 4
foo.var = 3
assert foo.var == 3

但是,设置者实际上不起作用:

foo.var = 4
assert foo.var == foo._var # raises AssertionError

foo._var没有改变,您只需用一个新值覆盖该属性。

您也可以使用ClassProperty作为一名装潢师:

class Foo(object):
    _var = 5

    @ClassProperty
    @classmethod
    def var(cls):
        return cls._var

    @var.setter
    @classmethod
    def var(cls, value):
        cls._var = value

assert foo.var == 5

扫码关注云+社区