Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
声明抽象类属性的最具python风格的方法_Python_Python 3.x_Abstract Class - Fatal编程技术网

声明抽象类属性的最具python风格的方法

声明抽象类属性的最具python风格的方法,python,python-3.x,abstract-class,Python,Python 3.x,Abstract Class,假设您正在编写一个抽象类,其一个或多个非抽象类方法要求具体类具有特定的类属性;e、 例如,如果可以通过匹配不同的正则表达式来构造每个具体类的实例,那么您可能希望为ABC提供以下信息: @classmethod def parse(cls, s): m = re.fullmatch(cls.PATTERN, s) if not m: raise ValueError(s) return cls(**m.groupdict()) (也许这可以通过自定义元类更

假设您正在编写一个抽象类,其一个或多个非抽象类方法要求具体类具有特定的类属性;e、 例如,如果可以通过匹配不同的正则表达式来构造每个具体类的实例,那么您可能希望为ABC提供以下信息:

@classmethod
def parse(cls, s):
    m = re.fullmatch(cls.PATTERN, s)
    if not m:
        raise ValueError(s)
    return cls(**m.groupdict())
(也许这可以通过自定义元类更好地实现,但为了示例起见,请尝试忽略这一点。)

现在,因为抽象方法和属性的重写是在实例创建时检查的,而不是在子类创建时检查的,所以尝试使用
abc.abstractmethod
来确保具体类具有
模式
属性将不起作用-但肯定应该有东西告诉任何查看代码的人“我没有忘记在ABC上定义
模式
;具体的类应该定义它们自己的类。”问题是:哪种东西是最具python风格的

  • 一堆装饰师

    @property
    @abc.abstractmethod
    def PATTERN(self):
        pass
    
    @property
    @classmethod
    @abc.abstractmethod
    def PATTERN(cls):
        pass
    
    (顺便说一句,假设Python3.4或更高版本。)这可能会让读者产生误解,因为这意味着
    PATTERN
    应该是实例属性而不是类属性

  • 装饰塔

    @property
    @abc.abstractmethod
    def PATTERN(self):
        pass
    
    @property
    @classmethod
    @abc.abstractmethod
    def PATTERN(cls):
        pass
    
    这可能会让读者感到非常困惑,因为
    @property
    @classmethod
    通常不能组合;它们只在这里一起工作(对于给定的“work”值),因为方法一旦被重写就会被忽略

  • 虚拟值

    PATTERN = ''
    
    PATTERN = None
    
    如果一个具体类无法定义自己的
    模式
    解析
    将只接受空输入。此选项并不广泛适用,因为并非所有用例都有适当的伪值

  • 导致伪值的错误

    PATTERN = ''
    
    PATTERN = None
    
    如果一个具体的类未能定义自己的
    模式
    解析
    将引发一个错误,程序员将得到他们应得的

  • 什么都不做。基本上是#4的一个更核心的变体。ABC的文档字符串中可能有注释,但ABC本身不应该有任何
    模式
    属性

  • 其他的


  • Python>=3.6版本


    (向下滚动寻找一个适用于Python的版本我已经搜索了很长一段时间了,直到昨天我才决定深入研究它。我喜欢很多,但是缺少两件事:允许一个抽象类有一个子类本身是抽象的,并且很好地使用类型提示和静态类型工具,例如(这是有道理的,因为早在2017年,这几乎不是一件事)

    我开始着手用我自己的解决方案在这里写一个回复,但是我意识到我需要大量的测试和文档,所以我把它做成了一个合适的python模块:

    使用(自版本0.9.5起):

    类解析器(acp.Abstract): 模式:str=acp.abstract\u class\u属性(str) @类方法 def解析(cls,s): m=重新完全匹配(cls模式,s) 如果不是m: 提升值错误 返回cls(**m.groupdict()) 类FooBarParser(解析器): 模式=r“foo\s+bar” 定义初始化(…):。。。 类SpamParser(解析器): 图案=r“(垃圾邮件)+鸡蛋” 定义初始化(…):。。。
    请参阅以了解or的充分使用。

    Python是否主观?我已经了解到元类有助于增强使用它的对象的外观。@wwii是的,它们也可以用于此目的,但在本例中,这不仅仅是外观。与抽象基类一样,元类也可以增强特定类的属性但是E是在定义时定义的,不仅仅是外观或感觉…这正是我所说的外观和感觉-我应该更精确。THNX因为
    NotImplemented
    是一个单例,通常与
    is
    class RequirePatternMeta(type):
        """Metaclass that enforces child classes define PATTERN."""
    
        def __init__(cls, name, bases, attrs):
            # Skip the check if there are no parent classes,
            # which allows base classes to not define PATTERN.
            if not bases:
                return
            if attrs.get('PATTERN', NotImplemented) is NotImplemented:
                # Choose your favorite exception.
                raise NotImplementedError('You forgot to define PATTERN!!!')
    
    class PatternDefiningBase(metaclass=RequirePatternMeta):
        # Dear programmer: implement this in a subclass OR YOU'LL BE SORRY!
        PATTERN = NotImplemented
    
        @classmethod
        def sample(cls):
            print(cls.PATTERN)
    
    class LegalPatternChild(PatternDefiningBase):
        PATTERN = r'foo\s+bar'
    
    class IllegalPatternChild(PatternDefiningBase):
        pass
    
    from abs import ABCMeta, abstractmethod
    
    ABCRequirePatternMeta = type('ABCRequirePatternMeta', (ABCMeta, RequirePatternMeta), {})
    
    class PatternDefiningBase(metaclass=ABCRequirePatternMeta):
        # Dear programmer: implement this in a subclass OR YOU'LL BE SORRY!
        PATTERN = NotImplemented
    
        @classmethod
        def sample(cls):
            print(cls.PATTERN)
    
        @abstractmethod
        def abstract(self):
            return 6
    
    class LegalPatternChild(PatternDefiningBase):
        PATTERN = r'foo\s+bar'
    
        def abstract(self):
            return 5
    
    class IllegalPatternChild1(PatternDefiningBase):
        PATTERN = r'foo\s+bar'
    
    print(LegalPatternChild().abstract())
    print(IllegalPatternChild1().abstract())
    
    class IllegalPatternChild2(PatternDefiningBase):
        pass
    
    5
    TypeError: Can't instantiate abstract class IllegalPatternChild1 with abstract methods abstract
    # Then the NotImplementedError if it kept on going.