Prefer properties. It's what they're there for.

The reason is that all attributes are public in Python. Starting names with an underscore or two is just a warning that the given attribute is an implementation detail that may not stay the same in future versions of the code. It doesn't prevent you from actually getting or setting that attribute. Therefore, standard attribute access is the normal, Pythonic way of, well, accessing attributes.

The advantage of properties is that they are syntactically identical to attribute access, so you can change from one to another without any changes to client code. You could even have one version of a class that uses properties (say, for code-by-contract or debugging) and one that doesn't for production, without changing the code that uses it. At the same time, you don't have to write getters and setters for everything just in case you might need to better control access later.

Answer from kindall on Stack Overflow
๐ŸŒ
Real Python
realpython.com โ€บ python-getter-setter
Getters and Setters: Manage Attributes in Python โ€“ Real Python
January 20, 2025 - Up to this point, youโ€™ve learned how to create bare-bones getter and setter methods to manage the attributes of your classes. Youโ€™ve also learned that properties are the Pythonic way to approach the problem of adding functional behavior to existing attributes.
๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ python โ€บ getter-and-setter-in-python
Getter and Setter in Python - GeeksforGeeks
July 11, 2025 - A Geek class is defined with an _age attribute. The get_age() method is the getter, which retrieves the value of _age. The set_age() method is the setter, which assigns a value to _age.
๐ŸŒ
Python Course
python-course.eu โ€บ oop โ€บ properties-vs-getters-and-setters.php
3. Properties vs. Getters and Setters | OOP | python-course.eu
Alternatively, we could have used a different syntax without decorators to define the property. As you can see, the code is definitely less elegant and we have to make sure that we use the getter function in the __init__ method again: class P: def __init__(self, x): self.set_x(x) def get_x(self): return self.__x def set_x(self, x): if x < 0: self.__x = 0 elif x > 1000: self.__x = 1000 else: self.__x = x x = property(get_x, set_x)
๐ŸŒ
Medium
aignishant.medium.com โ€บ understanding-python-property-decorators-getters-setters-57d6b535e5d2
Understanding Python Property Decorators: Getters, Setters | by Nishant Gupta | Medium
February 23, 2025 - The property decorator in Python is a powerful feature that allows you to define โ€œgetterโ€, โ€œsetterโ€ methods for class attributes without explicitly calling them as methods.
Top answer
1 of 5
11
tl;dr - getters and setters are used so that people creating classes can upgrade classes without breaking the code of those that use them. Getters and setters wrap attributes as methods, allowing you to use functionality only available through methods. In Python, we donโ€™t use getters and setters because we have properties, which allow us to make attributes look like methods after the fact. โ€”- To really understand getters and setters means understanding class design, understanding the potential problems with accessing object attributes, understanding why some languages use getters and setters, and finally understanding why we do not need getters and setters in Python. Imagine designing a class, but for a library, a library that people other than you will use. You might design a class once and then you are done with it, but in all likelihood youโ€™ll want to design it in a way where you can upgrade the functionality of it if you need to, so you need to design it in a futureproof way. The most important thing here is to ensure that, when you do upgrade your class with new functionality, you do it in a way that does not break the code of the people that are using it. This is the concept of backwards compatibility - your new class can be used by people who write code against the older class. The importance of this cannot be understated - if you continuously break peopleโ€™s code every time you upgrade your own, no one will want to use your code, ever. To ensure backwards compatibility, all the things that the people who write code access in your class access must not change. This means - the library import, the class name, the method names, the method parameters, what the method returns, and the attributes of the class - all these must be unchanged. All these aspects make up what is known as the public API of your class, and changing these means breaking backwards compatibility. Now, consider writing code for such a class. For a complicated method, you may wish to refactor its code into multiple sub-methods. Or, you may need to store attributes on your class for reasons of convenience. Having these as part of your public API would be undesirable, partly because the people using your library class do not need to access these, but mostly because if they end up using them, itโ€™ll hamper your ability to upgrade your class in the future. These end up being private methods and attribute - these are not meant to be accessible by people who use your code and you are free to change them should you need to in the future. Languages like C++ and Java let you label functions and attributes as public and private, and people using your library class will be barred from accessing private elements. In Python, there is no public or private - instead you name your private elements giving it a prefix of a single underscore (i.e. self._bar instead of self.bar), and whilst calling code can access these underscore variables, they understand that they generally must not unless they absolutely have to. An important part of protecting your public API is also related to attributes. Attribute access is very limited - you can get a value from an attribute, set a value onto an attribute, and delete an attribute entirely (get, set and delete) - and thatโ€™s about it. The problem is, when you upgrade your class, you may end to wanting to do something more. For example, you may want to add validation - i.e. you may want to raise an exception if someone assigns an incorrect value to an attribute. Or you might want to change one attribute to retrieve data from another place - a classic example is a class that provides temperature for something in both Celsius and Fahrenheit, the attribute for one should just get the attribute for the other and then do the C-to/from-F conversion. These are things that can be done only by methods, not attributes, and if you use an attribute as part of your public API you canโ€™t upgrade your class to use these things without breaking the code of those that use your class, because they are accessing an attribute (self.bar) rather than a method (self.bar()). This is where getters and setters come into play. Languages like Java and C++ use these. The concept is simple - have your attributes as private (i.e. self._bar), and then wrap your private attributes in public methods. This is how it looks in Python: def get_bar(self): return self._bar def set_bar(self, val): self._bar = val The people that use your code then use self.get_bar() and self.set_bar() when interacting with your class. Because they are interacting with a method, you can upgrade your class with the above functionality described, without breaking your public API. Getters and setters solve an important problem, but they are not without problems - the biggest being that they are fugly. The people that use your code have to do self.get_bar() rather than self.bar. But the bigger problem is for you, the creator of the class, who has to litter your code with getters and setters, regardless of whether you need them or not. You may never need to upgrade your class in the future, but youโ€™ll need to use getters and setters if you want to expose an attribute, just on the off chance youโ€™ll need it. Python solves this problem with properties. Properties allow for attributes to be converted into methods, but still be accessed as attributes. You, as the creator of a class, use public attributes when required (self.bar). When you upgrade your class, if and only if you need the functionality of a method, you use a property. You convert your public attribute into a private one (self._bar) and then you use the below syntax: @property def bar(self): return self._bar @bar.setter def bar(self, val): self._bar = val People who call your code still access the same way as an attribute (self.bar) but you now have a method under the hood, so you can use functionality that only methods can do, without breaking your public API for your users. And you only add properties when you need them, so you donโ€™t litter your code like you would with getters and setters.
2 of 5
7
Generally an object doesn't want you directly accessing or changing it's attributes. This is kinda the point of encapsulation. As such, you generally want to have 'getters' (that GET an objects attributes) and 'setters' (that, as you may guess, SET those attributes.) Say you have a Ball class. Ball has an attribute, diameter. Let's now say softball is an instance of object Ball. You COULD use softball.diameter to access this attribute. In programming it's generally frowned upon, though in Python less so. You might have an object method, say, get_diameter() that returns the diameter. So instead of accessing the variable directly through softball.diameter, you use ball.get_diameter() which is an example of a getter. See if you can imagine how a setter would look. This allows you to encapsulate how attributes are set, changed, accessed, etc, inside the method itself, and is generally considered a good thing.
๐ŸŒ
Programiz
programiz.com โ€บ python-programming โ€บ property
Python @property Decorator (With Examples)
A pythonic way to deal with the above problem is to use the property class. Here is how we can update our code: # using property class class Celsius: def __init__(self, temperature=0): self.temperature = temperature def to_fahrenheit(self): return (self.temperature * 1.8) + 32 # getter def get_temperature(self): print("Getting value...") return self._temperature # setter def set_temperature(self, value): print("Setting value...") if value < -273.15: raise ValueError("Temperature below -273.15 is not possible") self._temperature = value # creating a property object temperature = property(get_temperature, set_temperature)
Top answer
1 of 9
1159

