Using property() on classmethods

后端 未结 15 775
Happy的楠姐
Happy的楠姐 2020-11-22 16:55

I have a class with two class methods (using the classmethod() function) for getting and setting what is essentially a static variable. I tried to use the property() functi

15条回答
  •  逝去的感伤
    2020-11-22 17:32

    Here's a solution which should work for both access via the class and access via an instance which uses a metaclass.

    In [1]: class ClassPropertyMeta(type):
       ...:     @property
       ...:     def prop(cls):
       ...:         return cls._prop
       ...:     def __new__(cls, name, parents, dct):
       ...:         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
       ...:         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
       ...:         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
       ...:         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
       ...:
    
    In [2]: class ClassProperty(object):
       ...:     __metaclass__ = ClassPropertyMeta
       ...:     _prop = 42
       ...:     def __getattr__(self, attr):
       ...:         raise Exception('Never gets called')
       ...:
    
    In [3]: ClassProperty.prop
    Out[3]: 42
    
    In [4]: ClassProperty.prop = 1
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
     in ()
    ----> 1 ClassProperty.prop = 1
    
    AttributeError: can't set attribute
    
    In [5]: cp = ClassProperty()
    
    In [6]: cp.prop
    Out[6]: 42
    
    In [7]: cp.prop = 1
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
     in ()
    ----> 1 cp.prop = 1
    
     in (cls, attr, val)
          6         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
          7         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
    ----> 8         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
          9         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
    
    AttributeError: can't set attribute
    

    This also works with a setter defined in the metaclass.

提交回复
热议问题