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.

classification
Title: @classmethod can be stacked on @property, but @staticmethod cannot
Type: enhancement Stage: resolved
Components: Versions: Python 3.11, Python 3.10, Python 3.9
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: rhettinger, tusharsadhwani
Priority: normal Keywords:

Created on 2021-08-22 06:39 by tusharsadhwani, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (2)
msg400051 - (view) Author: Tushar Sadhwani (tusharsadhwani) * Date: 2021-08-22 06:39
Starting with Python3.9, `@classmethod` can be stacked on top of `@property`, but it seems that `@staticmethod` cannot.


>>> class C:
...     @classmethod
...     @property
...     def cm(cls):
...         return cls.__name__

...     @staticmethod
...     @property
...     def magic_number():
...         return 42
... 
>>> C.cm
'C'
>>> C.magic_number
<property object at 0x7f0ad3c1ea90>
>>> 


This feels like inconsistent behaviour, plus, having staticmethod properties can be useful for creating read-only class attributes, for eg:


class C:
    @staticmethod
    @property
    def FINE_STRUCTURE_CONSTANT():
        return 1 / 137


This would make it hard to accidentally modify the constant inside the class.
msg400081 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2021-08-22 17:25
The classmethod and staticmethod decorators have somewhat different semantics.  Accessing a classmethod with C.cm creates a bound method object which has both __call__ and __get__.  In contrast, accessing a staticmethod with C.sm returns the underlying function.  So there is no opportunity for a customized __get__ method as we have with classmethod.

Also, even if C.sm did return a custom descriptor, the code example still can't be made to work because the __get__ method on property objects is hardwired to pass in an instance.¹  That means that the underlying method must have a "self" argument.  

Another issue is that properties have __set__ and __delete__ methods which could not be made to work without a reference to the class or instance.

To make a read-only class variable, a metaclass would be needed.  While it is possible to write a descriptor to make C.FINE_STRUCTURE_CONSTANT call a function that returns 1/137, there is no way for the descriptors to block the assignment:  C.FINE_STRUCTURE_CONSTANT = 1 / 100

Thanks for the suggestion, but I don't think this can be made to work.  

¹ https://docs.python.org/3/howto/descriptor.html#properties
History
Date User Action Args
2022-04-11 14:59:49adminsetgithub: 89136
2021-08-22 17:38:02rhettingersetassignee: rhettinger
2021-08-22 17:25:36rhettingersetstatus: open -> closed

nosy: + rhettinger
messages: + msg400081

resolution: rejected
stage: resolved
2021-08-22 06:39:43tusharsadhwanicreate