From 7c9315501bbcd128585fc1b1c32475a68b282566 Mon Sep 17 00:00:00 2001 From: darksun Date: Sun, 5 May 2019 10:44:32 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=89=E9=A2=98:=2020190504=20Add=20methods?= =?UTF-8?q?=20retroactively=20in=20Python=20with=20singledispatch=20source?= =?UTF-8?q?s/tech/20190504=20Add=20methods=20retroactively=20in=20Python?= =?UTF-8?q?=20with=20singledispatch.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...oactively in Python with singledispatch.md | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 sources/tech/20190504 Add methods retroactively in Python with singledispatch.md diff --git a/sources/tech/20190504 Add methods retroactively in Python with singledispatch.md b/sources/tech/20190504 Add methods retroactively in Python with singledispatch.md new file mode 100644 index 0000000000..022b06aa52 --- /dev/null +++ b/sources/tech/20190504 Add methods retroactively in Python with singledispatch.md @@ -0,0 +1,106 @@ +[#]: collector: (lujun9972) +[#]: translator: ( ) +[#]: reviewer: ( ) +[#]: publisher: ( ) +[#]: url: ( ) +[#]: subject: (Add methods retroactively in Python with singledispatch) +[#]: via: (https://opensource.com/article/19/5/python-singledispatch) +[#]: author: (Moshe Zadka https://opensource.com/users/moshez) + +Add methods retroactively in Python with singledispatch +====== +Learn more about solving common Python problems in our series covering +seven PyPI libraries. +![][1] + +Python is one of the most [popular programming languages][2] in use today—and for good reasons: it's open source, it has a wide range of uses (such as web programming, business applications, games, scientific programming, and much more), and it has a vibrant and dedicated community supporting it. This community is the reason we have such a large, diverse range of software packages available in the [Python Package Index][3] (PyPI) to extend and improve Python and solve the inevitable glitches that crop up. + +In this series, we'll look at seven PyPI libraries that can help you solve common Python problems. Today, we'll examine [**singledispatch**][4], a library that allows you to add methods to Python libraries retroactively. + +### singledispatch + +Imagine you have a "shapes" library with a **Circle** class, a **Square** class, etc. + +A **Circle** has a **radius** , a **Square** has a **side** , and a **Rectangle** has **height** and **width**. Our library already exists; we do not want to change it. + +However, we do want to add an **area** calculation to our library. If we didn't share this library with anyone else, we could just add an **area** method so we could call **shape.area()** and not worry about what the shape is. + +While it is possible to reach into a class and add a method, this is a bad idea: nobody expects their class to grow new methods, and things might break in weird ways. + +Instead, the **singledispatch** function in **functools** can come to our rescue. + + +``` +@singledispatch +def get_area(shape): +raise NotImplementedError("cannot calculate area for unknown shape", +shape) +``` + +The "base" implementation for the **get_area** function fails. This makes sure that if we get a new shape, we will fail cleanly instead of returning a nonsense result. + + +``` +@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) +``` + +One nice thing about doing things this way is that if someone writes a _new_ shape that is intended to play well with our code, they can implement **get_area** themselves. + + +``` +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 +``` + +_Calling_ **get_area** is straightforward. + + +``` +`print(get_area(shape))` +``` + +This means we can change a function that has a long **if isintance()/elif isinstance()** chain to work this way, without changing the interface. The next time you are tempted to check **if isinstance** , try using **singledispatch**! + +In the next article in this series, we'll look at **tox** , a tool for automating tests on Python code. + +#### Review the previous articles in this series: + + * [Cython][5] + * [Black][6] + * [attrs][7] + + + +-------------------------------------------------------------------------------- + +via: https://opensource.com/article/19/5/python-singledispatch + +作者:[Moshe Zadka ][a] +选题:[lujun9972][b] +译者:[译者ID](https://github.com/译者ID) +校对:[校对者ID](https://github.com/校对者ID) + +本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 + +[a]: https://opensource.com/users/moshez +[b]: https://github.com/lujun9972 +[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/computer_code_programming_laptop.jpg?itok=ormv35tV +[2]: https://opensource.com/article/18/5/numbers-python-community-trends +[3]: https://pypi.org/ +[4]: https://pypi.org/project/singledispatch/ +[5]: https://opensource.com/article/19/4/7-python-problems-solved-cython +[6]: https://opensource.com/article/19/4/python-problems-solved-black +[7]: https://opensource.com/article/19/4/python-problems-solved-attrs