Here's how I would do this:

class ClassPropertyDescriptor(object):

    def __init__(self, fget, fset=None):
        self.fget = fget
        self.fset = fset

    def __get__(self, obj, klass=None):
        if klass is None:
            klass = type(obj)
        return self.fget.__get__(obj, klass)()

    def __set__(self, obj, value):
        if not self.fset:
            raise AttributeError("can't set attribute")
        type_ = type(obj)
        return self.fset.__get__(obj, type_)(value)

    def setter(self, func):
        if not isinstance(func, (classmethod, staticmethod)):
            func = classmethod(func)
        self.fset = func
        return self

def classproperty(func):
    if not isinstance(func, (classmethod, staticmethod)):
        func = classmethod(func)

    return ClassPropertyDescriptor(func)


class Bar(object):

    _bar = 1

    @classproperty
    def bar(cls):
        return cls._bar

    @bar.setter
    def bar(cls, value):
        cls._bar = value


# test instance instantiation
foo = Bar()
assert foo.bar == 1

baz = Bar()
assert baz.bar == 1

# test static variable
baz.bar = 5
assert foo.bar == 5

# test setting variable on the class
Bar.bar = 50
assert baz.bar == 50
assert foo.bar == 50

The setter didn't work at the time we call Bar.bar, because we are calling TypeOfBar.bar.__set__, which is not Bar.bar.__set__.

Adding a metaclass definition solves this:

class ClassPropertyMetaClass(type):
    def __setattr__(self, key, value):
        if key in self.__dict__:
            obj = self.__dict__.get(key)
        if obj and type(obj) is ClassPropertyDescriptor:
            return obj.__set__(self, value)

        return super(ClassPropertyMetaClass, self).__setattr__(key, value)

# and update class define:
#     class Bar(object):
#        __metaclass__ = ClassPropertyMetaClass
#        _bar = 1

# and update ClassPropertyDescriptor.__set__
#    def __set__(self, obj, value):
#       if not self.fset:
#           raise AttributeError("can't set attribute")
#       if inspect.isclass(obj):
#           type_ = obj
#           obj = None
#       else:
#           type_ = type(obj)
#       return self.fset.__get__(obj, type_)(value)

Now all will be fine.

Answer from Mahmoud Abdelkader on Stack Overflow
🌐
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....
Top answer
1 of 9
137

Here's how I would do this:

class ClassPropertyDescriptor(object):

    def __init__(self, fget, fset=None):
        self.fget = fget
        self.fset = fset

    def __get__(self, obj, klass=None):
        if klass is None:
            klass = type(obj)
        return self.fget.__get__(obj, klass)()

    def __set__(self, obj, value):
        if not self.fset:
            raise AttributeError("can't set attribute")
        type_ = type(obj)
        return self.fset.__get__(obj, type_)(value)

    def setter(self, func):
        if not isinstance(func, (classmethod, staticmethod)):
            func = classmethod(func)
        self.fset = func
        return self

def classproperty(func):
    if not isinstance(func, (classmethod, staticmethod)):
        func = classmethod(func)

    return ClassPropertyDescriptor(func)


class Bar(object):

    _bar = 1

    @classproperty
    def bar(cls):
        return cls._bar

    @bar.setter
    def bar(cls, value):
        cls._bar = value


# test instance instantiation
foo = Bar()
assert foo.bar == 1

baz = Bar()
assert baz.bar == 1

# test static variable
baz.bar = 5
assert foo.bar == 5

# test setting variable on the class
Bar.bar = 50
assert baz.bar == 50
assert foo.bar == 50

The setter didn't work at the time we call Bar.bar, because we are calling TypeOfBar.bar.__set__, which is not Bar.bar.__set__.

Adding a metaclass definition solves this:

class ClassPropertyMetaClass(type):
    def __setattr__(self, key, value):
        if key in self.__dict__:
            obj = self.__dict__.get(key)
        if obj and type(obj) is ClassPropertyDescriptor:
            return obj.__set__(self, value)

        return super(ClassPropertyMetaClass, self).__setattr__(key, value)

