[Tutor] I can't understand where python class methods come from

Ben Finney ben+python at benfinney.id.au
Sun Feb 23 23:44:42 CET 2014


voger <vogernewsletters at yahoo.gr> writes:

> I have a really hard time understanding where methods are defined in
> python classes.

Reading the rest of your message, I think you're saying that you can't
locate *which* class defines a method

> […] With python everything looks like magic.

It can seem that way. Fortunately, most of the magic needs to be
explicitly declared in the code, so it's a matter of knowing what to
look for.

In this message, I'll guide you in when you should expect magic, and
where to look for it.


> Methods and properties appearing out of nowhere and somehow easing the
> task at hand. I am not complaining for their existence but I really
> can't understand how and what is defined so I can use it.

This is a valid complaint, and certainly some libraries can get rather
too clever with the “magic behaviour”, leading to difficulty in
understanding what is happening well enough to debug problems.

> Enough ranting and let me give an example of what I mean.
>
> Let's have a look at the pygeocoder library located here:
> http://code.xster.net/pygeocoder/src/8888c863f907f8a706545fa9b27959595f45f8c5/pygeolib.py?at=default

The important part of that file is the ‘GeocoderResult’ class
definition. It defines a lot of magic behaviour.

In general, the magic often happens with “dunder”-named attributes; that
is, attributes named with a leading and traling double-underscore.

An attribute named “__foo__” is a strong indication that it will be
treated specially and be invoked by the Python interpreter, *without*
the programmer needing to invoke the attribute by name.

Here is the class definition showing just the dunder-named attributes::

class GeocoderResult(collections.Iterator):

    …

    def __init__(self, data):
        …

    def __len__(self):
        …

    def __iter__(self):
        …

    def __getitem__(self, key):
        …

    def __unicode__(self):
        …

    if sys.version_info[0] >= 3:  # Python 3
        def __str__(self):
            return self.__unicode__()

        def __next__(self):
            return self.return_next()
    else:  # Python 2
        def __str__(self):
            return self.__unicode__().encode('utf8')

        def next(self):
            return self.return_next()

    …

    def __getattr__(self, name):
        …


So already you should be on high alert: there is a large amount of
“magic” in this class! Seemlingly-simple uses of this class and its
instances will result in invocations of those custom methods, even
without seeing the names used explicitly.

> Some properties I can see them defined but some others like
> sublocality or administrative_area_level_1 I don't see them defined
> anywhere.

The specific magic happening here is that, when you access an attribute
on an object, Python will allow interception of that request by a custom
‘__getattr__’ method. As you can see, the ‘GeocoderResult’ class defines
that method for its instances, so you will need to look there for custom
behaviour when accessing attributes on instances of this class.

<URL:http://docs.python.org/3/reference/datamodel.html#object.__getattr__>

Similarly, the class defines ‘__getitem__’ to intercept ‘foo[bar]’, it
defines ‘__len__’ to intercept ‘len(foo)’, it defines ‘__iter__’ to
intercept attempts to iterate over an instance; and so on. Much magic!

Personally, I'm suspicious whether this class really needs to be so
awfully clever; it is certainly making the behaviour less intuitive, as
demonstrated in your case. It smells of a poor design.

> I hope I didn't bore you with this long text but this is really
> confusing for me and I hope someone can help me understand these
> things.

One good decision made by the Python core developers early on was a
convention of naming these special, magical-behaviour “hook” attributes
in a way that they are clearly special and signal to the reader that
Python will be using them implicitly.

So the general advice is to understand that any “dunder”-named attribute
needs to be researched, because it can be invoked *without* you
necessarily being aware of that.

Hope that helps!

-- 
 \            “Choose mnemonic identifiers. If you can't remember what |
  `\                mnemonic means, you've got a problem.” —Larry Wall |
_o__)                                                                  |
Ben Finney



More information about the Tutor mailing list