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.
๐ŸŒ
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.
๐ŸŒ
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....
Find elsewhere
๐ŸŒ
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
bugs.python.org โ€บ issue20659
Issue 20659: Want to make a class method a property by combining decorators - Python tracker
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
๐ŸŒ
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
๐ŸŒ
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 ...