预计阅读本页时间:-
7.6 混合使用静态方法、类方法和抽象方法
这些装饰器各有各的用处,但有时可能会需要同时使用。下面介绍一些相关的小技巧。
抽象方法的原型并非一成不变。在实际实现方法的时候,可以根据需要对方法的参数进行扩展。
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
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中定义的接口。这包括将它们作为类方法或静态方法进行实现:
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
尽管静态方法get_ingredients没有基于对象的状态返回结果,但是它仍然满足在基类BasePizza中定义的抽象接口,所以它仍然是有效的。
从Python 3开始(在Python 2中有问题,详见issue 5867,http://bugs.python.org/issue5867),可能会支持在@abstractmethod之上使用@staticmethod和@classmethod装饰器,如示例7.13所示。
示例 7.13 混合使用@classmethod和@abstractmethod
import abc
class BasePizza(object):
__metaclass__ = abc.ABCMeta
ingredients = ['cheese']
@classmethod
@abc.abstractmethod
def get_ingredients(cls):
"""Returns the ingredient list."""
return cls.ingredients
注意,像这样在BasePizza中定义get_ingredients为类方法并不会强迫其子类也将其定义为类方法。将其定义为静态方法也是一样,没有办法强迫子类将抽象方法实现为某种特定类型的方法。
但是等一下,这里我们在抽象方法中居然是有实现代码的。真的可以吗?是的,在Python中完全没问题!不同于Java,Python中可以在抽象方法中放入代码并使用super()调用它,如示例7.14所示。
示例 7.14 通过抽象方法使用super()
import abc
class BasePizza(object):
__metaclass__ = abc.ABCMeta
default_ingredients = ['cheese']
@classmethod
@abc.abstractmethod
def get_ingredients(cls):
"""Returns the default ingredient list."""
return cls.default_ingredients
class DietPizza(BasePizza):
def get_ingredients(self):
return [Egg()] + super(DietPizza, self).get_ingredients()
在这个例子中,每一个新的继承自BasePizza基类的Pizza子类都必须重写get_ingredients方法,但它可以通过基类的默认机制访问原料表。