Try this: Python Property

The sample code is:

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

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

    @x.setter
    def x(self, value):
        print("setter of x called")
        self._x = value

    @x.deleter
    def x(self):
        print("deleter of x called")
        del self._x


c = C()
c.x = 'foo'  # setter called
foo = c.x    # getter called
del c.x      # deleter called
2 of 9
628

What's the pythonic way to use getters and setters?

The "Pythonic" way is not to use "getters" and "setters", but to use plain attributes, like the question demonstrates, and del for deleting (but the names are changed to protect the innocent... builtins):

value = 'something'

obj.attribute = value  
value = obj.attribute
del obj.attribute

If later, you want to modify the setting and getting, you can do so without having to alter user code, by using the property decorator:

class Obj:
    """property demo"""
    #
    @property            # first decorate the getter method
    def attribute(self): # This getter method name is *the* name
        return self._attribute
    #
    @attribute.setter    # the property decorates with `.setter` now
    def attribute(self, value):   # name, e.g. "attribute", is the same
        self._attribute = value   # the "value" name isn't special
    #
    @attribute.deleter     # decorate with `.deleter`
    def attribute(self):   # again, the method name is the same
        del self._attribute

(Each decorator usage copies and updates the prior property object, so note that you should use the same name for each set, get, and delete function/method.)

