python中的abstractproperty + classmethod装饰器

Posted

技术标签:

【中文标题】python中的abstractproperty + classmethod装饰器【英文标题】:abstractproperty + classmethod decorators in python 【发布时间】: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 正在工作,但无法强制以这种方式从基类创建此成员

【问题讨论】:

【参考方案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)

【讨论】:

以上是关于python中的abstractproperty + classmethod装饰器的主要内容,如果未能解决你的问题,请参考以下文章

python abc模块

自己整理的c#语法和特性知识(c#1.0 -c#10)

自己整理的c#语法和特性知识(c#1.0 -c#10)

自己整理的c#语法和特性知识(c#1.0 -c#10)

自己整理的c#语法和特性知识(c#1.0 -c#10)

Python学习篇 Python中的元组