2

In this example, a user can still access and set the variable using:

obj = C()
obj._x=10
varA  = obj._x

Even if we use __x instead of _x in below code, x still doesn't become private. So the only purpose of _x is to let the programmers know that it is not meant to be set directly via obj._x?

class C:
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x
lmiguelvargasf
  • 63,191
  • 45
  • 217
  • 228
variable
  • 8,262
  • 9
  • 95
  • 215
  • 8
    No. Python is a language for "consenting adults"; that is, we may indicate that a variable is private via a leading underscore, but we don't enforce privacy like C++/C#/Java. The double leading underscore has a specific purpose: mimicking the access modifiers in other languages is not that purpose. – snakecharmerb Sep 09 '19 at 19:15
  • Even a leading double underscore won't prevent modification, it will just make it "harder" https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-a-single-and-a-double-underscore-before-an-object-name – DeepSpace Sep 09 '19 at 19:17
  • Python doesn't have private. Not even double-underscore name-mangling. That isn't what double-underscore name-mangling is for. Your example using property is not what you should be doing. – juanpa.arrivillaga Sep 09 '19 at 19:19
  • Ok so in this example, the purpose of property is to ensure that when value is assigned or fetched using obj.x, then, it calls the appropriate getter/setter which will apply logic if any and then get/set the value from/to _x respectively – variable Sep 09 '19 at 19:36
  • @variable And in that case, you should (probably) be assigning to the property *everywhere*, even in `__init__`, instead of bypassing and assigning directly to `_x`. – chepner Sep 09 '19 at 19:39
  • @variable if your getter and setters don't apply any logic then *don't use a property* that defeats the entire point! This example should just have an `__init__` that assigns to `self.x`. then later if you decide you want to manage how `self.x` is accessed, **then you add the property**. It's encapsulation without boilerplate. That's *the beauty of it* – juanpa.arrivillaga Sep 09 '19 at 20:32

1 Answers1

3

In Python, it is a convention to use _var_name in order to indicate that something is private, but it does not enforce it like in languages as C++, C#, Java, etc.

A double underscore prefix causes the Python interpreter to rewrite the attribute name in order to avoid naming conflicts in subclasses.

This is also called name mangling—the interpreter changes the name of the variable in a way that makes it harder to create collisions when the class is extended later.

Consider the following example

class Test:
    def __init__(self):
        self.foo = 11
        self._bar = 23
        self.__baz = 23

Now, let's run the following code:

>>> t = Test()
>>> dir(t)
['_Test__baz', '__class__', '__delattr__', '__dict__', '__dir__',
 '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
 '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__',
 '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
 '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
 '__weakref__', '_bar', 'foo']

dir(t) gives us a list with the object’s attributes. When you search for __baz in that list you’ll see that there is no variable with that name. If you look closely you’ll see there’s an attribute called _Test__baz on this object. This is the name mangling that the Python interpreter applies.

lmiguelvargasf
  • 63,191
  • 45
  • 217
  • 228
  • Ok so even removing the single underscore doesnt make any difference technically – variable Sep 09 '19 at 19:23
  • @variable, it doesn't. As user `snakecharmerb` has told you. This is an agreed convention, so you can simply break the rules, but Pythonistas has agreed to respect it. – lmiguelvargasf Sep 09 '19 at 19:25
  • 2
    @variable Again, **Python does not have private variables**. [It says that right in the documentation](https://docs.python.org/3.7/tutorial/classes.html#private-variables). If you are looking for that, use another language – juanpa.arrivillaga Sep 09 '19 at 19:25
  • @juanpa.arrivillaga, thank you so much to provide links to the documentation. – lmiguelvargasf Sep 09 '19 at 19:29
  • The purpose of property is to ensure that when value is assigned or fetched using obj.x, then, it calls the appropriate getter/setter which will apply logic if any and then get/set the value from/to _x respectively ? – variable Sep 09 '19 at 19:42
  • @variable, that is the definition of a getter and a setter in some programming languages like C++, C# or Java. In Python, `property` is decorator that helps you to achieve the same result. However, adding an `_` does not guarantee you that the variable won't be accessed, so considering you are following the conventions, the property will allow you access/set this property. – lmiguelvargasf Sep 09 '19 at 19:51
  • Makes sense thanks – variable Sep 09 '19 at 19:56