Name mangling vs qualified access to class attributes

Steve D'Aprano steve+python at pearwood.info
Wed Dec 14 09:12:10 EST 2016


On Wed, 14 Dec 2016 07:27 am, paolieri at gmail.com wrote:

> The official Python tutorial at
> 
> https://docs.python.org/3/tutorial/classes.html#private-variables
> 
> says that "name mangling is helpful for letting subclasses override
> methods without breaking intraclass method calls" and makes an interesting
> example:
> 
> class Mapping:
>     def __init__(self, iterable):
>         self.items_list = []
>         self.__update(iterable)
> 
>     def update(self, iterable):
>         for item in iterable:
>             self.items_list.append(item)
> 
>     __update = update   # private copy of original update() method
> 
> class MappingSubclass(Mapping):
> 
>     def update(self, keys, values):
>         # provides new signature for update()
>         # but does not break __init__()
>         for item in zip(keys, values):
>             self.items_list.append(item)
> 
> 
> It seems to me that, in this example, one could just have:
> 
> class Mapping:
>     def __init__(self, iterable):
>         self.items_list = []
>         Mapping.update(self, iterable)
> 
>     def update(self, iterable):
>         for item in iterable:
>             self.items_list.append(item)
> 
> and avoid copying 'Mapping.update' into 'Mapping.__update'. 

Perhaps.

But remember that copying Mapping.update in this way is very cheap: it's
only a new reference (e.g. a copy of a pointer), it doesn't have to copy
the entire function object.

The differences between:

    Mapping.update(self, iterable)

and

    self.__update(iterable)

are very subtle and (as far as I can see) only matter in some fairly hairy
situations. Thanks to name mangling, the second is equivalent to:

    self._Mapping__update(iterable)

which gives subclasses the opportunity to override it, if they dare. They
probably shouldn't, because it is a private method, but it you really,
really need to, you can.

A more exotic difference is that the first example looks directly at the
class, while the second checks for an instance attribute first, giving the
instance the opportunity to shadow _Mapping__update.

One last subtle difference: the second version will work even if you bind
another object to Mapping:

    class Mapping: ...

    instance = Mapping()  # create instance
    Mapping = None  # rebind the name to something else
    d = type(instance)(iterable)  # create a new instance

In this (admittedly exotic) situation Raymond Hettinger's code with
self.__update will continue to work perfectly, while your alternative with
Mapping.update will fail.


I don't know if Raymond has an objective reason for preferring one over the
other, or if it is just a matter of personal taste. If you have a Twitter
account, perhaps you could ask him to comment?

https://twitter.com/raymondh



-- 
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list