`staticmethod` 和 `abc.abstractmethod`:会混合吗?

问题描述 投票:0回答:5

在我的 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__'
python abstract-class static-methods python-decorators abstract-methods
5个回答
399
投票

Python 3.3 开始,可以组合

@staticmethod
@abstractmethod
,因此不再需要其他建议:

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

3.3 版以来

@abstractstaticmethod已被弃用(但在 Python 3.13 中仍然存在)。
    


41
投票
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
    

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

更新 - 另一种解释方式:

方法是静态的,它控制着它的调用方式。 抽象方法永远不会被调用。 因此,除了用于文档目的之外,抽象静态方法是一个毫无意义的概念。


6
投票
目前这在 Python 2.X 中是不可能的,它只会强制方法是抽象的或静态的,但不能同时是两者。

在 Python 3.2+ 中,添加了新的装饰器

abc.abstractclassmethod

abc.abstractstaticmethod
,以将它们的抽象和静态或抽象和类方法的强制结合起来。

参见

Python 问题 5867


1
投票

文档如下所述:

abstractmethod()

与其他方法结合使用时
描述符,它应该作为最里面的装饰器应用,...

所以,

@abstractmethod

一定是
最里面的装饰器,如下所示:

from abc import ABC, abstractmethod class Person(ABC): @classmethod @abstractmethod # The innermost decorator def test1(cls): pass @staticmethod @abstractmethod # The innermost decorator def test2(): pass @property @abstractmethod # The innermost decorator def name(self): pass @name.setter @abstractmethod # The innermost decorator def name(self, name): pass @name.deleter @abstractmethod # The innermost decorator def name(self): pass
然后,您需要在子类中重写它们,如下所示:

class Student(Person): def __init__(self, name): self._name = name @classmethod def test1(cls): # Overrides abstract class method print("Test1") @staticmethod def test2(): # Overrides abstract static method print("Test2") @property def name(self): # Overrides abstract getter return self._name @name.setter def name(self, name): # Overrides abstract setter self._name = name @name.deleter def name(self): # Overrides abstract deleter del self._name
然后,您可以实例化子类并调用它们,如下所示:

obj = Student("John") # Instantiates "Student" class obj.test1() # Class method obj.test2() # Static method print(obj.name) # Getter obj.name = "Tom" # Setter print(obj.name) # Getter del obj.name # Deleter print(hasattr(obj, "name"))
输出:

Test1 Test2 John Tom False
您可以查看

我的回答,其中解释了抽象属性

© www.soinside.com 2019 - 2024. All rights reserved.