Randolf Scholz <randolf.sch...@gmail.com> added the comment:

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.

----------
Added file: https://bugs.python.org/file50344/ClassPropertyIdea.py

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue45356>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to