3.8 < Python < 3.11

Can use both decorators together. See this answer.

Python 2 and python 3 (works in 3.9-3.10 too)

A property is created on a class but affects an instance. So if you want a classmethod property, create the property on the metaclass.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         pass
...     @classmethod
...     def getvar(cls):
...         return cls._var
...     @classmethod
...     def setvar(cls, value):
...         cls._var = value
...     
>>> foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func)
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

But since you're using a metaclass anyway, it will read better if you just move the classmethods in there.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         @property
...         def var(cls):
...             return cls._var
...         @var.setter
...         def var(cls, value):
...             cls._var = value
... 
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

or, using Python 3's metaclass=... syntax, and the metaclass defined outside of the foo class body, and the metaclass responsible for setting the initial value of _var:

>>> class foo_meta(type):
...     def __init__(cls, *args, **kwargs):
...         cls._var = 5
...     @property
...     def var(cls):
...         return cls._var
...     @var.setter
...     def var(cls, value):
...         cls._var = value
...
>>> class foo(metaclass=foo_meta):
...     pass
...
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3
Answer from A. Coady on Stack Overflow
Top answer
1 of 16
201

3.8 < Python < 3.11

Can use both decorators together. See this answer.

Python 2 and python 3 (works in 3.9-3.10 too)

A property is created on a class but affects an instance. So if you want a classmethod property, create the property on the metaclass.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         pass
...     @classmethod
...     def getvar(cls):
...         return cls._var
...     @classmethod
...     def setvar(cls, value):
...         cls._var = value
...     
>>> foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func)
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

But since you're using a metaclass anyway, it will read better if you just move the classmethods in there.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         @property
...         def var(cls):
...             return cls._var
...         @var.setter
...         def var(cls, value):
...             cls._var = value
... 
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

or, using Python 3's metaclass=... syntax, and the metaclass defined outside of the foo class body, and the metaclass responsible for setting the initial value of _var:

>>> class foo_meta(type):
...     def __init__(cls, *args, **kwargs):
...         cls._var = 5
...     @property
...     def var(cls):
...         return cls._var
...     @var.setter
...     def var(cls, value):
...         cls._var = value
...
>>> class foo(metaclass=foo_meta):
...     pass
...
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3
2 of 16
171

Update: The ability to chain @classmethod and @property was removed in Python 3.13 .

