1

How to access an outer class member from an inner class in Python 3?

Below is my code snippet.

class Outer:    
    def __init__(self):
        self.__x = 20
        self.__str = "Outer Class"

    def show(self):
        self.i1 = self.Inner(Outer())
        self.i1.display()

    def fn(self):
        print("Hello from fn() of Outer Class")
        print("str : ", self.__str)

    class Inner:
        def __init__(self, outer):
            self.__str_in = "Inner Class"
            self.outer = outer

        def display(self):
            print("str_in : ", self.__str_in)
            print("Inside display() of Inner Class")
            # print("x : ", self.outer.__x)
            # print("str : ", self.outer.__str)
            # self.outer.fn()


obj = Outer()
obj.show()

If I execute the commented lines, it throws an error saying -

line 23, in display
    print("x : ", self.outer.__x)
AttributeError: type object 'Outer' has no attribute '_Inner__x'

Can anyone help? Thanks in advance.

0

2 Answers 2

1

The problem with your code is that you didn't understand correctly the meaning of name mangling, that's exactly what you're doing when adding the double leading score in your variable name.

When setting up the variable as self.__x, what you're actually doing is telling the world outside your class that it can only be accessed this way when operating inside the Outer class. If you try to access outside, lets say add after the definition of obj the following print(obj.__x), you'll see the same problem.

The name mangling means that when accessing the variable outside of the scope of your class, you should call the variable _ClassName__variableName, so, in our example, you should use print(obj._Outer__x) to be able to print the variable.

Since your Inner class works the same way, as an outside scope, the simplest solution would be to rewrite your display method this way:

def display(self):
    print("str_in : ", self.__str_in)
    print("Inside display() of Inner Class")
    print("x : ", self.outer._Outer__x)
    print("str : ", self.outer._Outer__str)
    self.outer.fn()

Now, other thing I noticed, and can generate problems if you didn't do this consciously, is the call self.i1 = self.Inner(Outer()). Here you're not using the same object data that you instantiated as obj, but creating a new instance of Outer and sending this to Inner.
And what's the problem with this? Let's say you added the following lines:

obj = Outer()
obj._Outer__x = 10
obj.show()

Then the output of your show() will always be x: 20, because this change you've done in the variable, was made to an instance that was not passed to Inner.

If it's not the behaviour you were aiming for, just change this line to:

self.i1 = self.Inner(self)

So now you're effectively passing the instantiated object to Inner

Sign up to request clarification or add additional context in comments.

1 Comment

Welcome, @SarfarazHussain!
0

The problem is that you are passing the class instead of an instance in self.i1 = self.Inner(Outer), and self.__str is an instance attribute.

There is also another problem. You are using __ prefix which is subjected to name mangling, so try to avoid that.

You have 2 ways to fix this:

  • Pass the instance, ie self.i1 = self.Inner(self)

or

  • Make _str a class attribute:

    class Outer:
        _str = "Outer Class"  # NOTE THE SINGLE _
    
        def __init__(self):
            self._x = 20 # NOTE THE SINGLE _
    
        ...           
    

5 Comments

Thank you. But I have tried both ways and still, it is not working. The same error is showing up.
@SarfarazHussain Because you are probably still using __
It worker :D Thank you.. But can we say what is the problem with __? I studied that __ is for private, _ for protected.
The problem is with understanding the name mangling and its effects outside the class @SarfarazHussain! Check my answer, where I detail it and present the solution: stackoverflow.com/a/53692466/10642035

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.