`staticmethod` and `abc.abstractmethod`: Will it blend?
In my Python app I want to make a method that is both a staticmethod
and an abc.abstractmethod
. How do I do this?
I tried applying both decorators, but it doesn't work. If I do this:
import abc
class C(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
@staticmethod
def my_function(): pass
I get an exception*, and if I do this:
class C(object):
__metaclass__ = abc.ABCMeta
@staticmethod
@abc.abstractmethod
def my_function(): pass
The abstract method is not enforced.
How can I make an abstra开发者_StackOverflow中文版ct static method?
*The exception:
File "c:\Python26\Lib\abc.py", line 29, in abstractmethod
funcobj.__isabstractmethod__ = True
AttributeError: 'staticmethod' object has no attribute '__isabstractmethod__'
Starting with Python 3.3, it is possible to combine @staticmethod
and @abstractmethod
, so none of the other suggestions are necessary anymore:
@staticmethod
@abstractmethod
def my_abstract_staticmethod(...):
Further @abstractstatic
is deprecated since version 3.3.
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
This will do it:
>>> 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
You go "Eh? It just renames @abstractmethod", and this is completely correct. Because any subclass of the above will have to include the @staticmethod decorator anyway. You have no need of it here, except as documentation when reading the code. A subclass would have to look like this:
>>> class B(A):
... @staticmethod
... def themethod():
... print "Do whatevs"
To have a function that would enforce you to make this method a static method you would have to subclass ABCmeta to check for that and enforce it. That's a lot of work for no real return. (If somebody forgets the @staticmethod decorator they will get a clear error anyway, it just won't mention static methods.
So in fact this works just as well:
>>> import abc
>>>
>>> class A(object):
... __metaclass__ = abc.ABCMeta
... @abc.abstractmethod
... def themethod():
... """Subclasses must implement this as a @staticmethod"""
... pass
Update - Another way to explain it:
That a method is static controls how it is called. An abstract method is never called. And abstract static method is therefore a pretty pointless concept, except for documentation purposes.
This is currently not possible in Python 2.X, which will only enforce the method to be abstract or static, but not both.
In Python 3.2+, the new decoratorsabc.abstractclassmethod
and abc.abstractstaticmethod
were added to combine their enforcement of being abstract and static or abstract and a class method.
See Python Issue 5867
The documentation says below:
When
abstractmethod()
is applied in combination with other method descriptors, it should be applied as the innermost decorator, ...
So, @abstractmethod
must be the innermost decorator as shown below:
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
Then, you need to override them in the child class as shown below:
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
Then, you can instantiate the child class and call them as shown below:
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"))
Output:
Test1
Test2
John
Tom
False
You can see my answer which explains about abstract property.
精彩评论