【问题标题】:Proper way to implement ABC SubClass实现 ABC 子类的正确方法
【发布时间】:2018-06-15 10:37:30
【问题描述】:

我有一个接口类,它定义了对活动“使用中”类的要求:

class Portfolio(ABC):
    @abstractmethod
    def update_portfolio(self):
        raise NotImplementedError

    @abstractmethod
    def update_from_fill(self):
        raise NotImplementedError

    @abstractmethod
    def check_signal(self, signal_event):
        raise NotImplementedError

方法 update_portfolio 和 update_from_fill 都是在 99% 的必需案例中相同的方法。只有 check_signal 方法会有所不同。因此,为了避免一次又一次地编写相同的代码,我定义了一个基类,其中包含 update_portfolio 和 update_from_fill 的默认方法:

class BaseBacktestPortfolio(Portfolio):
    def __init__(self, ...):
        ...

    def update_portfolio(self, ...):
        ...

    def update_from_fill(self, ...):
        ...

最后,我有一个继承自 BacktestPortfolio 类的类,它指定了 check_signal 方法的正确实现:

class USBacktestPortfolio(BaseBacktestPortfolio):
    def check_signal(self, ...):
        ...

现在,问题是我的编辑器抱怨 BacktestPortfolio 类没有所有必需的抽象方法。当然,我可以忽略这一点,但如果我能确保无法从 BacktestPortfolio 类中实例化一个对象,那么完美的场景将是。

这可能吗?和/或有没有更正确的方法来实现这样的结构?

【问题讨论】:

  • 你试过实例化BaseBacktestPortfolio吗?它已经是一个通过继承的 ABC,应该防止实例化。

标签: python python-3.x abstract-class


【解决方案1】:

当然,我可以忽略这一点,但如果我能确保无法从 BacktestPortfolio 类中实例化一个对象,那么完美的场景将是。

您的示例中已经是这种情况:

>>> BaseBacktestPortfolio.mro()
[__main__.BaseBacktestPortfolio, __main__.Portfolio, abc.ABC, object]
>>> BaseBacktestPortfolio()
TypeError: Can't instantiate abstract class BaseBacktestPortfolio with abstract methods check_signal

由于ABCABCMeta 只是常规类型,因此它们的特性被继承。这包括他们对实例化不完整类的防范。您的BaseBacktestPortfolio 已经一个抽象类。

来自您的 IDE/linter/... 的警告专门用于警告您无法实例化 BaseBacktestPortfolio

【讨论】:

    【解决方案2】:

    您也可以将BaseBacktestPortfolio 设为抽象类。

    from abc import ABC, abstractmethod
    
    class Portfolio(ABC):
        @abstractmethod
        def update_portfolio(self):
            pass
    
        @abstractmethod
        def update_from_fill(self):
            pass
    
        @abstractmethod
        def check_signal(self, signal_event):
            pass
    
    class BaseBacktestPortfolio(Portfolio, ABC):
    
        def update_portfolio(self):
            print("updated portfolio")
    
        def update_from_fill(self):
            print("update from fill")
    
        @abstractmethod
        def check_signal(self):
            pass
    
    class USBacktestPortfolio(BaseBacktestPortfolio):
        def check_signal(self):
            print("checked signal")
    

    还要注意,抽象方法中不需要raise NotImplementedError。你可以pass。它更像 Pythonic :)

    【讨论】:

    • BaseBacktestPortfolio 已经是 ABC,因为继承自 Portfolio。将 ABC 添加为显式基数根本不会更改 mro。
    • @MisterMiyagi 是的,我想你是对的。如果没有将其明确指定为ABC,我还没有尝试过此代码。但我有一个疑问。按照这个逻辑,ABC 的子类不是 all 都是抽象的。在大多数情况下,我们不希望这样。
    • 是的,任何 ABC 子类都是抽象的,除非它实现了整个接口。这在定义接口时通常是可取的。例如MutableSet继承自Set,但另外定义了抽象方法adddiscard
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-26
    • 1970-01-01
    • 2011-12-03
    相关资源
    最近更新 更多