Is it possible to make abstract classes in Python?
如何在Python中抽象类或方法?
我试图重新定义
1 2 3 | class F: def __new__(cls): raise Exception("Unable to create an instance of abstract class %s" %cls) |
但现在,如果我创建一个继承自
1 2 | class G(F): pass |
然后我也不能实例化
有没有更好的方法来定义抽象类?
使用
在python 3.4及更高版本中,可以从
1 2 3 4 5 6 | # Python 3.4+ from abc import ABC, abstractmethod class Abstract(ABC): @abstractmethod def foo(self): pass |
1 2 3 4 5 6 | # Python 3.0+ from abc import ABCMeta, abstractmethod class Abstract(metaclass=ABCMeta): @abstractmethod def foo(self): pass |
1 2 3 4 5 6 7 8 | # Python 2 from abc import ABCMeta, abstractmethod class Abstract: __metaclass__ = ABCMeta @abstractmethod def foo(self): pass |
无论使用哪种方法,都无法实例化具有抽象方法的抽象类,但可以实例化提供这些方法具体定义的子类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | >>> Abstract() Traceback (most recent call last): File"<stdin>", line 1, in <module> TypeError: Can't instantiate abstract class Abstract with abstract methods foo >>> class StillAbstract(Abstract): ... pass ... >>> StillAbstract() Traceback (most recent call last): File"<stdin>", line 1, in <module> TypeError: Can't instantiate abstract class StillAbstract with abstract methods foo >>> class Concrete(Abstract): ... def foo(self): ... print('Hello, World') ... >>> Concrete() <__main__.Concrete object at 0x7fc935d28898> |
当调用抽象方法时,实现这一点的老派方法(pre-pep 3119)只对抽象类中的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Abstract(object): def foo(self): raise NotImplementedError('subclasses must override foo()!') class Derived(Abstract): def foo(self): print 'Hooray!' >>> d = Derived() >>> d.foo() Hooray! >>> a = Abstract() >>> a.foo() Traceback (most recent call last): [...] |
这与使用
但是,如果您处理的是一组小的简单类,可能只使用一些抽象方法,那么这种方法比尝试浏览
这里有一个非常简单的方法,不用处理ABC模块。
在要成为抽象类的类的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class Base(): def __init__(self): if type(self) is Base: raise Exception('Base is an abstract class and cannot be instantiated directly') # Any initialization code print('In the __init__ method of the Base class') class Sub(Base): def __init__(self): print('In the __init__ method of the Sub class before calling __init__ of the Base class') super().__init__() print('In the __init__ method of the Sub class after calling __init__ of the Base class') subObj = Sub() baseObj = Base() |
运行时,它产生:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | In the `__init__` method of the Sub class before calling `__init__` of the Base class In the `__init__` method of the Base class In the `__init__` method of the Sub class after calling `__init__` of the Base class Traceback (most recent call last): File"/Users/irvkalb/Desktop/Demo files/Abstract.py", line 16, in <module> baseObj = Base() File"/Users/irvkalb/Desktop/Demo files/Abstract.py", line 4, in `__init__` raise Exception('Base is an abstract class and cannot be instantiated directly') Exception: Base is an abstract class and cannot be instantiated directly |
这表明可以实例化从基类继承的子类,但不能直接实例化该基类。
伊尔夫
以前的大多数答案都是正确的,但下面是Python3.7的答案和示例。是的,您可以创建一个抽象类和方法。有时类应该定义一个逻辑上属于某个类的方法,但该类不能指定如何实现该方法。例如,在下面的父母和婴儿班中,他们都吃东西,但每个班的实施情况都不同,因为婴儿和父母吃不同种类的食物,他们吃东西的次数也不同。因此,EAT方法子类重写abstractClass.eat。
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 | from abc import ABC, abstractmethod class AbstractClass(ABC): def __init__(self, value): self.value = value super().__init__() @abstractmethod def eat(self): pass class Parents(AbstractClass): def eat(self): return"eat solid food"+ str(self.value) +" times each day" class Babies(AbstractClass): def eat(self): return"Milk only"+ str(self.value) +" times or more each day" food = 3 mom = Parents(food) print("moms ----------") print(mom.eat()) infant = Babies(food) print("infants ----------") print(infant.eat()) |
输出:
1 2 3 4 | moms ---------- eat solid food 3 times each day infants ---------- Milk only 3 times or more each day |
这个将在python 3中工作
1 2 3 4 5 6 7 8 9 10 | from abc import ABCMeta, abstractmethod class Abstract(metaclass=ABCMeta): @abstractmethod def foo(self): pass Abstract() >>> TypeError: Can not instantiate abstract class Abstract with abstract methods foo |
是的,您可以使用abc(抽象基类)模块在python中创建抽象类。
本网站将帮助您:http://docs.python.org/2/library/abc.html
这同样有效,而且很简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class A_abstract(object): def __init__(self): # quite simple, old-school way. if self.__class__.__name__ =="A_abstract": raise NotImplementedError("You can't instantiate this abstract class. Derive it, please.") class B(A_abstract): pass b = B() # here an exception is raised: a = A_abstract() |
在代码片段中,还可以通过为子类中的
1 2 3 | def G(F): def __new__(cls): # do something here |
但这是一个黑客,我建议你不要这么做,除非你知道你在做什么。对于几乎所有的情况,我建议您使用我之前建议的
另外,当您创建一个新的(基本)类时,使它成为
只需快速添加@timgilbert的老一套答案……您可以让抽象基类的init()方法引发异常,这样就不会实例化它了,不是吗?
1 2 3 4 5 6 7 8 9 | >>> class Abstract(object): ... def __init__(self): ... raise NotImplementedError("You can't instantiate this class!") ... >>> a = Abstract() Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<stdin>", line 3, in __init__ NotImplementedError: You can't instantiate this class! |