The following post was originally published on OpenSource.com as part of a series on seven libraries that help solve common problems.
Imagine you have a "shapes" library.
We have a
Circle has a
Square has a
The library already exists:
we do not want to change it.
we do want to add an
If this was our library,
we would just add an
so that we can call
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.
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
This makes sure that if we get a new shape,
we will cleanly fail 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 else writes a new shape that is intended to play well with our
they can implement the
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
This means we can change a function that has a long
if isintance()/elif isinstance()
to work this way,
without changing the interface.
The next time you are tempted to check
Interfaces are forever
(The following talks about zope.interface interfaces, but applies equally well to Java interfaces, Go interfaces, and probably other similar constructs.)
When we write a function, we can sometimes change it in backwards-compatible ways. For example, we can loosen the type of a variable. We can restrict the type of …read more
Analyzing the Stack Overflow Survey
I am the parent of two young kids. It is easy to sink into random stuff, and not follow up on goals. Strict time management and prioritization means I get to work on open source projects, write programming books and update my blog with a decent cadence. Since a lot …read more
Publishing a Book with Sphinx
A Local LRU Cache
"It is a truth universally acknowledged, that a shared state in possession of mutability, must be in want of a bug." -- with apologies to Jane Austen
As Ms. Austen, and Henrik Eichenhardt, taught us, shared mutable state is the root of all evil.
Yet, the official documentation of functools tells …read more
Don't Make It Callable
There is a lot of code that overloads the
This is the method that
an object activates:
something(x, y, z)
something.__call__(x, y, z)
is a member of a Python-defined class.
At first, like every operator overload, this seems like a …read more
Staying Safe with Open Source
A couple of months ago, a successful attack against the Node ecosystem resulted in stealing an undisclosed amount of bitcoins from CoPay wallets.
The technical flow of the attack is well-summarized by the NPM blog post. Quick summary:
- nodemon, a popular way to run Node applications, depends on event-stream.
- The …
Checking in JSON
JSON is a useful format. It might not be ideal for hand-editing, but it does have the benefit that it can be hand-edited, and it is easy enough to manipulate programmatically.
For this reason, it is likely that at some point or another, checking in a JSON file into your …read more