ljy
ljy

Reputation: 143

How to get pseudo-private attribute through inner class in Python?

class Test:
    __x = 1
    class C:
        def test(self):
            print(Test.__x)
    c = C()

a = Test()
a.c.test()

I get Error Information like this

AttributeError: type object 'Test' has no attribute '_C__x'

So, is it inner class cannot get access to outer class? Or It can be using some other techniques?

And this questions comes from reading Learning Python, when author write about CardHolder, a inner class as a descriptor use instance.__name to reach the outer class' attribute, so what is the rule of whether can we access __X attribute?

Thank you for reading my problem.

Upvotes: 4

Views: 1161

Answers (2)

napuzba
napuzba

Reputation: 6288

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.

class Test:
    __x = 1                     # <= A
    class C:
        def test(self):
            print(Test.__x)     # <= B
    c = C()
  • In A the class is Test and therefore __x is replaced with _Test__x, So, Test actually have the attribute _Test__x
  • In B the class is C and therefore __x is replaced with _C__x, So the attribute you actually access is Test._C__x

To access 'private' __x attribute of Test class outside Test class definition you should use: Test._Test__x

print(Test._Test__x)

Upvotes: 2

AdrienW
AdrienW

Reputation: 3452

Adding to underscores is the proper way to declare private attributes in Python. Your code would work fine if you changed the name of __x to _Test__x when you call it from the other class.

class Test:
    __x = 1
    class C:
        def test(self):
            print(Test._Test__x)
    c = C()
    def test2(self):
        print self.__x

a = Test()
a.test2()   # prints 1
a.c.test()  # prints 1

This tutorial goes in the details of it. The rule is: you have to be in the class to call it directly. Subclasses won't work, but methods will.

Upvotes: 1

Related Questions