简体   繁体   中英

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

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.

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

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 _ ... 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM