0

I encountered a strange issue while using python. consider the below code:

class Foo:
    __bar=None

foo=Foo()
foo.bar=10
print(foo.bar)

I beleive I should get an error here. But I get the output as 10. I get the same output even if I change the code as:

foo=Foo()
foo.__bar=10
print(foo.__bar)

can someone explain why I am not getting an error here? Also what should I do to get an error? Edited for additional clarification:

class Foo:
    def __init__(self):
        self.__bar=10
    def get_bar(self):
        return self.__bar

foo=Foo()
foo.__bar=20
print(foo.__bar)
print(foo.get_bar())

Can someone explain why I am getting the answer as 20 and 10? I thought I will get an error for trying to access a private instance variable outside the class. Thanks for the help.

codingsplash
  • 4,252
  • 9
  • 44
  • 84
  • Why do you believe that you should get an error? What are you doing wrong, in your opinion? – Hashmush Feb 18 '15 at 05:46
  • Underscores for "private" variables is merely a convention. Nothing more. Also, `bar` and `__bar` are not the same property. Nothing in Python says that this should trigger anything. – deceze Feb 18 '15 at 05:46
  • wth, this is such a duplicate. did someone un-close it? – nneonneo Feb 18 '15 at 06:03
  • This question is not a duplicate, becuase it is not asking about leading double-underscore in general, but about a specific usage, and none of the answers in the other question cover the answer to this question. – shx2 Feb 18 '15 at 06:03

1 Answers1

4

First of all, you should read the answers to the related quesion.

Second of all, don't confuse between class-members and instance members. Your definition of the class Foo includes a class member named __bar, but assigning to foo.__bar adds an instance-member which overshadows it (and not overwrites it). Those are different things.

Now, when you assign (or in general, access) a leading-double-underscore attribute from "outside" (in your example, using foo.__bar), the name does not get mangaled, and everything works without extra magic. However, the standard way of accessing leading-double-underscore attributes is from within methods of the class (using self.__bar), and that is when the magic happens.

To demonstrate:

class Foo(object): pass

f = Foo()
foo.__bar = 10
foo.__bar
=> 10
foo.__dict__.keys()
=> dict_keys(['__bar'])

class Foo(object):
    def __init__(self):
       self.__bar = 10

foo = Foo()
foo.__dict__.keys()
=> dict_keys(['_Foo__bar'])  # mangaled!
foo.__bar  # cannot access from "outside"
=> AttributeError
shx2
  • 57,957
  • 11
  • 121
  • 147