As mentioned in How functions become bound or unbound methods , in Python 2 when you access a function on a class (eg you do
cls.func
) it becomes an 'unbound method'. In Python 3 this is gone, as Peter Donis mentioned in a comment on that entry; if you do
cls.func
you get back the plain function. I'm not entirely sure how I feel about this, so let's start by asking a relevant question: what's the difference between an unbound method and the underlying function?
The answer is that calling an unbound method adds extra type checking on the first argument. When
cls.func
is an unbound method and you call it, the first argument must be an instance of
cls
or a subclass of it (ie, something for which
isinstance()
would return
True
). If it isn't you get a
TypeError
(much like the ones we saw back here ). Calling the function directly has no such requirement; you can feed it anything at all, even though as a class method it's probably expecting an instance of the class as its first argument.
I'll admit that it's an open argument whether this type checking is a good thing or not. It's certainly atypical for Python and the conversion from a plain function into an unbound method is a bit surprising to people. There aren't that many situations in Python where making something an attribute of a simple class magically changes it into something else; normally you expect '
A.attr =
something; A.attr
' to give you '
something
' again. The argument in defense of the checking is that it's a useful safety measure for functions that are almost certainly coded with certain assumptions and directly calling class methods on the class is not exactly a common thing.
Now that I've written this entry, I can see why Python 3 took unbound methods out. They might be handy but they're not actually essential to how things work (unlike bound methods) and Python's mechanics are mostly about what actively has to be there. I guess my view is now that I don't mind them in Python 2 but I doubt I'm going to miss them in Python 3 ( if I ever do anything with Python 3 ).