Python abstract property() "Can' t 用抽象方法实例化抽象类 []”,但我做到了

标签 python python-3.x class oop abstract

我正在尝试在 python 3.7 中创建一个具有许多抽象 python 属性的基类。
我使用@property、@abstractmethod、@property.setter 注释尝试了一种方法(参见下面的“开始”)。这有效,但如果子类没有实现 setter,它不会引发异常。这就是对我使用@abstract 的意义所在,所以这不好。
所以我尝试使用两个@abstractmethod 方法和一个'property()' 以另一种方式(参见下面的'end'),它本身不是抽象的,而是使用这些方法。这种方法在实例化子类时会产生错误:

        # {TypeError}Can't instantiate abstract class FirstStep with abstract methods end
我显然正在实现抽象方法,所以我不明白它的含义。 'end' 属性未标记为@abstract,但如果我将其注释掉,它会运行(但我没有得到我的属性)。我还添加了测试非抽象方法“test_elapsed_time”以证明我拥有正确的类结构和抽象(它有效)。
有没有可能我在做一些愚蠢的事情,或者 property() 周围是否有一些特殊行为导致了这种情况?
class ParentTask(Task):
    def get_first_step(self):
        # {TypeError}Can't instantiate abstract class FirstStep with abstract methods end
        return FirstStep(self)


class Step(ABC):
    #     __metaclass__ = ABCMeta
    def __init__(self, task):
        self.task = task

    # First approach.  Works, but no warnings if don't implement setter in subclass
    @property
    @abstractmethod
    def start(self):
        pass

    @start.setter
    @abstractmethod
    def start(self, value):
        pass

    # Second approach.  "This method for 'end' may look slight messier, but raises errors if not implemented.
    @abstractmethod
    def get_end(self):
        pass

    @abstractmethod
    def set_end(self, value):
        pass

    end = property(get_end, set_end)

    def test_elapsed_time(self):
        return self.get_end() - self.start


class FirstStep(Step):
    @property
    def start(self):
        return self.task.start_dt

    # No warnings if this is commented out.
    @start.setter
    def start(self, value):
        self.task.start_dt = value

    def get_end(self):
        return self.task.end_dt

    def set_end(self, value):
        self.task.end_dt = value

最佳答案

我怀疑这是抽象方法和属性交互中的错误。
在您的基类中,按顺序发生以下事情:

  • 您定义了一个名为 start 的抽象方法。 .
  • 您创建一个使用 1) 中的抽象方法作为其 getter 的新属性。姓名start now 引用此属性,唯一引用现在由 Self.start.fget 持有的原始名称.
  • Python 保存对 start.setter 的临时引用, 因为名称 start即将绑定(bind)到另一个对象。
  • 创建第二个抽象方法,名为 start
  • 3) 中的引用被赋予了 4) 中的抽象方法来定义一个新属性来替换曾经绑定(bind)到名称 start 的新属性。 .该属性将 1 中的方法作为其 getter,并将 4 中的方法作为其 setter 。现在start指此属性; start.fget指1)中的方法; start.fset引用4)中的方法。

  • 此时,您有一个属性,其组件功能是抽象方法。属性本身不是抽象的,而是 property.__isabstractmethod__ 的定义标记它是因为它的所有组件方法都是抽象的。更重要的是,您在 Step.__abstractmethods__ 中有以下条目:
  • start , property
  • end , property
  • set_end , end 的 setter
  • gen_end , end 的 setter/getter

  • 注意 start 的组件函数属性丢失,因为 __abstractmethods__存储需要覆盖的事物的名称,而不是引用。使用 property和结果属性的 setter方法作为装饰器反复替换名称start指。
    现在,在您的子类中,您定义了一个名为 start 的新属性。 , 隐藏继承的属性,它没有 setter 和一个具体的方法作为它的 getter。此时,您是否为此属性提供 setter 并不重要,因为就 abc就机械而言,您已经提供了它所要求的一切:
  • 取名的具体方法start
  • 取名的具体方法get_endset_end
  • end 名称的隐含具体定义, 因为属性 end 的所有底层函数已经给出了具体的定义。
  • 关于Python abstract property() "Can' t 用抽象方法实例化抽象类 []”,但我做到了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65224767/

    相关文章:

    python - Python中的树形图可视化

    python - 根据该行中的值以及前面的几行获取 pandas 数据帧的一行

    django - 如何只允许管理员(或某些用户)编辑 Django 中的页面?

    python - 使用 Pandas GroupBy 和 value_counts 查找最常见的值

    jquery - 在我的代码中使用此 jquery 行转义 id

    python - 如何按未排序的列表对数据框进行分组?

    python - 为什么 sklearn 的 LabelEncoder 应该只用于目标变量?

    python-3.x - 不知道如何修复 popen ,"Invalid file object"错误

    c# - 在具有泛型类型的类上实现 IDisposable,其中泛型类型是一次性的

    c++ - 我如何包含具有相同包含的多个类?