Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@classmethod can be stacked on @property, but @staticmethod cannot #89136

Closed
tusharsadhwani mannequin opened this issue Aug 22, 2021 · 2 comments
Closed

@classmethod can be stacked on @property, but @staticmethod cannot #89136

tusharsadhwani mannequin opened this issue Aug 22, 2021 · 2 comments
Assignees
Labels
3.9 only security fixes 3.10 only security fixes 3.11 only security fixes type-feature A feature request or enhancement

Comments

@tusharsadhwani
Copy link
Mannequin

tusharsadhwani mannequin commented Aug 22, 2021

BPO 44973
Nosy @rhettinger, @tusharsadhwani

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = 'https://github.com/rhettinger'
closed_at = <Date 2021-08-22.17:25:36.323>
created_at = <Date 2021-08-22.06:39:43.790>
labels = ['type-feature', '3.9', '3.10', '3.11']
title = '@classmethod can be stacked on @property, but @staticmethod cannot'
updated_at = <Date 2021-08-22.17:38:02.202>
user = 'https://github.com/tusharsadhwani'

bugs.python.org fields:

activity = <Date 2021-08-22.17:38:02.202>
actor = 'rhettinger'
assignee = 'rhettinger'
closed = True
closed_date = <Date 2021-08-22.17:25:36.323>
closer = 'rhettinger'
components = []
creation = <Date 2021-08-22.06:39:43.790>
creator = 'tusharsadhwani'
dependencies = []
files = []
hgrepos = []
issue_num = 44973
keywords = []
message_count = 2.0
messages = ['400051', '400081']
nosy_count = 2.0
nosy_names = ['rhettinger', 'tusharsadhwani']
pr_nums = []
priority = 'normal'
resolution = 'rejected'
stage = 'resolved'
status = 'closed'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue44973'
versions = ['Python 3.9', 'Python 3.10', 'Python 3.11']

@tusharsadhwani
Copy link
Mannequin Author

tusharsadhwani mannequin commented Aug 22, 2021

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.

@tusharsadhwani tusharsadhwani mannequin added 3.9 only security fixes 3.10 only security fixes 3.11 only security fixes type-feature A feature request or enhancement labels Aug 22, 2021
@rhettinger
Copy link
Contributor

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

@ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.9 only security fixes 3.10 only security fixes 3.11 only security fixes type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

1 participant