Here's a more thorough example of why you would want to have a private attribute: data type validation (as pointed out by the other answers).

Let's say that you've been using the Dog class for a few weeks, and a new bug has come up that happens when the name attribute is (for whatever reason) set to a value that's not a string. You now need to change the code in order to enforce that a Dog's name is indeed a string, by raising an informative Exception. How do you do that?

Your first idea may be to simply check the name's data type after creating a new Dog (using the isinstance builtin function):

my_dog = Dog(name='Max', age=5)
if not isinstance(my_dog.name, str):
    raise ValueError("The Dog's name is not a string")

This works, but there's a clear issue here: you need to 1) change every line of code where a Dog is created, and 2) you need to tell anyone who ever uses your Dog class that, by the way, remember to check for the name's data type. This is clearly a lot of work, and not future-proof by any means - what if you or another user forgets to do this check? What if no one ever reads your documentation on the Dog class?

You may then think to perform this check in the __init__ method:

def class Dog:
    def __init__(self, name, age):
        if not isinstance(name, str):
            raise ValueError("The Dog's name is not a string")
        self.__name = name
        self.age = age

This cuts down on the work, but it doesn't stop someone from modifying the Dog's name after it was instantiated:

my_dog = Dog(name='Max', age=5)
my_dog.name = 10  # oops, wrong value!

What we want to do is to actually move this type-checking functionality to a method that runs every time the name attribute gets set - which is exactly what the setter method (the one decorated with the @name.setter decorator) does:

def class Dog:
    def __init__(self, name, age):
        self.__name = name
        self.age = age

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, new_name)
        if not isinstance(new_name, str):
            raise ValueError("The Dog's name is not a string")
        self.__name = new_name

Now the name's data type is always checked for, both during instantiation (in the __init__ method) and afterwards.

Data type validation is simply an example. The point of using private attributes and their getters/setters is to combine attribute access with some custom functionality. If you desire no functionality whatsoever when accessing/modifying the attribute, you're correct in your observation that you don't need to bother making it private and writing the getter/setter methods in the first place.

Answer from jfaccioni on Stack Exchange
🌐
Imperial College London
python.pages.doc.ic.ac.uk › 2021 › lessons › decorator › 03-application › 03-property.html
Advanced Lesson 4: Python Decorators > Property decorator
The property class has a constructor, which takes a function (the getter method) as the first parameter, and optionally a setter method as the second parameter. Python will automatically invoke the correct methods when a user accesses the .name attribute of a VainPerson instance.
Top answer
1 of 2
3

Here's a more thorough example of why you would want to have a private attribute: data type validation (as pointed out by the other answers).

Let's say that you've been using the Dog class for a few weeks, and a new bug has come up that happens when the name attribute is (for whatever reason) set to a value that's not a string. You now need to change the code in order to enforce that a Dog's name is indeed a string, by raising an informative Exception. How do you do that?

Your first idea may be to simply check the name's data type after creating a new Dog (using the isinstance builtin function):

my_dog = Dog(name='Max', age=5)
if not isinstance(my_dog.name, str):
    raise ValueError("The Dog's name is not a string")

This works, but there's a clear issue here: you need to 1) change every line of code where a Dog is created, and 2) you need to tell anyone who ever uses your Dog class that, by the way, remember to check for the name's data type. This is clearly a lot of work, and not future-proof by any means - what if you or another user forgets to do this check? What if no one ever reads your documentation on the Dog class?

You may then think to perform this check in the __init__ method:

def class Dog:
    def __init__(self, name, age):
        if not isinstance(name, str):
            raise ValueError("The Dog's name is not a string")
        self.__name = name
        self.age = age

This cuts down on the work, but it doesn't stop someone from modifying the Dog's name after it was instantiated:

my_dog = Dog(name='Max', age=5)
my_dog.name = 10  # oops, wrong value!

