Abstract methods in Python
我在使用Python继承时遇到问题。虽然这个概念对我来说太简单了,但到目前为止,我在Python一直无法理解,这至少让我感到惊讶。
我有一个原型:
1 2 3 4 5 6 7 | class Shape(): def __init__(self, shape_name): self.shape = shape_name class Rectangle(Shape): def __init__(self, name): self.shape = name |
在上面的代码中,我如何才能创建一个需要为所有子类实现的抽象方法?
在介绍ABC之前,你会经常看到这一点。
1 2 3 4 5 6 7 8 | class Base(object): def go(self): raise NotImplementedError("Please Implement this method") class Specialized(Base): def go(self): print"Consider me implemented" |
沿着这些线,用ABC
1 2 3 4 5 6 7 8 9 | import abc class Shape(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def method_to_implement(self, input): """Method documentation""" return |
另请阅读本教程:http://www.doughellmann.com/pymotw/abc/
您还可以查看zope.interface,它是在python中引入abc之前使用的。
- http://pypi.python.org/pypi/zope.interface
- http://wiki.zope.org/interfaces/frontpage
参见ABC模块。基本上,在类上定义
如果您的类已经在使用一个元类,那么从
一个便宜的选择(以及引入
但是,
你不能用语言原语。正如前面提到的,abc包在python2.6和更高版本中提供了这个功能,但是没有python2.5和更低版本的选项。
python是一种激进的动态类型语言。它不指定语言原语以允许您阻止程序编译,因为对象与类型要求不匹配;这只能在运行时发现。如果您需要一个子类实现一个方法,请将其记录下来,然后盲目地调用该方法,希望它会出现在那里。
如果它在那里,太棒了,它就简单地工作了;这被称为duck-typing,并且您的对象已经像duck一样发出足够的震动来满足接口的需要。即使您正在调用这样一个方法的对象是
异常出现在
如果没有实现该方法,您将得到一个attributeError(如果它根本不存在)或一个typeError(如果有同名的东西,但它不是一个函数或它没有该签名)。这取决于你如何处理——或者称之为程序员错误,让它使程序崩溃(对于一个Python开发人员来说,"应该"是明显的,是什么导致了那里的错误——一个未设置的duck接口),或者当你发现你的对象不支持你希望它做的事情时,捕捉并处理这些异常。实际上,在很多情况下,捕捉attributeError和typeError是很重要的。
抽象基类是一种深层次的魔力。我周期性地使用它们来实现一些东西,并对自己的聪明感到惊讶,不久之后我发现自己完全被自己的聪明所迷惑(尽管这很可能只是个人的局限)。
另一种方法(如果你问我的话,应该在pythonstdlibs中)是制作一个装饰器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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/good one jimmy2times。请注意该页底部的讨论,即装饰器的类型安全性。(如果有人倾斜,可以用检查模块固定)。
您可以使用six和abc高效地为python2和python3构建一个类,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import six import abc @six.add_metaclass(abc.ABCMeta) class MyClass(object): """ documentation """ @abc.abstractmethod def initialize(self, para=None): """ documentation """ raise NotImplementedError |
这是一份关于它的awesomoe文档。
必须实现抽象基类(abc)。
检查python文档