-2

Can someone explain why was I able to set a private variable without using the setter method?

1

Zephyr
  • 11,891
  • 53
  • 45
  • 80
  • the `.company` attribute did not exist until you set it to facebook, and it is independent from your "private" `.__company` attribute – imochoa Dec 01 '20 at 08:15
  • 1
    First of all Python doesn't really have *private* attributes. Second, you just created a new attribute `company` and didn't change the "private" attribute `__company` – Tomerikoo Dec 01 '20 at 08:30
  • 2
    Please avoid posting images (or worse, links to images) of code or errors. Anything text-based (code and errors) should be posted as text directly in the question itself and formatted properly. You can get more [formatting help here](https://stackoverflow.com/help/formatting). You can also read about [why you shouldn't post images/links of code](//meta.stackoverflow.com/q/285551). – Tomerikoo Dec 01 '20 at 08:31
  • Also, see [What's the pythonic way to use getters and setters?](https://stackoverflow.com/questions/2627002/whats-the-pythonic-way-to-use-getters-and-setters) Also relevant: [What is the meaning of single and double underscore before an object name?](https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-single-and-double-underscore-before-an-object-name) – Tomerikoo Dec 01 '20 at 08:32
  • After assigning to `Facebook` change the `print` to `print(obj2.name, obj2.company, obj2.get_company())` and see what happened – Tomerikoo Dec 01 '20 at 08:40

2 Answers2

1

Yes, you can.

Python doesn't really have private members. However, it does some tricky naming things to try and accomplish as such.

When you do have a __member name, to access it outside, you would use _<ClassName>__<member_name>

Example:

[ttucker@zim stackoverflow]$ cat private.py 
class MyClass:
    def __init__(self):
        self.__private = "initial"

    def show(self):
        print(self.__private)


private = MyClass()
private.show()              # -> "initial"

# Does not actually set the private member,
# but creates a public member with the same name 
private.__private = "new"
private.show()              # -> "initial"
print(private.__private)    # -> "new"

# This actually changes the "private" member.
private._MyClass__private = "new"
private.show()              # -> "new"

Execution:

[ttucker@zim stackoverflow]$ python private.py 
initial
initial
new
new
Tim
  • 2,139
  • 13
  • 18
0

Thanks for @Tomerikoo's answer. I'd like to add something about this.

The key point is that python DOES NOT really have private attributes. Basically, python only changes private attributes' names as format below:

_className__privateAttributeName

So for code in the question, attribute company is just another new attribute. To verify this, we can use dir(obj2) to see the details.

>>> dir(obj2)
(Pdb) dir(obj2)
['_Employee__company', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__
', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__n
e__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook_
_', '__weakref__', 'company', 'get_company', 'name', 'set_company']
(Pdb)

As we can see company and _Employee__company are just two different attributes.

V Demo
  • 151
  • 3