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
Properties defined outside methods belong to the class itself (class properties) and are shared by all objects:
🌐
Real Python
realpython.com › python-property
Python's property(): Add Managed Attributes to Your Classes – Real Python
December 15, 2024 - However, the decorator approach is more popular in the Python community. You can create a property by calling property() with an appropriate set of arguments and assigning its return value to a class attribute. All the arguments to property() are optional. However, you typically provide at least a getter function. The following example shows how to create a Circle class with a property that manages its radius:
People also ask

What is a Python namespace?

A Python namespace is a mapping from names to objects, with the property that there is zero relation between names in different namespaces. Namespaces are usually implemented as Python dictionaries, although this is abstracted away.

🌐
toptal.com
toptal.com › developers › python › python-class-attributes-an-overly-thorough-guide
Python Class Attributes: Examples of Variables | Toptal®
Python class method versus instance method: What’s the difference?

In Python, a class method is a method that is invoked with the class as the context. This is often called a static method in other programming languages. An instance method, on the other hand, is invoked with an instance as the context.

🌐
toptal.com
toptal.com › developers › python › python-class-attributes-an-overly-thorough-guide
Python Class Attributes: Examples of Variables | Toptal®
What happens if both instance attribute and class attribute are defined?

In that case, the instance namespace takes precedence over the class namespace. If there is an attribute with the same name in both, the instance namespace will be checked first and its value returned.

🌐
toptal.com
toptal.com › developers › python › python-class-attributes-an-overly-thorough-guide
Python Class Attributes: Examples of Variables | Toptal®
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.

🌐
Python documentation
docs.python.org › 3 › tutorial › classes.html
9. Classes — Python 3.14.3 documentation
In our example, the call x.f() is exactly equivalent to MyClass.f(x). In general, calling a method with a list of n arguments is equivalent to calling the corresponding function with an argument list that is created by inserting the method’s instance object before the first argument. In general, methods work as follows. When a non-data attribute of an instance is referenced, the instance’s class is searched.
🌐
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 ...
🌐
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). This is most commonly done using the @property decorator. ... class Temperature: def __init__(self, celsius): # Internal, "private" variable self._celsius = celsius # 1.
Find elsewhere
🌐
The Python Coding Stack
thepythoncodingstack.com › p › the-properties-of-python-property
The Properties of Python's `property`
April 1, 2025 - Let's see how this works before explaining what a property is: ... You use .athlete_id as if it were a data attribute. Note that you don't include parentheses after .athlete_id. In fact, anyone using this class doesn't need to know that .athlete_id is not an actual data attribute.
🌐
Toptal
toptal.com › developers › python › python-class-attributes-an-overly-thorough-guide
Python Class Attributes: Examples of Variables | Toptal®
March 5, 2014 - This Python guide outlines specific use cases for attributes, properties, variables, objects, and more.
🌐
Tutorial Teacher
tutorialsteacher.com › python › property-function
Python property() Method
The property() method in Python provides an interface to instance attributes. It encapsulates instance attributes and provides a property, same as Java and C#. The property() method takes the get, set and delete methods as arguments and returns an object of the property class. It is recommended to use the property decorator instead of the property() method. ... Returns the property attribute from the given getter, setter, and deleter. The following example ...
🌐
Python.org
discuss.python.org › python help
Use instance attributes or class properties inside the class definition? - Python Help - Discussions on Python.org
January 23, 2022 - Let’s say we have this class definition… class Student: def __init__(self): self._permission = False def go_to_party(self): if self._permission: print("Let's party!") else: print("I gotta study some more.") @property def permission(self): return self._permission @permission.setter def permission(self, parental_decision: bool): self._permission = parental_decision @property def is_permitted(self)...
🌐
GeeksforGeeks
geeksforgeeks.org › python › python-property-function
Python property() function - GeeksforGeeks
July 11, 2025 - Explanation: Employee class has a shared class attribute count, initialized to 0. The increase method increments count. Calling increase() on emp1 sets count to 1 and on emp2, it updates to 2. Printing emp1.count, emp2.count and Employee.count all return 2. Example 2. Using property() for encapsulation
🌐
Medium
elfi-y.medium.com › python-properties-and-class-methods-a6c7ad69b0f1
Python Properties and Class Methods | by E.Y. | Medium
January 10, 2021 - Instance Methods: The first methodmethod is an instance method. The parameter selfpoints to an instance of MyClass. It can also access the class itself through self.__class__ property.
🌐
Python Course
python-course.eu › oop › implementing-a-custom-property-class.php
6. Implementing a Custom Property Class | OOP | python-course.eu
We need another class to use the previously defined class and to demonstrate how the property class decorator works. To continue the tradition of the previous chapters of our Python tutorial we will again write a Robot class. We will define a property in this example class to demonstrate the ...
🌐
Machine Learning Plus
machinelearningplus.com › python › python-property
Python @Property Explained – How to Use and When? (Full Examples)
Similar to the setter, the deleter’s method defines what happens when a property is deleted. You can create the deleter method by defining a method of the same name and adding a @{methodname}.deleter decorator. See the implementation below. ... class Person(): def __init__(self, firstname, lastname): self.first = firstname self.last = lastname @property def fullname(self): return self.first + ' '+ self.last @fullname.setter def fullname(self, name): firstname, lastname = name.split() self.first = firstname self.last = lastname @fullname.deleter def fullname(self): self.first = None self.last
🌐
Python documentation
docs.python.org › 3 › howto › descriptor.html
Descriptor Guide — Python 3.14.3 documentation
The property() builtin helps whenever a user interface has granted attribute access and then subsequent changes require the intervention of a method. For instance, a spreadsheet class may grant access to a cell value through Cell('b10').value.
🌐
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.

🌐
Medium
gokulapriyan.medium.com › understanding-python-class-components-attributes-methods-and-properties-explained-1b83402098ed
🔍 Understanding Python Class Components: Attributes, Methods, and Properties Explained” | by Gokulapriyan | Medium
September 26, 2024 - These include instance methods, class methods, and static methods. Properties: Special methods to control access to attributes, typically used for encapsulation and adding validation logic. By understanding attributes, methods, and properties, you can create more structured and efficient Python ...
🌐
IONOS
ionos.com › digital guide › websites › web development › python property
How to use Python property - IONOS
July 20, 2023 - @property-name.deleter: Specifies the method that deletes a property ... If you are interested in advanced Python tutorials, check out the following articles in our Digital Guide: ... The following code snippet creates a class called “dog” with the attribute “_name”. While this example has no value in the real world, it helps to illustrate the functionality of Python property and how effective Python properties are.
🌐
StrataScratch
stratascratch.com › blog › how-to-use-python-property-decorator-with-examples
How to Use Python Property Decorator (With Examples) - StrataScratch
November 16, 2023 - You can use Python properties to do just that. class TemperatureModel: def __init__(self, initial_temperature): self._temperature = initial_temperature @property def temperature(self): return self._temperature @temperature.setter def ...