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__)
Answer from Martijn Pieters on Stack Overflow
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)
🌐
Python documentation
docs.python.org › 3 › library › functions.html
Built-in Functions — Python 3.14.3 documentation
2 weeks ago - 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.
Discussions

What is the purpose of @property ?
Properties solve several problems. The main one is that they allow you to substitute a method call for an attribute access without changing the public API. That is important if you're dealing with large software projects where you can't break backwards compatibility. The method can contain arbitrary logic. For example, suppose that you wrote a class that stores a temperature. You initially wrote it to store temperate in Fahrenheit as a simple attribute, and you have lots of existing code that depends on that. But at some point you decide that you want it internally stored as Celsius. By using a computed property, you can change the internal representation to Celsius, while pretending to external users that it's still stored as Fahrenheit, by writing a getter method that dynamically computes the conversion. This is intentionally silly, but you can imagine more complex examples where you want to change the internal representation or other internal implementation details without affecting the public API. Another problem it solves is of validation. With a simple attribute, users can set any value. Again going back to the temperature example, someone might set the attribute to an invalid temperature. By using a setter of a property, you can intercept that attribute access and execute arbitrary logic to perform validation, raising an exception if they do something wrong. Arguably, the getting and setting in this case should have been written as methods in the first place, rather than attributes, but again you don't always have that kind of foresight, and often design decisions change and you need to make the change without breaking the API. Properties allow that. More on reddit.com
🌐 r/learnpython
14
25
November 17, 2017
properties - When and how to use the builtin function property() in python - Stack Overflow
The behavior of x.b accesses, and assignments such as x.b = 2, in languages which do have properties (a set of languages which includes but is not limited to Python) is exactly the same as for getter and setter methods in, e.g., Java: the same expectations, the same lack of language-enforced ... More on stackoverflow.com
🌐 stackoverflow.com
Python @property: How and Why?
Just remember to never use properties unless you actually have some processing to do on get or set. This might sound funny when it comes to python, but properties are much slower than simple attribute gets, and also slower than method calls such as get_fahrenheit(). This is particularly noticeable if you are dealing frequently with them, for example in rendering code for something that changes every X milliseconds. If you are merely using it as a convenience in an API for normal scripted tasks, I don't think they will be much of an issue, though. More on reddit.com
🌐 r/Python
44
172
March 3, 2014
@property or not?
Here’s the snippet of code im working with: class VolumeInfo(BaseModel): name: Path suffix: str format: str size: Size page_count: int pages: tuple[PageInfo, ...] = tuple() @property def… More on discuss.python.org
🌐 discuss.python.org
0
January 26, 2024
🌐
Real Python
realpython.com › python-property
Python's property(): Add Managed Attributes to Your Classes – Real Python
December 15, 2024 - It allows you to control attribute access, enabling features such as data validation, lazy evaluation, and the creation of backward-compatible APIs without modifying the class’s public interface. By using @property, you can avoid the clutter of getter and setter methods, keeping your code clean and Pythonic.
🌐
Programiz
programiz.com › python-programming › property
Python @property Decorator (With Examples)
Note: The actual temperature value is stored in the private _temperature variable. The temperature attribute is a property object which provides an interface to this private variable. In Python, property() is a built-in function that creates and returns a property object.
🌐
GeeksforGeeks
geeksforgeeks.org › python › python-property-function
Python property() function - GeeksforGeeks
July 11, 2025 - property() function in Python is a built-in function that returns an object of the property class. It allows developers to create properties within a class, providing a way to control access to an attribute by defining getter, setter and deleter ...
🌐
The Python Coding Stack
thepythoncodingstack.com › p › the-properties-of-python-property
The Properties of Python's `property`
April 1, 2025 - To do this, we can change .athlete_id from a data attribute into a property: ... We renamed the data attribute defined in the .__init__() method to ._athlete_id, with a leading underscore. The leading underscore identifies this attribute as non-public. It's not really a private attribute that cannot be accessed from outside the class – Python doesn't have private attributes – but it clearly shows the programmer's intent to any user of this class: this attribute is not meant to be accessed from outside the class.
Find elsewhere
🌐
Reddit
reddit.com › r/learnpython › what is the purpose of @property ?
r/learnpython on Reddit: What is the purpose of @property ?
November 17, 2017 -

