Mahdi-bagvand
Mahdi-bagvand

Reputation: 1407

a bug in python private-attribute_class

I have below code

class AccountBannk:
    def __init__(self,balance,holder):
        self.__AccountHolder=holder
    def Display_AccountHolder(self):
        print "account holder is" , self.__AccountHolder
myaccount=AccountBannk(100000,"mehdiebagvand")
#print myaccount.__AccountHolder #is a error
myaccount.__AccountHolder="ali"
print myaccount.__AccountHolder      #print ali

in this code AccountHolder is a private attribute
and in python we can not directly edit or print it.
if we try below code, python release a error

print myaccount.__AccountHolder

but my questions are
1-why python not release error in below code

myaccount.__AccountHolder="ali"

2-I print myaccount.__AccountHolder in end_line but python not release error
and change the value of myaccount.__AccountHolder to 'ali'

Upvotes: 1

Views: 71

Answers (2)

Ben
Ben

Reputation: 71485

This is one of the many reasons I believe that it's way more trouble than it's worth to use __names as "private variables". The intended use case of __names is more to allow classes in a hierarchy to use nice(ish) names without worrying so much about what names are in use by other classes in the hierarchy, not to create "private" attributes.

For "private" attributes, just use single leading underscores (like _name). This documents your intention that certain names are private implementation details, while others are part of the class' public interface. It doesn't prevent anyone using the "private" name, but neither do __names because the mangling is very easy to reverse-engineer. All either of these techniques do is prevent anyone from accidentally using a name you intended to be private; they can do dodgy things, but they have to know that they're doing it. This is all you can ever get in Python; because everything is dynamic anyone can do anything at any time anyway.

So the major difference between __name and _name for your private internal names is that __name will become a major PITA whenever you start wanting to use getattr or hasattr (even within the correct class), dynamically attach methods, or have a subclass that does want to share the "private" name. A _name with a single underscore has no problems in any of those areas, is just as effective at documenting your intention, and is just as effective (i.e. almost completely ineffective) in preventing private names being used outside the class definition.

Upvotes: 1

Jason Sperske
Jason Sperske

Reputation: 30416

This is not a bug. When you are defining your first __AccountHolder inside you class, Python is mangling the variable's name (making it hard to guess, but not truly private, see PEP-8). When you attach your second __AccountHolder you are creating a new varible (with a new mangled name). Try this to see:

print myaccount.__AccountHolder
print myaccount.Display_AccountHolder()

Or add

print dir(myaccount)

Before and after you do that second assignment like so:

>>> myaccount=AccountBannk(100000,"mehdiebagvand")
>>> dir(myaccount)
    ['Display_AccountHolder', '_AccountBannk__AccountHolder', '__doc__', '__init__', '__module__']
>>> myaccount.__AccountHolder="ali"
>>> dir(myaccount)
    ['Display_AccountHolder', '_AccountBannk__AccountHolder', '__AccountHolder', '__doc__', '__init__', '__module__']

And as for the name mangling, here it is from the documentation:

__double_leading_underscore: when naming a class attribute, invokes name mangling (inside class FooBar, __boo becomes FooBar_boo; see below).

Upvotes: 3

Related Questions