【问题标题】:Redefine abstract method as static method and call it from base class将抽象方法重新定义为静态方法并从基类中调用
【发布时间】:2015-01-14 14:34:48
【问题描述】:

假设我需要实现一个抽象 Python 接口,该接口将具有许多派生类(每个派生类名称相同,但编写在不同的模块中),并且在基类中我需要一个通用方法,该方法将使用特定的导入派生类'静态方法。

所以我的玩具模块看起来像这样:

abstract_class.py

 from abc import ABCMeta, abstractmethod

 from derived_class import Derived

 class Abstract:
   __metaclass__ = ABCMeta

   @abstractmethod
   def foo(self):
     pass

   def bar(self):
     Derived.foo()

derived_class.py

from abstract_class import Abstract

class Derived(Abstract):
  @staticmethod
  def foo():
    print 'Good news everyone!'

if __name__ == '__main__':
  derived_object = Derived()
  derived_object.bar()

当然,当我尝试运行 derived_class.py 时,我会收到抽象名称导入错误。

我该如何正确组织这个?

【问题讨论】:

  • 为什么不让Abstract.bar 直接打电话给self.foo
  • 我感觉你可能在XY Problem。但无论如何,你不应该使用circular imports,即使它不会带来真正的危险。另外 - 你可能想看看Python Super and Inheritance
  • @jonrsharpe 因为它会调用 Abstract.foo,它不会打印任何东西
  • 不在derived_object 中,它不会,因为selfDerived 实例,而foo@staticmethod,而不是@abstractmethod。试试看!
  • @jonrsharpe 刚试过,所以def bar(self): self.foo(),如果我从派生类调用 bar() 它不会打印任何东西

标签: python static abstract-class static-methods


【解决方案1】:

另一方面,如果您绝对需要在没有对象实例的情况下执行此操作,则可以使用 classmethods 而不是 staticmethods。

from abc import ABC, abstractmethod

class MyAbstractClass(ABC):

    @staticmethod
    @abstractmethod
    def foo(label: str):
        raise NotImplementedError()


    @classmethod
    def foo_agnostic(cls, label: str):
        """
        NOTE: Here, this method doesn't have a reference to an instance of the class.
        Instead, it only has a reference to the class itself; but that is enough
        to call the abstract static foo() method.
        """
        cls.foo(label)


class MyDerivedClass(MyAbstractClass):

    @staticmethod
    def foo(label: str):
        print(label)


if __name__ == "__main__":
    instance = MyDerivedClass()
    instance.foo("Test 1")                # Outputs "Test 1"
    instance.foo_agnostic("Test 2")       # Outputs "Test 2"
    MyDerivedClass.foo_agnostic("Test 3") # Outputs "Test 3"

【讨论】:

  • 也许@abstractmethod 应该在@staticmethod 之前?
  • 好吧,不。我会添加一个答案。
  • @mika:代码如宣传的那样工作。期待您的回答。
  • 感谢您的回复,否则我不会发现我的评论具有误导性!我的意思是我的第一条评论是“不”,即@abstractmethod 应该排在第二条。然后我忘记添加一个答案来警告了,哈哈。
  • @user26742873:啊,好的,很酷。感谢您的澄清。
【解决方案2】:

... 在基类中,我注意到有一个通用方法,它将使用 特定导入派生类的静态方法

如果我正确理解您的问题,我会说此功能是开箱即用的,但有一个小例外:不要使用静态方法;只需使用常规实例方法即可。

在基类中定义抽象方法将确保派生类包含该方法的实现。而且,开箱即用,派生类中定义的方法将在您调用 derived_object.bar() 时被调用。

【讨论】:

    猜你喜欢
    • 2012-12-03
    • 1970-01-01
    • 2012-05-24
    • 1970-01-01
    • 2011-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多