Hi guys, I'm new to Python and I was curious if I define a class, what is the fuss with getattr, setattr and @property? I've read couple topics on stackexchange, but neither did motivate why I should use them. I mean I can define own functions to set something, and just use car.wheels to get the amount of wheels. No need to define an extra function car.getattr(wheels). What am I missing.

Top answer
1 of 5
20
Properties solve several problems. The main one is that they allow you to substitute a method call for an attribute access without changing the public API. That is important if you're dealing with large software projects where you can't break backwards compatibility. The method can contain arbitrary logic. For example, suppose that you wrote a class that stores a temperature. You initially wrote it to store temperate in Fahrenheit as a simple attribute, and you have lots of existing code that depends on that. But at some point you decide that you want it internally stored as Celsius. By using a computed property, you can change the internal representation to Celsius, while pretending to external users that it's still stored as Fahrenheit, by writing a getter method that dynamically computes the conversion. This is intentionally silly, but you can imagine more complex examples where you want to change the internal representation or other internal implementation details without affecting the public API. Another problem it solves is of validation. With a simple attribute, users can set any value. Again going back to the temperature example, someone might set the attribute to an invalid temperature. By using a setter of a property, you can intercept that attribute access and execute arbitrary logic to perform validation, raising an exception if they do something wrong. Arguably, the getting and setting in this case should have been written as methods in the first place, rather than attributes, but again you don't always have that kind of foresight, and often design decisions change and you need to make the change without breaking the API. Properties allow that.
2 of 5
2
Since a good explanation is given for properties, perhaps I can tackle getattr (and setattr by extension). Let's use your example - you have an object car with the attribute wheels. There are two ways to access this: car.wheels getattr(car, 'wheels') So why would you use the second form? Well, look at the second parameter - wheels is a string. Because the second parameter is a string, you can get attributes dynamically from an object. Imagine you wanted to have user input to allow the user to grab an attribute from car and print out that attribute. (A contrived example, I know.) You could do this: attribute = input("Type car attribute") print(getattr(car, attribute)) If the user types in wheels, then this script prints out car.wheels. But if the user types in doors, then this script prints out car.doors. I hope you can see - because we are using a string to access the object's attribute, you can do more dynamic things with this functionality.
🌐
W3Schools
w3schools.com › python › python_class_properties.asp
Python Class Properties
Python Examples Python Compiler ... Q&A Python Bootcamp Python Certificate Python Training ... Properties are variables that belong to a class....
🌐
Mimo
mimo.org › glossary › python › property
Python property(): Syntax, Usage, and Examples
A Python property is a special kind of attribute that lets you run code whenever it is accessed, set, or deleted. It allows you to expose what looks like a simple attribute to the user, while hiding the internal logic for getting or setting its value (getters and setters).
Top answer
1 of 8
153

In languages that rely on getters and setters, like Java, they're not supposed nor expected to do anything but what they say -- it would be astonishing if x.getB() did anything but return the current value of logical attribute b, or if x.setB(2) did anything but whatever small amount of internal work is needed to make x.getB() return 2.

However, there are no language-imposed guarantees about this expected behavior, i.e., compiler-enforced constraints on the body of methods whose names start with get or set: rather, it's left up to common sense, social convention, "style guides", and testing.

The behavior of x.b accesses, and assignments such as x.b = 2, in languages which do have properties (a set of languages which includes but is not limited to Python) is exactly the same as for getter and setter methods in, e.g., Java: the same expectations, the same lack of language-enforced guarantees.

The first win for properties is syntax and readability. Having to write, e.g.,

x.setB(x.getB() + 1)

instead of the obvious

x.b += 1

cries out for vengeance to the gods. In languages which support properties, there is absolutely no good reason to force users of the class to go through the gyrations of such Byzantine boilerplate, impacting their code's readability with no upside whatsoever.

In Python specifically, there's one more great upside to using properties (or other descriptors) in lieu of getters and setters: if and when you reorganize your class so that the underlying setter and getter are not needed anymore, you can (without breaking the class's published API) simply eliminate those methods and the property that relies on them, making b a normal "stored" attribute of x's class rather than a "logical" one obtained and set computationally.

In Python, doing things directly (when feasible) instead of via methods is an important optimization, and systematically using properties enables you to perform this optimization whenever feasible (always exposing "normal stored attributes" directly, and only ones which do need computation upon access and/or setting via methods and properties).

So, if you use getters and setters instead of properties, beyond impacting the readability of your users' code, you are also gratuitously wasting machine cycles (and the energy that goes to their computer during those cycles;-), again for no good reason whatsoever.

