How modules work in Python
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Wed Nov 19 06:32:46 EST 2014
Larry Hudson wrote:
> Your example may look the same (it uses the same dot syntax), but here it
> is to resolve a namespace -- a module is not an object. So yes, this is
> still a function and not a method. But we're getting rather pedantic
> here.
But not pedantic enough. Modules are, in fact, objects. All values in Python
are objects, including classes themselves! But modules are merely instances
of ModuleType:
py> import types
py> isinstance(types, types.ModuleType)
True
py> print(types)
<module 'types' from '/usr/local/lib/python3.3/types.py'>
The *simple* answer is that when you define a function inside the body of a
class, Python "magically" turns it into a method. But the *pedantic* answer
has to do with the descriptor protocol, and that is quite pedantic indeed.
A *simplified* description of the pedantic answer:
When you look up an attribute, say obj.attr, Python checks
whether the attribute has a __get__ method. If it does,
rather than return that object itself, Python returns the
result of calling __get__. Functions have a __get__ method,
and so they are descriptors. The __get__ method of functions
returns a method object.
Here's an example. Let's define a class with a function inside it, and an
instance:
py> class X(object):
... def method(self):
... return "spam"
...
py> instance = X()
If we look inside the class __dict__, we can see the original function:
py> X.__dict__['method']
<function X.method at 0xb7cc814c>
If we look at that function, we see it has a __get__ method:
py> f = X.__dict__['method']
py> f.__get__
<method-wrapper '__get__' of function object at 0xb7cc814c>
Calling that __get__ method returns a method object:
py> f.__get__(instance, X)
<bound method X.method of <__main__.X object at 0xb7bd65ec>>
which is what a normal attribute lookup does:
py> instance.method
<bound method X.method of <__main__.X object at 0xb7bd65ec>>
Now, the twist: when you store an object in the *instance* __dict__, the
descriptor protocol doesn't get invoked. So when you have a function in a
module, it is stored in the instance dictionary and looking up module.func
does not call __get__ and does not return a method, it just returns the
function.
The same thing applies to non-modules too. If you define a function inside
the body of a class, it is stored in the class __dict__, but if you store
it in the instance __dict__, it never gets converted to a method.
You can read up on descriptors here:
https://docs.python.org/3/howto/descriptor.html
--
Steven
More information about the Python-list
mailing list