Message403653
Dear Raymond,
I think decorator chaining is a very useful concept. At the very least, if all decorators are functional (following the `functools.wraps` recipe), things work out great -- we even get associativity of function composition if things are done properly!
The question is: can we get similar behaviour when allowing decoration with stateful objects, i.e. classes? This seems a lot more difficult. At the very least, in the case of `@classmethod` I think one can formulate a straightforward desiderata:
### Expectation
- `classmethod(property)` should still be a `property`!
- More generally: `classmethod(decorated)` should always be a subclass of `decorated`!
Using your pure-python versions of property / classmethod from <https://docs.python.org/3.9/howto/descriptor.html>, I was able to write down a variant of `classmethod` that works mostly as expected in conjunction with `property`. The main idea is rewrite the `classmethod` to dynamically be a subclass of whatever it wrapped; roughly:
```python
def ClassMethod(func):
class Wrapped(type(func)):
def __get__(self, obj, cls=None):
if cls is None:
cls = type(obj)
if hasattr(type(self.__func__), '__get__'):
return self.__func__.__get__(cls)
return MethodType(self.__func__, cls)
return Wrapped(func)
```
I attached a full MWE. Unfortunately, this doesn't fix the `help` bug, though it is kind of weird because the decorated class-property now correctly shows up under the "Readonly properties" section. Maybe `help` internally checks `isinstance(cls.func, property)` at some point instead of `isinstance(cls.__dict__["func"], property)`?
### Some further Proposals / Ideas
1. Decorators could always have an attribute that points to whatever object they wrapped. For the sake of argument, let's take `__func__`.
⟹ raise Error when typing `@decorator` if `not hasattr(decorated, "__func__")`
⟹ Regular functions/methods should probably by default have `__func__` as a pointer to themselves?
⟹ This could hae several subsidiary benefits, for example, currently, how would you implement a pair of decorators `@print_args_and_kwargs` and `@time_execution` such that both of them only apply to the base function, no matter the order in which they are decorating it? The proposed `__func__` convention would make this very easy, almost trivial.
2. `type.__setattr__` could support checking if `attr` already exists and has `__set__` implemented.
⟹ This would allow true class-properties with `getter`, `setter` and `deleter`. I provide a MWE here: <https://mail.google.com/mail/u/0/#label/Python+Ideas/FMfcgzGlkPRbJVRkHHtkRPhMCxNsFHpl>
3. I think an argument can be made that it would be really, really cool if `@` could become a general purpose function composition operator?
⟹ This is already kind of what it is doing with decorators
⟹ This is already exacltly what it is doing in numpy -- matrix multiplication \*is\* the composition of linear functions.
⟹ In fact this is a frequently requested feature on python-ideas!
⟹ But here is probably the wrong place to discuss this. |
|
Date |
User |
Action |
Args |
2021-10-11 12:55:14 | randolf.scholz | set | recipients:
+ randolf.scholz, rhettinger, terry.reedy, berker.peksag, serhiy.storchaka, wim.glenn, corona10, AlexWaygood |
2021-10-11 12:55:14 | randolf.scholz | set | messageid: <1633956914.04.0.414158594898.issue45356@roundup.psfhosted.org> |
2021-10-11 12:55:14 | randolf.scholz | link | issue45356 messages |
2021-10-11 12:55:13 | randolf.scholz | create | |
|