0
  • Operating System: Windows 10, 64 bit
  • Editor: VSCode 1.56.2
  • Python: 3.9.0

I have a class with year property.

When I want to private this property, it seems that get and set functions that are written using @property and @year.setter decorators don't work.

class Ab():
    def __init__(self, year):
        self.__year = year
        print(self.__year)

    @property
    def year(self):
        return self.__year

    @year.setter
    def year(self, y):
        if y < 8:
            self.__year = 0
        else:
            self.__year = y


a = Ab(5)

Actual output: 5

Expected output: 0

I'm new in python, so thanks in advance for any helps.

rioV8
  • 24,506
  • 3
  • 32
  • 49
z.ghane
  • 151
  • 1
  • 15
  • Python does not define access modifiers. – Nicholas Hunter May 18 '21 at 18:19
  • @ Nicholas Hunter sorry, I can't understand. It means that because it's private so even inside the class we can't modify it?! or for a private attribute we can't convert it to a property? – z.ghane May 18 '21 at 18:25
  • 1
    You never assign to `year`, only `__year`, so the setter is never called. – chepner May 18 '21 at 18:34
  • @chepner I put __ before methods, I mean `def __year(self):` but it gives me this error `RecursionError: maximum recursion depth exceeded in comparison` – z.ghane May 18 '21 at 18:38
  • That's because that defines a class attribute named `__year` which shadows the instance attribute, so you end up with infinite recursion. The getter and setter are the *only* two things that should access `self.__year` directly; *everything* else, including other methods, should go through the property. – chepner May 18 '21 at 18:43

2 Answers2

2

You never actually modified Ab.year:

class Ab():
    def __init__(self, year):
        self.__year = year
        self.year = year # <-- this needs to be here
        print(self.__year)

    @property
    def year(self):
        return self.__year

    @year.setter
    def year(self, y):
        if y < 8:
            self.__year = 0
        else:
            self.__year = y
a = Ab(5)
>>> 0

Btw it's a bad idea to use double leading underscores unless you explicitly want name-mangling.

Lucas Ng
  • 671
  • 4
  • 11
  • 1
    You don't need the `self.__year = ...` at all in `__init__`. – chepner May 18 '21 at 18:35
  • But with this the year is not private anymore. – z.ghane May 18 '21 at 18:51
  • @Ghane in Python nothing is truly private. If that's what you really want, you could convert `Ab` to a Cython extension type – Lucas Ng May 18 '21 at 19:08
  • @Lucas Ng Yes. before python I learned Java. I thought I can private things like in Java. Thanks. – z.ghane May 18 '21 at 19:13
  • The extent of privacy you get is single underscore names not being tied to the namespace when importing – Lucas Ng May 18 '21 at 19:15
  • @Lucas Ng I think that setter and getter is just using for accessing attributes from outside of a class. so if it's private and we have not access to this attribute outside of a class, then we don't need setter and getter like this. Is my conclusion right? – z.ghane May 18 '21 at 19:18
  • setter and getter is when you want to automate an action you take every time an attribute is set or get. For example, you might have a circle that you want to update the area attribute of every time the radius changes. This action can be called internally or externally. However, if there's no need for any such action automation, then it's no use overcomplicating your code. – Lucas Ng May 18 '21 at 19:25
1

You need to reference the the setter in your __init__-- not the dunder private property.

class Ab():
    def __init__(self, year):
        self.year = year
        print(self.__year)
Teejay Bruno
  • 1,716
  • 1
  • 4
  • 11
  • With this, the `print(self.__year)` gives me the expected output. But it's a little bit strange for me. It seems year have a hidden relationship with __year, but __year have not relationship with year, I added these lines and from the output of them I said that: `self.year = year print(self.__year) self.__year = 1 print(self.__year)` Is it right? – z.ghane May 18 '21 at 18:48
  • @Ghane - `seems year have a hidden relationship with __year` - One reason to use @property getters and setters is to obfuscate how that attribute is obtained, where it comes from, how it is calculated. – wwii May 18 '21 at 19:56