What we want to do is to actually move this type-checking functionality to a method that runs every time the name attribute gets set - which is exactly what the setter method (the one decorated with the @name.setter decorator) does:

def class Dog:
    def __init__(self, name, age):
        self.__name = name
        self.age = age

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, new_name)
        if not isinstance(new_name, str):
            raise ValueError("The Dog's name is not a string")
        self.__name = new_name

Now the name's data type is always checked for, both during instantiation (in the __init__ method) and afterwards.

Data type validation is simply an example. The point of using private attributes and their getters/setters is to combine attribute access with some custom functionality. If you desire no functionality whatsoever when accessing/modifying the attribute, you're correct in your observation that you don't need to bother making it private and writing the getter/setter methods in the first place.

2 of 2
5

The advantage of properties is that from the viewpoint of the user of your class, it's syntactically the same as plain attribute access. So you can add logic (validation etc.) at any time without changing the class's interface and breaking the code that uses it. You can even swap in different versions of the class (e.g. with properties that do logging during development, without properties for production) and the caller won't even notice.

Contrast this to a language like Java where best practice is to always write getter/setter methods even if you don't need them, because you might need them later, but can't add them later without changing the API and thereby breaking code that uses the class.

BTW, there are no truly private attributes in Python. The leading __ is intended to keep names from conflicting among subclasses of the base class, where that might be a problem.

Discussions

properties - How does the @property decorator work in Python? - Stack Overflow
I would like to understand how the built-in function property works. What confuses me is that property can also be used as a decorator, but it only takes arguments when used as a built-in function ... More on stackoverflow.com
🌐 stackoverflow.com
When not to use @property decorator?
A property looks like a field to someone who doesn't know how the class works, so it should act more or less like a field or the users of the class are going to get confused, which is bad. A few things I can think of: A property probably shouldn't have side effects (aside from setters setting values), certainly not side effects that are obvious from outside the class. Imagine you asked for the length of an array and the property's getter called print() or something. A property probably shouldn't take too long to generate. Imagine you had a large, highly connected graph that you were manipulating, and you gave it a property that returned all the shortest paths in the graph as a matrix, and it was generated each time, which took seconds or more. If x.prop == val would evaluate to False for any reason immediately after x.prop = val, then prop shouldn't be a property. More on reddit.com
🌐 r/learnpython
12
9
May 26, 2023
Cached @property decorator that is memory friendly
Here's the only caching @property you need to know: class memoized_property(object): """A read-only @property that is only evaluated once.""" def __init__(self, fget, doc=None): self.fget = fget self.__doc__ = doc or fget.__doc__ self.__name__ = fget.__name__ def __get__(self, obj, cls): if obj is None: return self obj.__dict__[self.__name__] = result = self.fget(obj) return result What goes on here, is that the object is known as a non-data descriptor . It's specifically the fact that the object has only __get__, and not __set__ or __del__, that values placed in __dict__ override the descriptor. This means after the first time __get__ runs, all subsequent accesses are direct attribute access - zero method call overhead. More on reddit.com
🌐 r/Python
4
5
August 8, 2010
Decorator to treat method as a property or callable.
So I think this basically does what you want. There might be a more suitable proxy in wrapt somewhere, but I fall back to ObjectProxy so often it's second nature. from __future__ import unicode_literals from wrapt import ObjectProxy class Callable(ObjectProxy): def __call__(self, *args, **kwargs): result = self.__wrapped__ if 'upper' in kwargs: result = result.upper() return result class Test(object): __slots__ = ('name',) def __init__(self, name): self.name = name @property def fullname(self): return Callable(self.name) test = Test(name='test') assert test.fullname == 'test' assert isinstance(test.fullname, unicode) is True assert test.fullname(upper=True) == 'TEST' assert test.fullname()[3] == 't' Here's a gist in case that's useful. More on reddit.com
🌐 r/Python
11
1
April 8, 2016
🌐
LinkedIn
linkedin.com › pulse › python-property-decorator-cloud-ai-analytics
Python @property decorator
Python @property decorator: · A pythonic way to use getters and setters in object-oriented programming. · It is a built-in property provided by python.
Top answer
1 of 15
1343

