Python中的抽象方法

212 python inheritance abstract

我在使用Python继承时遇到了麻烦.虽然这个概念在Java中对我来说似乎太容易了但到目前为止我一直无法理解Python,至少对我来说这是令人惊讶的.

我有一个原型如下:

class Shape():
   def __init__(self, shape_name):
       self.shape = shape_name

class Rectangle(Shape):
   def __init__(self, name):
       self.shape = name
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,我如何制作一个需要为所有子类实现的抽象方法?

kev*_*pie 282

在介绍abc之前,你会经常看到这个.

class Base(object):
    def go(self):
        raise NotImplementedError("Please Implement this method")


class Specialized(Base):
    def go(self):
        print "Consider me implemented"
Run Code Online (Sandbox Code Playgroud)

  • 这比我认为的接受的答案更加pythonic,因为它遵循python格言"我们都是成年人" - 如果一个子类没有实现这种类型的抽象方法,它将不得不处理后果 (54认同)
  • @ EmmettJ.Butler但它没有提供任何即时反馈.它仅在使用该方法后才提供反馈,这使得该机制作为抽象类完全无用. (7认同)
  • @EmmettJ.Butler 但 abc 毕竟应该被实现。我对吗? (2认同)
  • @Spiderman不,abc不适用于简单的基类,abc是当你需要isinstance检查时,类似于isinstance(x, number)或isinstance(x, collections.abc.Sequence)。 (2认同)

pyf*_*unc 239

沿着这些方向,使用ABC

import abc

class Shape(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def method_to_implement(self, input):
        """Method documentation"""
        return
Run Code Online (Sandbox Code Playgroud)

另请阅读这篇好教程:http://www.doughellmann.com/PyMOTW/abc/

您还可以查看在python中引入ABC之前使用的zope.interface.

  • 此语法在python 3中不起作用,请参阅此问题/答案:http://stackoverflow.com/a/18513858/1240268. (5认同)
  • @user506710:代码中唯一可能需要更改的其他部分是您是否已经在使用元类。在这种情况下,只需让您的元类从“abc.ABCMeta”派生而不是从“type”派生,就可以了。如果您不知道什么是元类,请不要担心。:-) (2认同)
  • 在 python 3 中,您应该使用这个答案。/sf/answers/955238441/ (2认同)

kin*_*all 41

请参阅abc模块.基本上,您__metaclass__ = abc.ABCMeta在类上定义,然后使用装饰每个抽象方法@abc.abstractmethod.除非已覆盖所有抽象方法,否则无法实例化从此类派生的类.

如果你的类已经在使用元类,ABCMeta而不是type从而导出它,你可以继续使用自己的元类.

一个廉价的替代方案(以及abc模块引入之前的最佳实践)是让所有抽象方法只引发异常(NotImplementedError是一个很好的异常),以便从它派生的类必须覆盖该方法才有用.

但是,abc解决方案更好,因为它使这些类完全不被实例化(即,它"更快地失败"),并且还因为您可以使用super()派生类中的函数提供每个方法的默认或基本实现.


Ada*_*erg 8

你不能用语言原语.正如已经提到的那样,abc包在Python 2.6及更高版本中提供了这个功能,但是Python 2.5及更早版本没有选项.该abc包不是Python的新功能; 相反,它通过添加显式添加功能"这个类说这样做吗?" 检查,手动实现一致性检查,如果错误地进行了这样的声明,则在初始化期间导致错误.

Python是一种激进的动态类型语言.它没有指定语言原语来允许您阻止程序编译,因为对象与类型要求不匹配; 这只能在运行时发现.如果你需要一个子类实现一个方法,记录那个,然后只是盲目地调用该方法,希望它会存在.

如果它在那里,很棒,它只是有效; 这叫做鸭子打字,你的对象就像鸭子一样嘎嘎叫来满足界面.这只是正常,即使self是你调用这样的方法的对象,强制覆盖的目的,由于需要的功能(通用功能)的具体实现方法的基础,因为self一个约定,没有什么实际的特殊.

例外情况是__init__,因为在调用初始化程序时,派生类型的初始化程序没有,因此它还没有机会将自己的方法装订到对象上.

如果没有实现该方法,你将得到一个AttributeError(如果它根本不存在)或一个TypeError(如果有那个名称的东西,但它不是一个函数,或者它没有那个签名).这取决于你如何处理它 - 要么称它为程序员错误并让它崩溃程序(对于python开发人员来说它应该是显而易见的,这会导致那种错误 - 一个未满足的duck接口),或者捕获和处理当您发现您的对象不支持您希望它执行的操作时,这些异常.实际上,捕捉AttributeError和TypeError在很多情况下都很重要.

  • 对于它的价值,Python*是*强类型的,它只是动态类型. (7认同)

Ler*_*ang 6

您可以使用 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
Run Code Online (Sandbox Code Playgroud)

这是一个很棒的文档。


dem*_*hog 5

抽象基类是深刻的魔力.我经常使用它们实现一些东西,并且对自己的聪明感到惊讶,不久之后我发现自己完全被自己的聪明所迷惑(尽管这可能只是个人的限制).

另一种方法(如果你问我应该在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()
Run Code Online (Sandbox Code Playgroud)

我没有写装饰.我刚想到有人会想到的.你可以在这里找到它:http: //code.activestate.com/recipes/577666-abstract-method-decorator/好一个jimmy2times.请注意该页面底部的讨论重新定义装饰器的安全性.(如果有人这么倾向,可以通过检查模块修复).

  • 这与 [abc.abstractmethod](https://docs.python.org/3/library/abc.html#abc.abstractmethod) 有何不同? (2认同)