如何制作班级财产?

发布于 2021-01-29 19:31:01

在python中,我可以使用@classmethod装饰器向类添加方法。是否有类似的装饰器将属性添加到类?我可以更好地表明我在说什么。

class Example(object):
   the_I = 10
   def __init__( self ):
      self.an_i = 20

   @property
   def i( self ):
      return self.an_i

   def inc_i( self ):
      self.an_i += 1

   # is this even possible?
   @classproperty
   def I( cls ):
      return cls.the_I

   @classmethod
   def inc_I( cls ):
      cls.the_I += 1

e = Example()
assert e.i == 20
e.inc_i()
assert e.i == 21

assert Example.I == 10
Example.inc_I()
assert Example.I == 11

我上面使用的语法是否可能还是需要更多的语法?

我想要类属性的原因是可以延迟加载类属性,这似乎很合理。

关注者
0
被浏览
53
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    这是我的处理方式:

    class ClassPropertyDescriptor(object):
    
        def __init__(self, fget, fset=None):
            self.fget = fget
            self.fset = fset
    
        def __get__(self, obj, klass=None):
            if klass is None:
                klass = type(obj)
            return self.fget.__get__(obj, klass)()
    
        def __set__(self, obj, value):
            if not self.fset:
                raise AttributeError("can't set attribute")
            type_ = type(obj)
            return self.fset.__get__(obj, type_)(value)
    
        def setter(self, func):
            if not isinstance(func, (classmethod, staticmethod)):
                func = classmethod(func)
            self.fset = func
            return self
    
    def classproperty(func):
        if not isinstance(func, (classmethod, staticmethod)):
            func = classmethod(func)
    
        return ClassPropertyDescriptor(func)
    
    
    class Bar(object):
    
        _bar = 1
    
        @classproperty
        def bar(cls):
            return cls._bar
    
        @bar.setter
        def bar(cls, value):
            cls._bar = value
    
    
    # test instance instantiation
    foo = Bar()
    assert foo.bar == 1
    
    baz = Bar()
    assert baz.bar == 1
    
    # test static variable
    baz.bar = 5
    assert foo.bar == 5
    
    # test setting variable on the class
    Bar.bar = 50
    assert baz.bar == 50
    assert foo.bar == 50
    

    在我们打电话时Bar.bar,设置员没有工作 ,因为我们正在打电话
    TypeOfBar.bar.__set__,而不是Bar.bar.__set__

    添加元类定义可以解决此问题:

    class ClassPropertyMetaClass(type):
        def __setattr__(self, key, value):
            if key in self.__dict__:
                obj = self.__dict__.get(key)
            if obj and type(obj) is ClassPropertyDescriptor:
                return obj.__set__(self, value)
    
            return super(ClassPropertyMetaClass, self).__setattr__(key, value)
    
    # and update class define:
    #     class Bar(object):
    #        __metaclass__ = ClassPropertyMetaClass
    #        _bar = 1
    
    # and update ClassPropertyDescriptor.__set__
    #    def __set__(self, obj, value):
    #       if not self.fset:
    #           raise AttributeError("can't set attribute")
    #       if inspect.isclass(obj):
    #           type_ = obj
    #           obj = None
    #       else:
    #           type_ = type(obj)
    #       return self.fset.__get__(obj, type_)(value)
    

    现在一切都会好起来的。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看