f



Name mangling vs qualified access to class attributes

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 =3D []
        self.__update(iterable)

    def update(self, iterable):
        for item in iterable:
            self.items_list.append(item)

    __update =3D 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 =3D []
        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'. More generally,=
 any time one needs to "let subclasses override methods without breaking in=
traclass method calls" (the goal stated in the tutorial), using qualified a=
ccess to class attributes/methods should suffice.

Am I missing something? Is 'self.__update(iterable)' in 'Mapping.__init__' =
preferable to 'Mapping.update(self, iterable)'?

I think that, instead, name mangling is helpful to avoid accidental overrid=
es of methods/attributes by the *current* class (rather than its subclasses=
). Given the way that C3 linearization works, you can't know in advance who=
 will follow your class A in B.__mro__ when B extends A. Name mangling allo=
ws you to avoid overriding methods/attributes of classes that might follow.

Any thoughts?

Best,
-- Marco
0
paolieri
12/13/2016 8:27:26 PM
comp.lang.python 77058 articles. 6 followers. Post Follow

4 Replies
607 Views

Similar Articles

[PageSpeed] 17

On 13Dec2016 12:27, paolieri@gmail.com <paolieri@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'. More generally, any time one needs to "let subclasses override methods without breaking intraclass method calls" (the goal stated in the tutorial), using qualified access to class attributes/methods should suffice.
>
>Am I missing something? Is 'self.__update(iterable)' in 'Mapping.__init__' preferable to 'Mapping.update(self, iterable)'?

IMO, mostly in that "Mapping.update" hardwires the class name, whereas 
"self.__update" will survive a class rename.

I confess I've never used name mangling in the manner shown in the example.

Hoping for more insightful comments...

Cheers,
Cameron Simpson <cs@zip.com.au>
0
Cameron
12/13/2016 9:52:23 PM
paolieri@gmail.com writes:

> 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'. More generally, any time one needs to "let subclasses override methods without breaking intraclass method calls" (the goal stated in the tutorial), using qualified access to class attributes/methods should suffice.
>
> Am I missing something? Is 'self.__update(iterable)' in 'Mapping.__init__' preferable to 'Mapping.update(self, iterable)'?
>
> I think that, instead, name mangling is helpful to avoid accidental overrides of methods/attributes by the *current* class (rather than its subclasses). Given the way that C3 linearization works, you can't know in advance who will follow your class A in B.__mro__ when B extends A. Name mangling allows you to avoid overriding methods/attributes of classes that might follow.
>
> Any thoughts?

You can do that indeed for class level attributes (such as methods);
you cannot do it for instance level attributes (e.g. holding instance specific
values).

>From my point of view, "__" name mangling is particularly interesting
for mixin classes (i.e. classes implementing a single feature
and being designed to be used in deriving classes combining the necessary
features by deriving from all features classes required).
Those classes are typically combined with other classes - with a
corresponding risk of name clashes. Therefore, the above name mangling
is helpful to reduce that risk for private attributes (whether methods
or data attributes).

0
dieter
12/14/2016 8:14:27 AM
On Wed, 14 Dec 2016 07:27 am, paolieri@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.

0
Steve
12/14/2016 2:12:10 PM
Hi all,

Thank you for the feedback. So, to recap, reasons to use name mangling
'self.__update(iterable)' rather than qualified access
'Mapping.update(self, iterable)' are:


1. Qualified access stops working when class 'Mapping' is renamed
(at compile-time) or its name is reassigned at runtime.

Honestly, I wouldn't worry about the first case: if I rename a class,
fixing qualified accesses within the class itself is just a matter of
refactoring.  Instead, when another class is assigned to the name
'Mapping' (in the scope where it was defined), qualified access breaks
at runtime, while looking up methods through 'self' still works.


2. Method lookup through 'self' allows subclasses or instances to
override mangled names.

This should be extremely rare. After all, mangled names are meant to
avoid overrides.


For me, the takeaway is that it's always better to invoke methods on
'self', rather than passing 'self' yourself. As Guido said about the
drawbacks of having methods see each other in their scopes:

"m1(self) and self.m1() [would be] equivalent.  That's evil, because
it opens up a meaningless choice between alternative (and the m1(self)
notation is inferior, because it doesn't look in base classes)."

https://mail.python.org/pipermail/python-dev/2000-November/010598.html


Best,
-- Marco
0
Marco
12/15/2016 10:36:18 AM
Reply: