【问题标题】:Assertion in abstract base class?抽象基类中的断言?
【发布时间】:2019-11-03 14:54:18
【问题描述】:

基本上我想要的是要求抽象基类的子类不仅要实现某些属性或方法,而且还可以对这些属性或方法提出要求,例如数据类型或允许的值。

例如,假设我想要求具有name 并且name 以字母“a”开头的类:

from abc import ABC, abstractproperty

class Base(ABC):
     @abstractproperty
     def name(self):
         assert self.name[0] == 'a' # or similar; help needed here

class Derived1(Base):
    name = 'albert' # I want this class definition to work

class Derived2(Base):
    name = 'john' # I want this class definition to fail the 'a' assertion

我将在哪里/如何在基类中声明这一点?

【问题讨论】:

  • 谁设置了name属性?创建实例时是类用户吗?你能举例说明这些类的用法吗?
  • 名称属性在派生定义时设置。我们不提前知道我们将拥有多少 Derived 类定义,但我们提前知道它们的名称必须符合某些要求。不知道你还想知道什么
  • 这不仅是荒谬的unpythonic,而且在静态类型语言中也是一个糟糕的设计选择。如果您真的希望所有基类的属性name'a' 开头...那么就这样做。您不需要强制执行它:约定优于配置。在 Python 中,你真的不能强制执行它(考虑猴子补丁)。您可以做的另一件事是创建一个函数,将 'a' 添加到所有 names (如果他们没有)
  • 这只是一个简单检查的例子。假设我们想检查name 是否为字符串类型。或者该名称在集合{'jack', 'jill'} 中。可以是任何类型的数据完整性检查
  • 设置类属性不会定义属性。

标签: python oop python-3.6 metaprogramming abc


【解决方案1】:

使用__init_subclass__ 对类属性实施限制。

class Base:
    def __init_subclass__(cls):
        try:
            name = cls.name
        except AttributeError:
            raise ValueError("No name attribute")

        if name[0] != "a":
            raise ValueError("first letter of name is not 'a'")


class Derived1(Base):
    name = 'albert' # OK

class Derived2(Base):
    name = 'john' # Fails due to first letter 'j'

# Fails because Derived3.name is never defined
class Derived3(Base):
    pass  

【讨论】:

  • 这很酷,+1,但这感觉像是一个糟糕的设计决策的解决方法,并且可能是一些严重的矫枉过正。如果我们希望我们所有的name 属性都以'a' 开头......那么我们就这样做并完成它,很好摆脱!就像如果我们希望 name 成为一个字符串...然后将它变成一个该死的字符串并继续前进(我们这样做一直不检查类型并假设它们没问题)。我们真的需要一个构造来执行它吗? simple 运行时检查有什么问题?像这样的东西并不像 Pythonic。加上继承不适用于这种恶作剧......我离题了
  • 以“a”开头的名称是该问题的示例。定义一个基类来强制一个将由子类实现的接口并没有错。
猜你喜欢
  • 2018-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-29
  • 1970-01-01
  • 2016-02-27
  • 1970-01-01
相关资源
最近更新 更多