【问题标题】:abstractproperty + classmethod decorators in pythonpython中的abstractproperty + classmethod装饰器
【发布时间】:2021-03-30 12:06:54
【问题描述】:

我想强制孩子们在 python2.7 中使用类方法。 我试过这个:

import abc

class Base(object):
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractproperty
    def value(self):
        pass

    @abc.abstractproperty
    @classmethod
    def text(cls):
        pass

class Imp(Base):

   TEXT = "hi im text"
    @classmethod
    def haba(cls):
        print 'HI'
    
    @property
    def value(self):
        return 'asdasd'
    
    @classmethod
    @property
    def text(cls):
        return 'ho ho p'

print Imp.text
print Imp.TEXT

但我得到了这个输出:
ma​​in.Imp'>>
嗨,我的文字

我怎样才能正确地强制孩子实现类方法属性?
您可以看到 Imp.TEXT 正在工作,但无法强制以这种方式从基类创建此成员

【问题讨论】:

    标签: python-2.7 metaclass


    【解决方案1】:

    在重新阅读您的问题几次后,我得出结论,您希望 cl 方法的行为就像它是类的属性一样。

    首先,Python 的抽象方法/属性检查的实现仅在实例化时执行,而不是在类声明时执行。我希望你知道这一点。

    其次,Python 的描述符协议允许创建等效的“类属性”,尽管语言本身没有更高级别的支持 - 您可以创建一个类,__get__ 方法在以下情况下返回您的计算属性实例参数是 None (通常描述符将返回 'self' 以便可以从类中检索它们)。

    最后 - 有可能通过将自定义元类声明为抽象本身,然后将其声明为您的类元类,abstractproperties 将在运行时触发 - 让我们尝试一下 - :

    
    In [1]: import abc                                                                                                           
    
    In [2]: class AbsPropertyMeta(abc.ABC, type): 
       ...:     @abc.abstractproperty 
       ...:     def cl(cls): 
       ...:         return "Ho ho ho" 
       ...:                                                                                                                      
    
    In [3]: class ConcreteExample(metaclass=AbsPropertyMeta): 
       ...:     pass 
       ...:                                                                                                                      
    
    

    (请注意,我将使用 Python 3 开发答案,这应该是您在任何新项目或学习目的中应该使用的)

    因此,对于前一个示例,元类中的属性确实作为“类属性”工作,但 Python 不会强制在类主体中对其进行重新定义。

    所以,如果你真的需要这种设计,你应该为此创建一个完整的自定义元类,并完全放弃 abc.ABCMeta 机制:

    from functools import partial
    
    def abstractclassproperty(func):
        func._abstract_property = True
        return func
    
    
    class clsproperty(object):
        def __init__(self, func):
            self.func = func
    
        def __get__(self, instance, owner):
            return self.func(owner)
    
    
    class ABCAbstractClsProperty(type):
        def __new__(mcls, name, bases, namespace, **kw):
            new_cls = super(ABCAbstractClsProperty, mcls).__new__(mcls, name, bases, namespace, **kw)
            for attr_name in dir(new_cls):  # Dir retrieves attributes from all superclasses
                attr = getattr(new_cls, attr_name)
                if getattr(attr, "im_func", None):   # Python 2 specific normalization.
                    attr = attr.im_func
                if getattr(attr, '_abstract_property', False) and new_cls.__dict__.get(attr_name) is not attr:
                    raise TypeError("Can't create class {!r}: abstract property {!r} not implemented".format(name, attr_name))
            return new_cls
    
    """ # Python 3:
    
    class A(metaclass=ABCAbstractClsProperty):
        @abstractclassproperty
        def cl(cls):
            pass
    """
    class A(object):
        __metaclass__ = ABCAbstractClsProperty
        @abstractclassproperty
        def cl(cls):
            pass
    
    
    
    try:
        class B(A):
            pass
    except TypeError:
        print("Check ok")
    
    
    class C(A):
        @clsproperty
        def cl(cls):
            return "ho ho ho " + cls.__name__
    
    print(C.cl)
    

    【讨论】:

      猜你喜欢
      • 2019-08-08
      • 1970-01-01
      • 2016-03-17
      • 2012-07-30
      • 2021-08-13
      • 1970-01-01
      • 2022-01-21
      • 2020-02-27
      • 1970-01-01
      相关资源
      最近更新 更多