The property() function returns a special descriptor object:

>>> property()
<property object at 0x10ff07940>

It is this object that has extra methods:

>>> property().getter
<built-in method getter of property object at 0x10ff07998>
>>> property().setter
<built-in method setter of property object at 0x10ff07940>
>>> property().deleter
<built-in method deleter of property object at 0x10ff07998>

These act as decorators too. They return a new property object:

>>> property().getter(None)
<property object at 0x10ff079f0>

that is a copy of the old object, but with one of the functions replaced.

Remember, that the @decorator syntax is just syntactic sugar; the syntax:

@property
def foo(self): return self._foo

really means the same thing as

def foo(self): return self._foo
foo = property(foo)

so foo the function is replaced by property(foo), which we saw above is a special object. Then when you use @foo.setter(), what you are doing is call that property().setter method I showed you above, which returns a new copy of the property, but this time with the setter function replaced with the decorated method.

The following sequence also creates a full-on property, by using those decorator methods.

First we create some functions:

>>> def getter(self): print('Get!')
... 
>>> def setter(self, value): print('Set to {!r}!'.format(value))
... 
>>> def deleter(self): print('Delete!')
... 

Then, we create a property object with only a getter:

>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True

Next we use the .setter() method to add a setter:

>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True

Last we add a deleter with the .deleter() method:

>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True

Last but not least, the property object acts as a descriptor object, so it has .__get__(), .__set__() and .__delete__() methods to hook into instance attribute getting, setting and deleting:

>>> class Foo: pass
... 
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!

The Descriptor Howto includes a pure Python sample implementation of the property() type:

class Property:
    "Emulate PyProperty_Type() in Objects/descrobject.c"

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)
2 of 15
403

The documentation says it's just a shortcut for creating read-only properties. So

@property
def x(self):
    return self._x

is equivalent to

def getx(self):
    return self._x
x = property(getx)
🌐
NestJS
docs.nestjs.com › modules
Documentation | NestJS - A progressive Node.js framework
Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).
🌐
W3Schools
w3schools.com › python › python_decorators.asp
Python Decorators
Python Examples Python Compiler ... Python Certificate Python Training ... Decorators let you add extra behavior to a function, without changing the function's code....
Find elsewhere
🌐
GeeksforGeeks
geeksforgeeks.org › python › python-property-decorator-property
Python Property Decorator - @property - GeeksforGeeks
July 12, 2025 - Note: For more information, refer to Decorators in Python · @property decorator is a built-in decorator in Python which is helpful in defining the properties effortlessly without manually calling the inbuilt function property().
🌐
DEV Community
dev.to › eastrittmatter › python-property-and-descriptors-2aco
Python Property() and Descriptors - DEV Community
March 8, 2024 - It is easy enough to added some data validation before setattr to determine if the reassignment should occur, and Python even has an inbuilt Validator class that makes this easier (custom calidatorscan be made as subclasses by being defined with TheClassName(Validator)). The property decorator, along with the classmethod decorator and others, can handle all this work of hooking in with descriptors for us, but often we need to start using magic methods ourselves to change how our custom objects behave.
🌐
Programiz
programiz.com › python-programming › property
Python @property Decorator (With Examples)
Let's look at how to implement this as a decorator: class Celsius: def __init__(self, temperature=0): # when creating the object, the setter method is called automatically self.temperature = temperature def to_fahrenheit(self): # convert the temperature to Fahrenheit return (self.temperature * 1.8) + 32 @property def temperature(self): print("Getting value...") return self._temperature @temperature.setter def temperature(self, value): print("Setting value...") # ensure the temperature does not go below absolute zero if value < -273.15: raise ValueError("Temperature below -273.15°C is not poss
🌐
AlgoMaster
algomaster.io › learn › python › property-decorator
Property Decorator | Python | AlgoMaster.io | AlgoMaster.io
January 3, 2026 - The @property decorator is a built-in feature in Python that allows you to define a method as a property.
🌐
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.
🌐
Python documentation
docs.python.org › 3 › whatsnew › 3.14.html
What’s new in Python 3.14
3 weeks ago - Remove the following deprecated properties on ast.Constant, which were present for compatibility with the now-removed AST classes:
🌐
StrataScratch
stratascratch.com › blog › how-to-use-python-property-decorator-with-examples
How to Use Python Property Decorator (With Examples) - StrataScratch
November 16, 2023 - In this code, the Python property decorator makes it so that you can't just randomly set the temperature to any value. It has to be between 10 and 40 for the model to work properly.
🌐
Python Software Foundation
wiki.python.org › python › Decorators.html
Decorators
This decorator does not alter a function, but causes it to be executed if __name__ == '__main__'. This provides an experimental cleaner syntax to the traditional way of bootstrapping a python script.
🌐
TypeORM
typeorm.io
TypeORM - Code with Confidence. Query with Power. | TypeORM
TypeORM is an ORM that can run in NodeJS, Browser, Cordova, Ionic, React Native, NativeScript, Expo, and Electron platforms and can be used with TypeScript and JavaScript.
🌐
Reddit
reddit.com › r/learnpython › when not to use @property decorator?
r/learnpython on Reddit: When not to use @property decorator?
May 26, 2023 -

