4
class ParentClass(object):
    def __init__(self):
        self.__x = 1
        self.y = 10
    def PRINT(self):
        print (self.__x, self.y)

class ChildClass(ParentClass):
    def __init__(self):
        super(ChildClass, self).__init__()
        self.__x = 2
        self.y = 20


c = ChildClass()
c.PRINT()

Why is the output (1, 20)? I know how I got 20, but shouldn't it be 2 instead of 1?

3 Answers 3

3

Just to expand slightly on poke's answer...

From the official Python tutorial

Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.

So if we add this line to the end of your code:

print c._ChildClass__x, c._ParentClass__x,

it will print

(1, 20)
2 1
Sign up to request clarification or add additional context in comments.

Comments

2

Members that start with two underscores are “private”. Although Python does not have a real way to restrict access to members, it does some name mangling to give them a more complicated name so they stay more or less private.

So in your case, ParentClass has a __x field that is used in the PRINT method. And ChildClass has a separate, independent __x field that is not used anywhere. So for the printing, only the parent’s __x is used.

To fix this, simply change the two underscores to a single underscore, to mark the name as “internal” but not private to the type.

6 Comments

What he said. Also, you can still access the private object by accounting for the name mangling and accessing ParentClass()._ParentClass__x.
Do yourself a favor and don’t access name-wrangled members. That’s defeating the point.
Isn't it called name mangling, not name wrangling? I'm pretty sure wrangle means to round up livestock or to argue, and mangle means to mess something up so it is unidentifiable. Although I do like the mental image of rounding up variable names...
Yes, @poke agreed that's not necessarily recommended!
@SethMMorton Now that you mention it, you’re right. I wonder how often I made this mistake by now… >_<
|
0

For 'private' variable (__ as prefix) in a class, name of it has been changed. You can use the new name to call variable accordingly. Like this:

#!/usr/bin/python
# -*- coding: utf-8 -*-

class ParentClass(object):
    def __init__(self):
        self.__x = 1
        self.y = 10
    def PRINT(self):
        print (self.__x, self.y)
        print (self._ParentClass__x, self.y)
        print (self._ChildClass__x, self.y)

class ChildClass(ParentClass):
    def __init__(self):
        super(ChildClass, self).__init__()
        self.__x = 2
        self.y = 20


c = ChildClass()
c.PRINT()

OUTPUT:

(1, 20)
(1, 20)
(2, 20)

2 Comments

I realise that your code is just to illustrate a language point, but the 3rd line in your .PRINT() method is a little scary. If we do e.g., p = ParentClass(); p.PRINT() we get AttributeError: 'ParentClass' object has no attribute '_ChildClass__x'
@PM2Ring I think in this case, PRINT() won't be invoked in this way since this is just an example but not a program.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.