Your only argument against properties is e.g. that "an outside user wouldn't expect any side effects as a result of an assignment, usually"; but you miss the fact that the same user (in a language such as Java where getters and setters are pervasive) wouldn't expect (observable) "side effects" as a result of calling a setter, either (and even less for a getter;-). They're reasonable expectations and it's up to you, as the class author, to try and accommodate them -- whether your setter and getter are used directly or through a property, makes no difference. If you have methods with important observable side effects, do not name them getThis, setThat, and do not use them via properties.

The complaint that properties "hide the implementation" is wholly unjustified: most all of OOP is about implementing information hiding -- making a class responsible for presenting a logical interface to the outside world and implementing it internally as best it can. Getters and setters, exactly like properties, are tools towards this goal. Properties just do a better job at it (in languages that support them;-).

2 of 8
37

The idea is to allow you to avoid having to write getters and setters until you actually need them.

So, to start off you write:

class MyClass(object):
    def __init__(self):
        self.myval = 4

Obviously you can now write myobj.myval = 5.

But later on, you decide that you do need a setter, as you want to do something clever at the same time. But you don't want to have to change all the code that uses your class - so you wrap the setter in the @property decorator, and it all just works.

🌐
Reddit
reddit.com › r/python › python @property: how and why?
r/Python on Reddit: Python @property: How and Why?
March 3, 2014 - You pass arguments from python into the property, which is built in code and hopefully C, the property then checks if it has an fget, fset or fdel, if has one of those, it will call that method passing the arguments back into python code.
🌐
LinkedIn
linkedin.com › pulse › understanding-property-decorator-python-nuno-bispo-m7aee
Understanding the @property Decorator in Python
February 7, 2024 - The basis of Python's approach to object-oriented programming is the principle of encapsulation—the idea that data within an object should be accessible only through well-defined interfaces. This is where the @property decorator comes into play, offering a mechanism to control access to class attributes.
🌐
Python documentation
docs.python.org › 3 › howto › descriptor.html
Descriptor Guide — Python 3.14.3 documentation
January 30, 2026 - Subsequent improvements to the program require the cell to be recalculated on every access; however, the programmer does not want to affect existing client code accessing the attribute directly. The solution is to wrap access to the value attribute in a property data descriptor:
🌐
B-List
b-list.org › weblog › 2023 › dec › 21 › dont-use-python-property
Don't use Python's property
December 21, 2023 - In Python, on the other hand, you could write your class: class MyClass: value: int def __init__(self, value: int): self.value = value · And then when you later decide you need value to be a method, you can do that without forcing anyone else to change their code that used your class, by declaring it as a “property”:
🌐
Wisc
irc.wisc.edu › properties
Fluid Property Calculator
The Industrial Refrigeration Consortium is a collaborative effort between the University of Wisconsin-Madison and industry. Our goal is to improve the safety, efficiency, and productivity of industrial refrigeration systems and technologies.
🌐
NetworkX
networkx.org › documentation › stable › tutorial.html
Tutorial — NetworkX 3.6.1 documentation
Convenient access to all edges is achieved with the edges property. for (u, v, wt) in FG.edges.data('weight'): if wt < 0.5: print(f"({u}, {v}, {wt:.3})") ... Attributes such as weights, labels, colors, or whatever Python object you like, can be attached to graphs, nodes, or edges.
🌐
Plymouth Rock Assurance
plymouthrock.com › home
Plymouth Rock Assurance | Car Insurance and Home Insurance
October 1, 2024 - Plymouth Rock Assurance offers insurance quotes and coverage for your auto, home, motorcycle and more. Get a quote online today!
🌐
Astral
docs.astral.sh › ruff › settings
Settings | Ruff
For example, if you have a project with a minimum supported Python version of 3.9 but a subdirectory of developer scripts that want to use a newer feature like the match statement from Python 3.10, you can use per-file-target-version to specify "developer_scripts/*.py" = "py310".
🌐
Python.org
discuss.python.org › python help
@property or not? - Python Help - Discussions on Python.org
January 26, 2024 - Here’s the snippet of code im working with: class VolumeInfo(BaseModel): name: Path suffix: str format: str size: Size page_count: int pages: tuple[PageInfo, ...] = tuple() @property def smallest_page(self) -> PageInfo: data = {page.size: page for page in self.pages} return data[min(data.keys())] @property def median_page(self) -> PageInfo: from statistics import median_low data = {page.size: page for page in self.pages} ...