Python 是当今使用最流行的编程语言之一,这有充分的理由:它是开源的,用途广泛(例如 Web 编程、商业应用程序、游戏、科学编程等等),并且它有一个充满活力和专注的社区为其提供支持。这个社区是我们拥有如此庞大、多样化的软件包范围的原因,这些软件包可在 Python 包索引 (PyPI) 中获得,以扩展和改进 Python 并解决不可避免出现的故障。
在本系列中,我们将研究七个 PyPI 库,它们可以帮助您解决常见的 Python 问题。今天,我们将研究 singledispatch,这是一个允许您追溯地向 Python 库添加方法的库。
singledispatch
想象一下,您有一个“形状”库,其中包含 Circle 类、Square 类等。
Circle 有一个半径,Square 有一个边长,而 Rectangle 有高度和宽度。我们的库已经存在;我们不想更改它。
但是,我们确实想向我们的库添加一个面积计算。如果我们不与其他人共享这个库,我们可以只添加一个 area 方法,这样我们就可以调用 shape.area() 而不必担心形状是什么。
虽然可以深入到类中并添加一个方法,但这并不是一个好主意:没有人期望他们的类会增长新的方法,并且事情可能会以奇怪的方式崩溃。
相反,functools 中的 singledispatch 函数可以来帮助我们。
@singledispatch
def get_area(shape):
raise NotImplementedError("cannot calculate area for unknown shape",
shape)
get_area 函数的“基本”实现失败。这确保了如果我们得到一个新的形状,我们将干净利落地失败,而不是返回无意义的结果。
@get_area.register(Square)
def _get_area_square(shape):
return shape.side ** 2
@get_area.register(Circle)
def _get_area_circle(shape):
return math.pi * (shape.radius ** 2)
以这种方式做事的一个好处是,如果有人编写了一个新的形状,旨在与我们的代码良好配合,他们可以自己实现 get_area。
from area_calculator import get_area
@attr.s(auto_attribs=True, frozen=True)
class Ellipse:
horizontal_axis: float
vertical_axis: float
@get_area.register(Ellipse)
def _get_area_ellipse(shape):
return math.pi * shape.horizontal_axis * shape.vertical_axis
调用 get_area 非常简单。
print(get_area(shape))
这意味着我们可以更改具有长 if isintance()/elif isinstance() 链的函数以这种方式工作,而无需更改接口。下次当您想检查 if isinstance 时,请尝试使用 singledispatch!
在本系列的下一篇文章中,我们将研究 tox,这是一个用于自动化 Python 代码测试的工具。
3 条评论