In Python 3.9 You could use them together, but (as noted in @xgt's comment) it was deprecated in Python 3.11, so it is not longer supported (but it may work for a while or reintroduced at some point).

Check the version remarks here:

https://docs.python.org/3.11/library/functions.html#classmethod

However, it used to work like so:

class G:
    @classmethod
    @property
    def __doc__(cls):
        return f'A doc for {cls.__name__!r}'

Order matters - due to how the descriptors interact, @classmethod has to be on top.

🌐
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.
Discussions

@property with @classmethod ?
There is no such thing as a property for classmethods. Sorry. You could just make another dictionary in Person: class Person(Node): _all_people = dict() def __init__(self): super().__init__() self._all_people[self.id] = self Or you could have a class method that takes an argument: class Node(object): _all_nodes = dict() def __init__(self): self.id = str(uuid.uuid4()) self._all_nodes[self.id] = self @staticmethod def all(cls): return {k: v for k, v in Node._all_nodes.items() if isinstance(v, cls)} print(Node.all(Person)) Or you could go the opposite way and store them in separate dictionaries: import uuid from collections import defaultdict class Node(object): _all_nodes = defaultdict(dict) def __init__(self): self.id = str(uuid.uuid4()) self._all_nodes[self.__class__][self.id] = self print(Node._all_nodes[Person]) Edit: my favorite is probably what you started with: just a normal classmethod in Node. Yeah, you need to add () to the end: class Node(object): _all_nodes = dict() def __init__(self): self.id = str(uuid.uuid4()) self._all_nodes[self.id] = self @classmethod def all(cls): return {k: v for k, v in Node._all_nodes.items() if isinstance(v, cls)} class Person(Node): pass print(Person.all()) More on reddit.com
🌐 r/learnpython
8
4
May 1, 2020
python - How to make a class property? - Stack Overflow
In python I can add a method to a class with the @classmethod decorator. Is there a similar decorator to add a property to a class? I can better show what I'm talking about. class Example(object... 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
classmethod properties are removed in Python 3.13
Problem description This was added in #519: numcodecs/numcodecs/zstd.pyx Lines 261 to 277 in 696e582 @classmethod @property def default_level(cls): """Returns the default compression level of the u... More on github.com
🌐 github.com
3
July 21, 2024
🌐
W3Schools
w3schools.com › python › python_class_properties.asp
Python Class Properties
Python Overview Python Built-in ... Q&A Python Bootcamp Python Certificate Python Training ... Properties are variables that belong to a class....
🌐
Reddit
reddit.com › r/learnpython › @property with @classmethod ?
r/learnpython on Reddit: @property with @classmethod ?
May 1, 2020 -

So I have a class that tracks all of its instances in a class-level dictionary that maps the ID numbers of the class, assigned at creation, to the class objects themselves:

import uuid

class Node(object):
    _all_nodes = dict()

    def __init__(self):
        self.id = str(uuid.uuid4())
        self._all_nodes[self.id] = self

So the class-level dictionary points at all instances of Nodes. Referencing the _all_nodes dictionary has become quite common in my code; it's the global store of data that the program is working with.

But all of the data stored in the _all_nodes class-level dictionary is actually instances of subclasses of Node, not direct instantiations of Node itself:

class Person(Node):
    ...
    # [many methods overridden]

It's frequently helpful to get a list, not of all Nodes, but of all Persons, so I wind up doing this a lot:

all_people = {k: v for k, v in Node._all_nodes.items() if isinstance(k, Person)}
# do something with all_people

In fact, I do it often enough that recreating that line has stopped involving thinking about anything other than how tedious it is to re-type, or hunt down again to copy and paste. It seems like the obvious thing to do is to bundle it into the Person class:

class Person(Node):
    def _all_people(self):
        return {k: v for k, v in Node._all_nodes.items() if isinstance(k, Person)}

The inconvenience of having to remember that Person._all_people is a function call (as are similar definitions in other subclasses), while Node._all_nodes refers directly to an attribute of an object, can be ameliorated by making _all_people a property to obscure the fact that it's a function call:

class Person(Node):
    @property
    def _all_people(self):
        return {k: v for k, v in Node._all_nodes.items() if isinstance(k, Person)}

This works, but there's a larger problem that prevents it from being useful: it requires an instance, rather than just the name of the class, in order to get access to the _all_people attribute. But if I really want a list of _all_people, I'm probably working on a higher-level task and don't happen to have an instance of Person ready to hand so that I can examine the property's returned value!

What I'd really like is to make the _all_people property callable from the class definition, without an instance, like it is with Node. But when I try this:

class Person(Node):
    @classmethod
    @property
    def _all_people(cls):
        return {p: cls._all_nodes[p] for p in cls._all_nodes if isinstance(cls._all_nodes[p], Person)}

I get code that runs, but doesn't effectively access the data: p = Person(); print(p._all_people) prints, not the dictionary, but rather <bound method ? of <class '__main__.Person'>>, which is not at all helpful.

Inverting the order of the @property and @classmethod decorators gives me the error TypeError: 'classmethod' object is not callable.

Is there some productive way that I can use @property and @classmethod to decorate the same method?

This is Python 3.5 under x64 Linux.

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.

🌐
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())
🌐
Medium
elfi-y.medium.com › python-properties-and-class-methods-a6c7ad69b0f1
Python Properties and Class Methods | by E.Y. | Medium
January 10, 2021 - Simply put, the property() method provides an interface to instance attributes, aka, getter , setter and deleter . ... Well, it is common to allow dynamically setting and getting an instance attribute when you build a class, e.g.
Find elsewhere
🌐
Python documentation
docs.python.org › 3 › tutorial › classes.html
9. Classes — Python 3.14.3 documentation
Creating a new class creates a ... attributes attached to it for maintaining its state. Class instances can also have methods (defined by its class) for modifying its state....
🌐
Tutorial Teacher
tutorialsteacher.com › python › property-function
Python property() Method
The property() function is used to define properties in the Python class. The property() method in Python provides an interface to instance attributes.
🌐
Mimo
mimo.org › glossary › python › property
Python property(): Syntax, Usage, and Examples
The property() built-in function in Python lets you manage how class attributes are accessed and modified. Instead of calling explicit getter method or setter method, you can create attributes that behave like regular variables but include custom logic behind the scenes.
🌐
Reintech
reintech.io › blog › python-practical-uses-for-property-method-tutorial
Python: Practical Uses for the property() Method | Reintech media
January 4, 2026 - The property() method is a built-in Python descriptor that transforms class methods into managed attributes. Rather than directly exposing object attributes, properties create a controlled interface that executes custom logic during attribute ...
🌐
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 - The method athlete_id that's decorated with the @property decorator is the getter for this attribute. It gets the attribute's value. The value is stored in the non-public ._athlete_id data attribute internally within the class, but it's accessed through the .athlete_id property, which uses the getter method.
🌐
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.

🌐
Toppr
toppr.com › guides › python-guide › references › methods-and-functions › python-property
Python property() function: Property python, python @property
October 18, 2021 - Python property() function is used to create a property of the class. Property python function is used in Python classes to define its properties by accepting getter, setter, and deleter methods.
🌐
LabEx
labex.io › tutorials › python-how-to-implement-python-class-properties-419513
How to implement Python class properties | LabEx
Property decorators provide a flexible way to define how class attributes are accessed, modified, and deleted. They allow you to create custom behavior for attribute interactions. class MyClass: def __init__(self): self._value = None @property ...
🌐
Python Tutorial
pythontutorial.net › home › python oop › python property
Python Property
March 31, 2025 - Similarly, when you read from the age property object, Python will execute the function assigned to the fget argument, which is the get_age() method. By using the property() class, we can add a property to a class while maintaining backward compatibility. In practice, you will define the attributes ...
🌐
GitHub
github.com › zarr-developers › numcodecs › issues › 553
classmethod properties are removed in Python 3.13 · Issue #553 · zarr-developers/numcodecs
July 21, 2024 - Problem description This was added in #519: numcodecs/numcodecs/zstd.pyx Lines 261 to 277 in 696e582 @classmethod @property def default_level(cls): """Returns the default compression level of the underlying zstd library.""" return ZSTD_d...
Author   QuLogic
🌐
Python
bugs.python.org › issue20659
Issue 20659: Want to make a class method a property by combining decorators - Python tracker
July 15, 2025 - This issue tracker has been migrated to GitHub, and is currently read-only. For more information, see the GitHub FAQs in the Python's Developer Guide · This issue has been migrated to GitHub: https://github.com/python/cpython/issues/64858
🌐
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 - Properties are defined using the @property decorator and allow you to expose an instance method like an attribute. ... class Person: def __init__(self, name): self._name = name @property def name(self): # Getter method, allows access to _name ...