`staticmethod` 和 `abc.abstractmethod`: 能否结合?

189 投票
5 回答
69250 浏览
提问于 2025-04-16 08:41

在我的Python应用中,我想创建一个既是 staticmethod 又是 abc.abstractmethod 的方法。我该怎么做呢?

我尝试同时使用这两个装饰器,但没有成功。如果我这样做:

import abc

class C(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    @staticmethod    
    def my_function(): pass

我会遇到一个异常*,如果我这样做:

class C(object):
    __metaclass__ = abc.ABCMeta

    @staticmethod    
    @abc.abstractmethod
    def my_function(): pass

那么抽象方法就没有被强制执行。

我该如何创建一个抽象的静态方法呢?

*异常信息:

File "c:\Python26\Lib\abc.py", line 29, in abstractmethod
 funcobj.__isabstractmethod__ = True
AttributeError: 'staticmethod' object has no attribute '__isabstractmethod__'

5 个回答

16

这样做就可以了:

  >>> import abc
  >>> abstractstaticmethod = abc.abstractmethod
  >>>
  >>> class A(object):
  ...     __metaclass__ = abc.ABCMeta
  ...     @abstractstaticmethod
  ...     def themethod():
  ...          pass
  ... 
  >>> a = A()
  >>> Traceback (most recent call last):
  File "asm.py", line 16, in <module>
    a = A()
  TypeError: Can't instantiate abstract class A with abstract methods test

你可能会想:“这不就是把@abstractmethod重命名了吗?”这完全正确。因为上面的任何子类都必须包含@staticmethod这个装饰器。你在这里并不需要它,除了在阅读代码时作为文档说明。子类的写法应该像这样:

  >>> class B(A):
  ...     @staticmethod
  ...     def themethod():
  ...         print "Do whatevs"

如果你想要一个函数来强制你把这个方法写成静态方法,你就得去修改ABCmeta来检查并强制执行。这会花费很多精力,但其实没有什么实际的好处。(如果有人忘记加@staticmethod装饰器,他们会收到一个明确的错误提示,只是不会提到静态方法。)

所以实际上,这样做也一样有效:

  >>> import abc
  >>>
  >>> class A(object):
  ...     __metaclass__ = abc.ABCMeta
  ...     @abc.abstractmethod
  ...     def themethod():
  ...         """Subclasses must implement this as a @staticmethod"""
  ...          pass

更新 - 另一种解释方式:

一个方法是静态的,这决定了它是如何被调用的。抽象方法是永远不会被调用的。因此,抽象静态方法其实是个没什么意义的概念,除了作为文档说明。

41

在编程中,有时候我们会遇到一些问题,比如代码运行不正常或者出现错误。这种时候,我们可以去一些技术论坛,比如StackOverflow,去寻找解决办法。在这些论坛上,很多人会分享他们的经验和解决方案,帮助其他人解决类似的问题。

当你在这些论坛上提问时,记得把你的问题描述清楚,包括你遇到的错误信息和你已经尝试过的解决办法。这样,其他人才能更好地理解你的问题,并给出有效的建议。

同时,也要注意查看别人提问的方式,学习如何更好地表达自己的问题,这样能提高你获得帮助的机会。

class abstractstatic(staticmethod):
    __slots__ = ()
    def __init__(self, function):
        super(abstractstatic, self).__init__(function)
        function.__isabstractmethod__ = True
    __isabstractmethod__ = True

class A(object):
    __metaclass__ = abc.ABCMeta
    @abstractstatic
    def test():
        print 5
386

Python 3.3开始,可以把@staticmethod@abstractmethod结合使用,所以之前提到的其他建议就不需要了:

@staticmethod
@abstractmethod
def my_abstract_staticmethod(...):

另外,@abstractstatic3.3版本开始就不再推荐使用了。

撰写回答