# and update class define:
#     class Bar(object):
#        __metaclass__ = ClassPropertyMetaClass
#        _bar = 1

# and update ClassPropertyDescriptor.__set__
#    def __set__(self, obj, value):
#       if not self.fset:
#           raise AttributeError("can't set attribute")
#       if inspect.isclass(obj):
#           type_ = obj
#           obj = None
#       else:
#           type_ = type(obj)
#       return self.fset.__get__(obj, type_)(value)

Now all will be fine.

2 of 9
73

If you define classproperty as follows, then your example works exactly as you requested.

class classproperty(object):
    def __init__(self, f):
        self.f = f
    def __get__(self, obj, owner):
        return self.f(owner)

The caveat is that you can't use this for writable properties. While e.I = 20 will raise an AttributeError, Example.I = 20 will overwrite the property object itself.

Discussions

properties - What's the difference between a Python "property" and "attribute"? - Stack Overflow
If the user of the class finds out about _x, they use it at their own risk. 2017-09-26T13:34:56.047Z+00:00 ... In general speaking terms a property and an attribute are the same thing. However, there is a property decorator in Python which provides getter/setter access to an attribute (or other ... More on stackoverflow.com
🌐 stackoverflow.com
When to use a property (rather than a method) in a class?
The simplest advice, kind of a rule of thumb, is that you should use a property (or a simple attribute) when the name of the thing is a noun ("height") and a method when the name of the thing is a verb ("make_taller"). Basically everybody finds it intuitive to remember that they need to call things whose names are doing words in order to do them. More on reddit.com
🌐 r/learnpython
28
45
December 15, 2023
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
Would you recommend using a property over a method when accessing a private attribute in python?
Are they often used in the professional world, Properties are fairly common, yes. if so what are the conditions needed, or its just something that's commonly done like the way its common to use f-strings. Basically you use a property if you want to apply some logic to attribute access. This could be many things, but some common reasons are validation, logging, and "dynamic attributes" which update based on other attributes. There's no reason to use a property just for the sake of using one. More on reddit.com
🌐 r/learnpython
14
0
September 13, 2024
🌐
Real Python
realpython.com › python-property
Python's property(): Add Managed Attributes to Your Classes – Real Python
December 15, 2024 - The @property decorator simplifies the management of attributes in your Python classes. It allows you to control attribute access, enabling features such as data validation, lazy evaluation, and the creation of backward-compatible APIs without ...
🌐
Python Course
python-course.eu › oop › implementing-a-custom-property-class.php
6. Implementing a Custom Property Class | OOP | python-course.eu
December 2, 2023 - When you run the code, you can see __init__ of 'our_property' will be called 'fget' set to a reference to the 'getter' function of 'city'. The attribute 'city' is an instance of the 'our_property' class. The 'our'property' class provides another decorator 'setter' for the setter functionality.
🌐
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.
🌐
GeeksforGeeks
geeksforgeeks.org › python › accessing-attributes-methods-python
Accessing Attributes and Methods in Python - GeeksforGeeks
March 29, 2025 - Attributes represent the properties or characteristics of an object, while methods define the actions or behaviors that an object can perform. Understanding how to access and manipulate both ...
Find elsewhere
🌐
Python documentation
docs.python.org › 3 › tutorial › classes.html
9. Classes — Python 3.14.3 documentation
Classes provide a means of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances of that type to be made. Each class instance can have attributes attached to it for maintaining its state.
🌐
Codearmo
codearmo.com › python-tutorial › properties
Properties in Python Classes | Codearmo
March 28, 2025 - Learn to create properties within Python classes including understanding the @property decorator, using getter, setter and delete within classes.
🌐
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 ...
🌐
PyPI
pypi.org › project › classproperty
classproperty · PyPI
Class properties let you define properties via the class statement. You define a dynamic property as if you were implementing a class.
      » pip install classproperty
    
🌐
Programiz
programiz.com › python-programming › property
Python @property Decorator (With Examples)
We can make objects out of this class and manipulate the temperature attribute as we wish: # Basic method of setting and getting attributes in Python class Celsius: def __init__(self, temperature=0): self.temperature = temperature def to_fahrenheit(self): return (self.temperature * 1.8) + 32 # Create a new object human = Celsius() # Set the temperature human.temperature = 37 # Get the temperature attribute print(human.temperature) # Get the to_fahrenheit method print(human.to_fahrenheit())
🌐
Reddit
reddit.com › r/learnpython › when to use a property (rather than a method) in a class?
r/learnpython on Reddit: When to use a property (rather than a method) in a class?
December 15, 2023 -

Suppose I had the class `vehicle` which represents a motor vehicle. Suppose the horsepower of the vehicle was not passed as an inputs but, with some detailed calculation, could be calculated from the other properties of the vehicle class. Would it be better to add `horsepower` as a property of the `vehicle` class, or as a method?

As a property, this might look something like this:

class Vehicle:

    def __init__(self, args):
        # Set args
        self._horsepower = None
    
    @property
    def horsepower(self):
        if self._horsepower is None:
            self._horsepower = calculate_horsepower()
        return self._horsepower

As a method, it may look like this:

class Vehicle:

    def __init__(self, args):
        # Set args

    def calculate_horsepower(self):
        # Calculate horsepower of instance vehicle

Which of the above is preferable?

In reality, horsepower is a property of a vehicle. However, if significant processing is required to calculate it then I'm not sure if it feels right to have it as a property of the `vehicle` 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).
🌐
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.
🌐
Python
peps.python.org › pep-0008
PEP 8 – Style Guide for Python Code | peps.python.org
Note 1: See the argument name recommendation above for class methods. For simple public data attributes, it is best to expose just the attribute name, without complicated accessor/mutator methods. Keep in mind that Python provides an easy path to future enhancement, should you find that a simple data attribute needs to grow functional behavior. In that case, use properties to hide functional implementation behind simple data attribute access syntax.
🌐
Quora
quora.com › How-do-you-define-and-use-properties-in-Python-classes
How to define and use properties in Python classes - Quora
Answer: Use [code ]@property[/code] to encapsulate attributes with getter/setter methods, enabling validation or computation. Example: [code]class Product: def __init__(self, price): self._price = price @property def price(self): return self._price @...
🌐
Medium
serdaralkancode.medium.com › various-styles-for-managing-or-accessing-your-attributes-properties-of-your-class-in-python-6d76d9b85af9
Various styles for managing or accessing your attributes/properties of your class in Python | by Serdar ALKAN | Medium
February 23, 2025 - If you remove setter methods or throw exception for setter method, only use @property methods. You make object read-only ... class Point: def __init__(self, x, y): self._x = x self._y = y @property def x(self): """The x property.""" print("Get x") return self._x @property def y(self): """The y property.""" print("Get y") return self._y
🌐
Reddit
reddit.com › r/learnpython › would you recommend using a property over a method when accessing a private attribute in python?
r/learnpython on Reddit: Would you recommend using a property over a method when accessing a private attribute in python?
September 13, 2024 -

I have been going through some books on classes to refresh my knowledge of Python, that's when I came across properties? Are they often used in the professional world, if so what are the conditions needed, or its just something that's commonly done like the way its common to use f-strings. Thanks in advance

🌐
Real Python
realpython.com › ref › builtin-functions › property
property() | Python’s Built-in Functions – Real Python
Here’s an example where you use property() to manage a circle’s radius and diameter. Note that the radius is a user-provided attribute while the diameter is a computed attribute: ... class Circle: def __init__(self, radius): self.radius = radius @property def radius(self): return self._radius @radius.setter def radius(self, value): self._radius = float(value) @property def diameter(self): return self.radius * 2 @diameter.setter def diameter(self, value): self.radius = value / 2 # Usage circle = Circle(10) print(circle.diameter) # Output: 20.0 circle.diameter = 30 print(circle.radius) # Output: 15.0