I\'m coming from the Java world and reading Bruce Eckels\' Python 3 Patterns, Recipes and Idioms.
While reading about classes, it goes on to say that in Py
The only time I ever use private variables is when I need to do other things when writing to or reading from the variable and as such I need to force the use of a setter and/or getter.
Again this goes to culture, as already stated. I've been working on projects where reading and writing other classes variables was free-for-all. When one implementation became deprecated it took a lot longer to identify all code paths that used that function. When use of setters and getters was forced, a debug statement could easily be written to identify that the deprecated method had been called and the code path that calls it.
When you are on a project where anyone can write an extension, notifying users about deprecated methods that are to disappear in a few releases hence is vital to keep module breakage at a minimum upon upgrades.
So my answer is; if you and your colleagues maintain a simple code set then protecting class variables is not always necessary. If you are writing an extensible system then it becomes imperative when changes to the core is made that needs to be caught by all extensions using the code.
As correctly mentioned by many of the comments above, let's not forget the main goal of Access Modifiers: To help users of code understand what is supposed to change and what is supposed not to. When you see a private field you don't mess around with it. So it's mostly syntactic sugar which is easily achieved in Python by the _ and __.
Private variables in python is more or less a hack: the interpreter intentionally renames the variable.
class A:
def __init__(self):
self.__var = 123
def printVar(self):
print self.__var
Now, if you try to access __var
outside the class definition, it will fail:
>>>x = A()
>>>x.__var # this will return error: "A has no attribute __var"
>>>x.printVar() # this gives back 123
But you can easily get away with this:
>>>x.__dict__ # this will show everything that is contained in object x
# which in this case is something like {'_A__var' : 123}
>>>x._A__var = 456 # you now know the masked name of private variables
>>>x.printVar() # this gives back 456
You probably know that methods in OOP are invoked like this: x.printVar() => A.printVar(x)
, if A.printVar()
can access some field in x
, this field can also be accessed outside A.printVar()
...after all, functions are created for reusability, there is no special power given to the statements inside.
The game is different when there is a compiler involved (privacy is a compiler level concept). It know about class definition with access control modifiers so it can error out if the rules are not being followed at compile time
Sorry guys for "resurrecting" the thread, but, I hope this will help someone:
In Python3 if you just want to "encapsulate" the class attributes, like in Java, you can just do the same thing like this:
class Simple:
def __init__(self, str):
print("inside the simple constructor")
self.__s = str
def show(self):
print(self.__s)
def showMsg(self, msg):
print(msg + ':', self.show())
To instantiate this do:
ss = Simple("lol")
ss.show()
Note that: print(ss.__s)
will throw an error.
In practice, Python3 will obfuscate the global attribute name. Turning this like a "private" attribute, like in Java. The attribute's name is still global, but in an inaccessible way, like a private attribute in other languages.
But don't be afraid of it. It doesn't matter. It does the job too. ;)
Python does not have any private variables like C++ or Java does. You could access any member variable at any time if wanted, too. However, you don't need private variables in Python, because in Python it is not bad to expose your classes member variables. If you have the need to encapsulate a member variable, you can do this by using "@property" later on without breaking existing client code.
In python the single underscore "_" is used to indicate, that a method or variable is not considered as part of the public api of a class and that this part of the api could change between different versions. You can use these methods/variables, but your code could break, if you use a newer version of this class.
The double underscore "__" does not mean a "private variable". You use it to define variables which are "class local" and which can not be easily overidden by subclasses. It mangles the variables name.
For example:
class A(object):
def __init__(self):
self.__foobar = None # will be automatically mangled to self._A__foobar
class B(A):
def __init__(self):
self.__foobar = 1 # will be automatically mangled to self._B__foobar
self.__foobar's name is automatically mangled to self._A__foobar in class A. In class B it is mangled to self._B__foobar. So every subclass can define its own variable __foobar without overriding its parents variable(s). But nothing prevents you from accessing variables beginning with double underscores. However, name-mangling prevents you from calling this variables /methods incidentally.
I strongly recommend to watch Raymond Hettingers talk "Pythons class development toolkit" from Pycon 2013 (should be available on Youtube), which gives a good example why and how you should use @property and "__"-instance variables.
If you have exposed public variables and you have the need to encapsulate them, then you can use @property. Therefore you can start with the simplest solution possible. You can leave member variables public unless you have a concrete reason to not do so. Here is an example:
class Distance:
def __init__(self, meter):
self.meter = meter
d = Distance(1.0)
print(d.meter)
# prints 1.0
class Distance:
def __init__(self, meter):
# Customer request: Distances must be stored in millimeters.
# Public available internals must be changed.
# This would break client code in C++.
# This is why you never expose public variables in C++ or Java.
# However, this is python.
self.millimeter = meter * 1000
# In python we have @property to the rescue.
@property
def meter(self):
return self.millimeter *0.001
@meter.setter
def meter(self, value):
self.millimeter = meter * 1000
d = Distance(1.0)
print(d.meter)
# prints 1.0
private and protected concepts are very important. But python - just a tool for prototyping and rapid development with restricted resources available for development, that is why some of protection levels are not so strict followed in python. You can use "__" in class member, it works properly, but looks not good enough - each access to such field contains these characters.
Also, you can noticed that python OOP concept is not perfect, smaltalk or ruby much closer to pure OOP concept. Even C# or Java are closer.
Python is very good tool. But it is simplified OOP language. Syntactically and conceptually simplified. The main goal of python existence is to bring to developers possibility to write easy readable code with high abstraction level in a very fast manner.