After defining the above, the original setting, getting, and deleting code is the same:

obj = Obj()
obj.attribute = value  
the_value = obj.attribute
del obj.attribute

You should avoid this:

def set_property(property,value):  
def get_property(property):  

Firstly, the above doesn't work, because you don't provide an argument for the instance that the property would be set to (usually self), which would be:

class Obj:

    def set_property(self, property, value): # don't do this
        ...
    def get_property(self, property):        # don't do this either
        ...

Secondly, this duplicates the purpose of two special methods, __setattr__ and __getattr__.

Thirdly, we also have the setattr and getattr builtin functions.

setattr(object, 'property_name', value)
getattr(object, 'property_name', default_value)  # default is optional

The @property decorator is for creating getters and setters.

For example, we could modify the setting behavior to place restrictions the value being set:

class Protective(object):

    @property
    def protected_value(self):
        return self._protected_value

    @protected_value.setter
    def protected_value(self, value):
        if acceptable(value): # e.g. type or range check
            self._protected_value = value

In general, we want to avoid using property and just use direct attributes.

This is what is expected by users of Python. Following the rule of least-surprise, you should try to give your users what they expect unless you have a very compelling reason to the contrary.

Demonstration

For example, say we needed our object's protected attribute to be an integer between 0 and 100 inclusive, and prevent its deletion, with appropriate messages to inform the user of its proper usage:

class Protective(object):
    """protected property demo"""
    #
    def __init__(self, start_protected_value=0):
        self.protected_value = start_protected_value
    # 
    @property
    def protected_value(self):
        return self._protected_value
    #
    @protected_value.setter
    def protected_value(self, value):
        if value != int(value):
            raise TypeError("protected_value must be an integer")
        if 0 <= value <= 100:
            self._protected_value = int(value)
        else:
            raise ValueError("protected_value must be " +
                             "between 0 and 100 inclusive")
    #
    @protected_value.deleter
    def protected_value(self):
        raise AttributeError("do not delete, protected_value can be set to 0")

(Note that __init__ refers to self.protected_value but the property methods refer to self._protected_value. This is so that __init__ uses the property through the public API, ensuring it is "protected".)

And usage:

