python中的顶层函数 python置顶窗口( 三 )


抽象方法是定义在基类中的一种方法,它没有提供任何实现,类似于Java中接口(Interface)里面的方法 。
在Python中实现抽象方法最简单地方式是:
Python
class Pizza(object):
def get_radius(self):
raise NotImplementedError
任何继承自_Pizza的类必须覆盖实现方法get_radius,否则会抛出异常 。
这种抽象方法的实现有它的弊端 , 如果你写一个类继承Pizza,但是忘记实现get_radius,异常只有在你真正使用的时候才会抛出来 。
Python
Pizza()
__main__.Pizza object at 0x7fb747353d90
Pizza().get_radius()
Traceback (most recent call last):
File "stdin", line 1, in module
File "stdin", line 3, in get_radius
NotImplementedError
还有一种方式可以让错误更早的触发,使用Python提供的abc模块,对象被初始化之后就可以抛出异常:
Python
import abc
class BasePizza(object):
__metaclass__= abc.ABCMeta
@abc.abstractmethod
def get_radius(self):
"""Method that should do something."""
使用abc后,当你尝试初始化BasePizza或者任何子类的时候立马就会得到一个TypeError,而无需等到真正调用get_radius的时候才发现异常 。
Python
BasePizza()
Traceback (most recent call last):
File "stdin", line 1, in module
TypeError: Can't instantiate abstract class BasePizza with abstract methods get_radius
混合静态方法、类方法、抽象方法
当你开始构建类和继承结构时,混合使用这些装饰器的时候到了,所以这里列出了一些技巧 。
记住,声明一个抽象的方法,不会固定方法的原型 , 这就意味着虽然你必须实现它,但是我可以用任何参数列表来实现:
Python
import abc
class BasePizza(object):
__metaclass__= abc.ABCMeta
@abc.abstractmethod
def get_ingredients(self):
"""Returns the ingredient list."""
class Calzone(BasePizza):
def get_ingredients(self, with_egg=False):
egg = Egg() if with_egg else None
return self.ingredients + egg
这样是允许的,因为Calzone满足BasePizza对象所定义的接口需求 。同样我们也可以用一个类方法或静态方法来实现:
Python
import abc
class BasePizza(object):
__metaclass__= abc.ABCMeta
@abc.abstractmethod
def get_ingredients(self):
"""Returns the ingredient list."""
class DietPizza(BasePizza):
@staticmethod
def get_ingredients():
return None
这同样是正确的,因为它遵循抽象类BasePizza设定的契约 。事实上get_ingredients方法并不需要知道返回结果是什么,结果是实现细节,不是契约条件 。
因此 , 你不能强制抽象方法的实现是一个常规方法、或者是类方法还是静态方法,也没什么可争论的 。从Python3开始(在Python2中不能如你期待的运行,见issue5867),在abstractmethod方法上面使用@staticmethod和@classmethod装饰器成为可能 。
Python
import abc
class BasePizza(object):
__metaclass__= abc.ABCMeta
ingredient = ['cheese']
@classmethod
@abc.abstractmethod
def get_ingredients(cls):
"""Returns the ingredient list."""
return cls.ingredients
别误会了,如果你认为它会强制子类作为一个类方法来实现get_ingredients那你就错了,它仅仅表示你实现的get_ingredients在BasePizza中是一个类方法 。
可以在抽象方法中做代码的实现?没错,Python与Java接口中的方法相反 , 你可以在抽象方法编写实现代码通过super()来调用它 。(译注:在Java8中 , 接口也提供的默认方法,允许在接口中写方法的实现)
Python
import abc

推荐阅读