Python 中的抽象方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4382945/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Abstract methods in Python
提问by
I am having trouble in using inheritance with Python. While the concept seems too easy for me in Java yet up till now I have been unable to understand in Python which is surprising to me at least.
我在使用 Python 继承时遇到问题。虽然这个概念在 Java 中对我来说似乎太容易了,但到目前为止我一直无法在 Python 中理解,这至少让我感到惊讶。
I have a prototype which follow:
我有一个原型如下:
class Shape():
def __init__(self, shape_name):
self.shape = shape_name
class Rectangle(Shape):
def __init__(self, name):
self.shape = name
In the above code how can I make an abstract method that would need to be implemented for all the subclasses?
在上面的代码中,如何创建一个需要为所有子类实现的抽象方法?
采纳答案by pyfunc
Something along these lines, using ABC
沿着这些路线的东西,使用 ABC
import abc
class Shape(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def method_to_implement(self, input):
"""Method documentation"""
return
Also read this good tutorial: http://www.doughellmann.com/PyMOTW/abc/
还可以阅读这个很好的教程:http: //www.doughellmann.com/PyMOTW/abc/
You can also check out zope.interfacewhich was used prior to introduction of ABC in python.
您还可以查看在 python 中引入 ABC 之前使用的zope.interface。
回答by joaquin
回答by kindall
See the abc module. Basically, you define __metaclass__ = abc.ABCMetaon the class, then decorate each abstract method with @abc.abstractmethod. Classes derived from this class cannot then be instantiated unless all abstract methods have been overridden.
请参阅abc 模块。基本上,您__metaclass__ = abc.ABCMeta在类上定义,然后用@abc.abstractmethod. 除非所有抽象方法都已被覆盖,否则无法实例化从此类派生的类。
If your class is already using a metaclass, derive it from ABCMetarather than typeand you can continue to use your own metaclass.
如果您的类已经在使用元类,则从而ABCMeta不是派生它type,您可以继续使用您自己的元类。
A cheap alternative (and the best practice before the abcmodule was introduced) would be to have all your abstract methods just raise an exception (NotImplementedErroris a good one) so that classes derived from it would have to override that method to be useful.
一种廉价的替代方法(abc也是引入模块之前的最佳实践)是让所有抽象方法只引发一个异常(这NotImplementedError是一个很好的方法),以便从它派生的类必须覆盖该方法才能有用。
However, the abcsolution is better because it keeps such classes from being instantiated at all (i.e., it "fails faster"), and also because you can provide a default or base implementation of each method that can be reached using the super()function in derived classes.
但是,该abc解决方案更好,因为它完全防止此类类被实例化(即,它“失败得更快”),并且还因为您可以提供每个方法的默认或基本实现,这些实现可以使用super()派生类中的函数访问.
回答by Adam Norberg
You can't, with language primitives. As has been called out, the abc packageprovides this functionality in Python 2.6 and later, but there are no options for Python 2.5 and earlier. The abcpackage is not a new feature of Python; instead, it adds functionality by adding explicit "does this class say it does this?" checks, with manually-implemented consistency checks to cause an error during initialization if such declarations are made falsely.
你不能,用语言原语。如前所述,abc 包在 Python 2.6 及更高版本中提供了此功能,但 Python 2.5 及更早版本没有选项。该abc包不是 Python 的新特性;相反,它通过添加明确的“这个类说它这样做了吗?”来增加功能。检查,如果这样的声明是错误的,手动实施的一致性检查会在初始化期间导致错误。
Python is a militantly dynamically-typed language. It does not specify language primitives to allow you to prevent a program from compiling because an object does not match type requirements; this can only be discovered at run time. If you require that a subclass implement a method, document that, and then just call the method in the blind hope that it will be there.
Python 是一种激进的动态类型语言。它没有指定语言原语以允许您阻止程序因为对象与类型要求不匹配而编译;这只能在运行时发现。如果你需要一个子类实现一个方法,记录它,然后盲目地调用该方法,希望它会在那里。
If it's there, fantastic, it simply works; this is called duck typing, and your object has quacked enough like a duck to satisfy the interface. This works just fine even if selfis the object you're calling such a method on, for the purposes of mandatory overrides due to base methods that need specific implementations of features (generic functions), because selfis a convention, not anything actually special.
如果它在那里,太棒了,它就可以工作;这称为鸭子类型,并且您的对象已经像鸭子一样嘎嘎叫,以满足界面。即使self是您正在调用此类方法的对象,这也可以正常工作,出于强制覆盖的目的,由于需要特定功能(通用函数)实现的基本方法,因为这self是约定,实际上并不是什么特别的。
The exception is in __init__, because when your initializer is being called, the derived type's initializer hasn't, so it hasn't had the opportunity to staple its own methods onto the object yet.
例外是在 中__init__,因为当您的初始化程序被调用时,派生类型的初始化程序还没有,所以它还没有机会将自己的方法装订到对象上。
If the method was't implemented, you'll get an AttributeError (if it's not there at all) or a TypeError (if something by that name is there but it's not a function or it didn't have that signature). It's up to you how you handle that- either call it programmer error and let it crash the program (and it "should" be obvious to a python developer what causes that kind of error there- an unmet duck interface), or catch and handle those exceptions when you discover that your object didn't support what you wish it did. Catching AttributeError and TypeError is important in a lot of situations, actually.
如果未实现该方法,您将得到一个 AttributeError(如果它根本不存在)或一个 TypeError(如果存在具有该名称的东西但它不是函数或没有该签名)。这取决于你如何处理 - 要么称其为程序员错误并让它使程序崩溃(并且对于 Python 开发人员来说“应该”很明显是什么导致了这种错误 - 一个未满足的鸭子接口),或者捕获并处理当你发现你的对象不支持你希望它做的事情时的那些例外。实际上,在很多情况下,捕获 AttributeError 和 TypeError 都很重要。
回答by kevpie
Before abc was introduced you would see this frequently.
在引入 abc 之前,您会经常看到这种情况。
class Base(object):
def go(self):
raise NotImplementedError("Please Implement this method")
class Specialized(Base):
def go(self):
print "Consider me implemented"
回答by demented hedgehog
Abstract base classes are deep magic. Periodically I implement something using them and am amazed at my own cleverness, very shortly afterwards I find myself completely confused by my own cleverness (this may well just be a personal limitation though).
抽象基类是深奥的魔法。我会定期使用它们来实现一些东西,并对自己的聪明感到惊讶,不久之后我发现自己完全被自己的聪明所迷惑(尽管这很可能只是个人限制)。
Another way of doing this (should be in the python std libs if you ask me) is to make a decorator.
这样做的另一种方法(如果你问我应该在 python std libs 中)是制作一个装饰器。
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()
I didn't write the decorator. It just occurred to me someone would have. You can find it here: http://code.activestate.com/recipes/577666-abstract-method-decorator/Good one jimmy2times. Note the discussion at the bottom of that page r.e. type safety of the decorator. (That could be fixed with the inspect module if anyone was so inclined).
我没有写装饰器。我只是想到有人会这样做。你可以在这里找到它:http: //code.activestate.com/recipes/577666-abstract-method-decorator/ 好一个 jimmy2times。请注意该页面底部关于装饰器类型安全的讨论。(如果有人愿意,这可以通过检查模块修复)。
回答by Lerner Zhang
You can use six and abc to construct a class for both python2 and python3 efficiently as follows:
您可以使用 6 和 abc 有效地为 python2 和 python3 构造一个类,如下所示:
import six
import abc
@six.add_metaclass(abc.ABCMeta)
class MyClass(object):
"""
documentation
"""
@abc.abstractmethod
def initialize(self, para=None):
"""
documentation
"""
raise NotImplementedError