>>> p1 = Protective(3)
>>> p1.protected_value
3
>>> p1 = Protective(5.0)
>>> p1.protected_value
5
>>> p2 = Protective(-5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
  File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> p1.protected_value = 7.3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 17, in protected_value
TypeError: protected_value must be an integer
>>> p1.protected_value = 101
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> del p1.protected_value
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 18, in protected_value
AttributeError: do not delete, protected_value can be set to 0

Do the names matter?

Yes they do. .setter and .deleter make copies of the original property. This allows subclasses to properly modify behavior without altering the behavior in the parent.

class Obj:
    """property demo"""
    #
    @property
    def get_only(self):
        return self._attribute
    #
    @get_only.setter
    def get_or_set(self, value):
        self._attribute = value
    #
    @get_or_set.deleter
    def get_set_or_delete(self):
        del self._attribute

Now for this to work, you have to use the respective names:

obj = Obj()
# obj.get_only = 'value' # would error
obj.get_or_set = 'value'  
obj.get_set_or_delete = 'new value'
the_value = obj.get_only
del obj.get_set_or_delete
# del obj.get_or_set # would error

I'm not sure where this would be useful, but the use-case is if you want a get, set, and/or delete-only property. Probably best to stick to semantically same property having the same name.

Conclusion

Start with simple attributes.

If you later need functionality around the setting, getting, and deleting, you can add it with the property decorator.

Avoid functions named set_... and get_... - that's what properties are for.

Find elsewhere
๐ŸŒ
Mimo
mimo.org โ€บ glossary โ€บ python โ€บ property
Python property(): Syntax, Usage, and Examples
Manages Attribute Access: The primary ... code, like validation or calculation. @property is for Getters: The @property decorator turns a method into a "getter," which allows it to be accessed like an attribute (e.g., obj.my_prop) instead of a method (obj.my_prop())....
๐ŸŒ
Real Python
realpython.com โ€บ python-property
Python's property(): Add Managed Attributes to Your Classes โ€“ Real Python
December 15, 2024 - A property in Python is a tool for creating managed attributes in classes. The @property decorator allows you to define getter, setter, and deleter methods for attributes.
๐ŸŒ
DataCamp
datacamp.com โ€บ tutorial โ€บ property-getters-setters
Python Property vs. Getters & Setters | DataCamp
December 18, 2018 - class SampleClass: def __init__(self, a): ## private varibale or property in Python self.__a = a ## getter method to get the properties using an object def get_a(self): return self.__a ## setter method to change the value 'a' using an object def set_a(self, a): self.__a = a
๐ŸŒ
Ansys
developer.ansys.com โ€บ blog โ€บ getting-started-classes-python-part-7-getters-and-setters
Getting started with classes in Python Part 7: getters and setters | Ansys Developer Portal
Here we are with Part 7 in this series on classes in Python. This article covers setters (the method on a class that sets a property) and getters (which gets the property).
๐ŸŒ
Medium
salma-mohamed.medium.com โ€บ getters-setters-and-deleters-in-python-b8ae8fc02662
GETTERS, SETTERS AND DELETERS IN PYTHON | by Salma mohamed | Medium
September 7, 2023 - -In Python, you can define a getter method using the @property decorator. The method name is typically the same as the attribute you want to get. class MyClass: def __init__(self, value): self._value = value @property def pytvalue(self): return ...
๐ŸŒ
TechVidvan
techvidvan.com โ€บ tutorials โ€บ python-property-class-getters-setters
Python Property Class | Getters & Setters - TechVidvan
May 18, 2021 - Setters:- They help in changing/renaming the already defined internal libraries in python. ... Class latestclass: def __ini__(self, a): self.__b= b ## getter method to get the properties def get_b(self): return self.__b ## setter method to change the value 'b' def set_b(self, b): self.__b = b
๐ŸŒ
freeCodeCamp
freecodecamp.org โ€บ news โ€บ python-property-decorator
The @property Decorator in Python: Its Use Cases, Advantages, and Syntax
December 19, 2019 - With @property, you and your team will not need to modify any of those lines because you will able to add getters and setters "behind the scenes" without affecting the syntax that you used to access or modify the attribute when it was public. ... class House: def __init__(self, price): self._price = price @property def price(self): return self._price @price.setter def price(self, new_price): if new_price > 0 and isinstance(new_price, float): self._price = new_price else: print("Please enter a valid price") @price.deleter def price(self): del self._price
๐ŸŒ
Python Reference
python-reference.readthedocs.io โ€บ en โ€บ latest โ€บ docs โ€บ property โ€บ setter.html
setter โ€” Python Reference (The Right Way) 0.1 documentation
A property object has getter, setter, and deleter methods usable as decorators that create a copy of the property with the corresponding accessor function set to the decorated function. This is best explained with an example: class C(object): 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
๐ŸŒ
Medium
medium.com โ€บ @pijpijani โ€บ understanding-property-in-python-getters-and-setters-b65b0eee62f9
Understanding Property in Python: Getters and Setters | by Pikho | Medium
March 2, 2023 - It provides a way to access or modify the value of an attribute in a controlled manner while hiding the implementation details. To create a property in Python, you can use the @property decorator to define a getter method for the attribute and the ...
๐ŸŒ
DEV Community
dev.to โ€บ hernanchilabert โ€บ understanding-getter-setter-and-private-variables-in-python-9h8
Understanding Getter, Setter and Private variables in Python - DEV Community
January 27, 2024 - In this example, __price is a private variable of the Product class. Encapsulation: They hide the internal state of an object from outside interference. Security: Prevents external entities from modifying the state in an uncontrolled manner. Maintenance: Makes it easier to change the attribute implementation without affecting external users. ... Python provides a property function that makes the implementation of getters and setters straightforward and intuitive.
๐ŸŒ
Medium
medium.com โ€บ @imshivam077 โ€บ day-32-getters-and-setters-f3747f62491e
Day-32 โ€” Getters And Setters. In Python, getters and setters areโ€ฆ | by Shivam Shukla | Medium
December 20, 2023 - In Python, getters and setters are methods that allow you to control access to the attributes of a class. They are used to get and set the values of private attributes, providing a way to encapsulate the internal state of an object.
๐ŸŒ
DEV Community
dev.to โ€บ the1kimk โ€บ function-decorators-in-python-understanding-property-getter-and-setter-methods-3a8e
Function Decorators in Python: Understanding @property, Getter, and Setter Methods - DEV Community
September 22, 2024 - This decorator allows you to define methods that behave like attributes, making the code more readable and Pythonic while still allowing for controlled access. Using the @property Decorator for Getter and Setter Below is the previous example refactored with @property to simplify syntax and improve readability: class Product: def __init__(self, price): self._price = price @property def price(self): return self._price @price.setter def price(self, value): if value >= 0: self._price = value else: raise ValueError("Price cannot be negative") product = Product(10) print(product.price) # 10 product.price = 20 print(product.price) # 20