Callable class instances versus closures in Python
At first, like every operator overload, this seems like a nifty idea. And then, like most operator overload cases, we need to ask: why? Why is this better than a named method?
I wholeheartedly agree with this, and in the beginning I agreed
with the whole article. But then I began thinking about my usage
__call__ and something that the article advocated as a
replacement, and found that I partially disagree with it. To quote
If something really is nothing more than a function call with some extra arguments, then either a closure or a partial would be appropriate.
(By 'partial', the article means the use of
to construct a partially applied function.)
My view is that if you have to provide something that's callable,
a callable class is better than a closure because it's more
amenable to inspection. A class instance is a clear thing; you
can easily see what it is, what it's doing, and inspect the state
of instances (especially if you remember to give your class a
__repr__). You can
even easily give them (and their methods) docstrings, so that
help() provides helpful information about them.
None of this is true of closures (unless you go well out of your way) and only a bit of it is true of partially applied functions. Even if you go out of your way to provide a docstring for your closure function, the whole assemblage is basically an opaque blob. A partially applied function is somewhat better because the resulting object exposes some information, but it's still not as open and transparent as an object.
This becomes especially important if your callable thing is going to be called repeatedly and hold internal state. It's far easier to make this internal state visible, potentially modifiable, and above all debuggable if you're using an object than if you try to wrap all of this up inside a function (or a closure) that manipulates its internal variables. Python objects are designed to be transparent (at least by default), as peculiar as this sounds in general.
(After all, one of the usual stated purposes of objects is to encapsulate things away from the outside world.)
Callable classes are unquestionably more verbose than closures, partially applied functions, or even lambdas, and sometimes this is annoying. But I think you should use them for anything that is not trivial by itself, and maybe even for small things depending on how long the resulting callable entities are going to live and how far away they are going to propagate in your program. The result is likely to be more maintainable and more debuggable.
PS: This somewhat biases me toward providing things with the entire
instance and using
__call__ over providing a method on the
instance. If you're trying to debug something, it's harder to go
from a method to inspecting the instance it comes from. Providing
just a method is probably okay if the use is 'close' to the class
definition (eg, in the same file or the same module), because then
you can look back and forth easily. Providing the full instance is
what I'd do if I was passing the callable thing around to another
module or returning it as part of my public API.
Staying away from Google Chrome after six months or so
Just short of six months ago, I wrote Walking away from Google Chrome, about how I had decided to stop using Chrome and only use Firefox. Although I didn't mention it in the entry, I implicitly included Chromium in this, which was really easy because I don't even have it installed on my Linux machines.
(A version of Chromium is available in Fedora, but it seems to be slightly outdated and I was always using Chrome in large part because of Google's bundled Flash, which is not in the open source Chromium build.)
Overall, I remain convinced that this is something that's worth doing, however small the impact of it may be. Subsequent developments in the Chrome world have reinforced both the alarming nature of Chrome's dominance and that Chrome's developers are either shockingly naive or deliberately working to cripple popular adblocking and content filtering extensions (see here, here, and here). Using Firefox is a little gesture against the former, however tiny, and provides me with some insulation from the latter, which it seems rather likely that Google will ram through sooner or later.
(It is not complete insulation, since many of the crucial extensions I use are developed for both Firefox and Chrome. One way or another, their development and use on Firefox would probably be affected by any Chrome changes here, if only because their authors might wind up with fewer users and less motivation to work on their addons.)
On a practical level I've mostly not had any problems sticking to this. My habits and reflexes proved more amenable to change than I was afraid of, and I haven't really had any problems with websites that made me want to just hit them with my incognito Chrome hammer. I've deliberately run Chrome a few times to test how some things behaved in it as compared to Firefox, but that's about it for my Chrome usage over the past six months (although I did have to do some initial work to hunt down various scripts that were using Chrome as their browser for various reasons).
My only significant use of Chrome was as my 'accept everything, make things work' browser. As I mentioned in my initial entry, in several ways Firefox works clearly better for this, and I've come to be more and more appreciative of them over the past six months. Cut and paste just works, Firefox requires no song and dance to remember my passwords, and so on. At this point I would find it reasonably annoying to switch much of my use back to Chrome.