The @property decorator comes with a whole system with getters and setters.

However I have been using it only to provide a cleaner access to a method which doesn't take any arguments and not for anything else.

If the method has to accept arguments in future, I remove the decorator and update the usages.

Are there any downsides to this? What are some other scenarios to not use @property?

Top answer
1 of 4
13
A property looks like a field to someone who doesn't know how the class works, so it should act more or less like a field or the users of the class are going to get confused, which is bad. A few things I can think of: A property probably shouldn't have side effects (aside from setters setting values), certainly not side effects that are obvious from outside the class. Imagine you asked for the length of an array and the property's getter called print() or something. A property probably shouldn't take too long to generate. Imagine you had a large, highly connected graph that you were manipulating, and you gave it a property that returned all the shortest paths in the graph as a matrix, and it was generated each time, which took seconds or more. If x.prop == val would evaluate to False for any reason immediately after x.prop = val, then prop shouldn't be a property.
2 of 4
5
I would say only use it in the first place if it's meant to be a thin wrapper around an internal attribute (or act like that's the case). If the property setting is doing more than pre/post condition checks and data cleaning, and the getter is doing more than the same checks and some standardization, you don't want properties; you want normal methods. Also, if you're doing any kind of side effects that affect outside, you should absolutely not be using property. Basically, don't allow the user to do something dumb, like accidentally triggering expensive operations, or side effects. It is not clear just by looking at a property that code will run as a result of simply accessing the property, so the user may needlessly trigger things that they don't mean to.
🌐
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.
🌐
Tutor Python
tutorpython.com › python-property-decorator
Python @property Decorator - Tutor Python
October 19, 2023 - Python @property decorator allows us to define methods in a class that can be accessed like attributes, providing a clean and intuitive way to encapsulate the logic behind attribute access and modification.
🌐
freeCodeCamp
freecodecamp.org › news › python-property-decorator
The @property Decorator in Python: Its Use Cases, Advantages, and Syntax
December 19, 2019 - I know you may be asking: how is this related to the @property? The @property is a built-in decorator for the property() function in Python.
🌐
The Teclado Blog
blog.teclado.com › property-decorator-in-python
The @property decorator in Python
January 26, 2023 - The property decorator allows us to define methods that act as attributes in Python classes. This simplifies using the objects, and extends what we can do when getting and setting attribute values.