我在使用Python继承时有麻烦。虽然这个概念在Java中对我来说太简单了,但到目前为止,我还无法理解Python,这至少让我感到惊讶。
我有一个原型如下:
class Shape():
def __init__(self, shape_name):
self.shape = shape_name
class Rectangle(Shape):
def __init__(self, name):
self.shape = name
在上面的代码中,我如何才能使一个抽象方法,需要实现的所有子类?
参见abc模块。基本上,你定义__metaclass__ = abc。ABCMeta,然后用@abc.abstractmethod装饰每个抽象方法。除非重写了所有抽象方法,否则不能实例化从该类派生的类。
如果您的类已经使用了元类,则从ABCMeta而不是type派生它,您可以继续使用自己的元类。
一种廉价的替代方法(也是abc模块引入之前的最佳实践)是让所有抽象方法都引发一个异常(NotImplementedError是一个很好的异常),以便从它派生的类必须重写该方法才能有用。
然而,abc解决方案更好,因为它完全避免了此类类的实例化(即,它“更快地失败”),而且还因为您可以提供每个方法的默认或基本实现,这些方法可以使用派生类中的super()函数实现。
抽象基类有很深的魔力。我时不时地使用它们实现一些东西,并为自己的聪明而感到惊讶,不久之后我发现自己完全被自己的聪明所迷惑(这可能只是个人的局限性)。
另一种方法(如果你问我,应该在python std库中)是创建一个装饰器。
def abstractmethod(method):
"""
An @abstractmethod member fn decorator.
(put this in some library somewhere for reuse).
"""
def default_abstract_method(*args, **kwargs):
raise NotImplementedError('call to abstract method '
+ repr(method))
default_abstract_method.__name__ = method.__name__
return default_abstract_method
class Shape(object):
def __init__(self, shape_name):
self.shape = shape_name
@abstractmethod
def foo(self):
print "bar"
return
class Rectangle(Shape):
# note you don't need to do the constructor twice either
pass
r = Rectangle("x")
r.foo()
我没有写装饰器。我只是突然想到有人会这么做。你可以在这里找到它:http://code.activestate.com/recipes/577666-abstract-method-decorator/好jimmy2times。请注意该页底部关于装饰器类型安全性的讨论。(如果有人愿意的话,可以用检查模块来修复)。
参见abc模块。基本上,你定义__metaclass__ = abc。ABCMeta,然后用@abc.abstractmethod装饰每个抽象方法。除非重写了所有抽象方法,否则不能实例化从该类派生的类。
如果您的类已经使用了元类,则从ABCMeta而不是type派生它,您可以继续使用自己的元类。
一种廉价的替代方法(也是abc模块引入之前的最佳实践)是让所有抽象方法都引发一个异常(NotImplementedError是一个很好的异常),以便从它派生的类必须重写该方法才能有用。
然而,abc解决方案更好,因为它完全避免了此类类的实例化(即,它“更快地失败”),而且还因为您可以提供每个方法的默认或基本实现,这些方法可以使用派生类中的super()函数实现。
沿着这些线,使用ABC
import abc
class Shape(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def method_to_implement(self, input):
"""Method documentation"""
return
还可以阅读这个很好的教程:https://pymotw.com/3/abc/
你也可以查看zope.interface,它是在python中引入ABC之前使用的。
http://pypi.python.org/pypi/zope.interface
https://zopeinterface.readthedocs.io/en/latest/README.html