On Wed, Aug 11, 2021 at 10:03 PM Larry Hastings <la...@hastings.org> wrote:
> Specifically: currently, decorators are called just after the function or 
> class object is created, before it's bound to a variable.  But we could 
> change it so that we first bind the variable to the initial value, then call 
> the decorator, then rebind.  That is, this code:
>
> @dekor8
> class C:
>     ...
>
> would become equivalent to this code:
>
> class C:
>     ...
> C = dekorate(C)
>
> This seems like it would solve the class self-reference problem--the "Node" 
> example above--when PEP 649 is active.

Critically, the decorator itself would have to be evaluated *before*
that assignment. So it would actually have to work out more like:

_tmp = dekor8
class C:
    ...
C = _tmp(C)

Otherwise things like "@foo.setter" would break.

> This approach shouldn't break reasonable existing code.  That said, this 
> change would be observable from Python, and pathological code could notice 
> and break.  For example:
>
> def ensure_Foo_is_a_class(o):
>     assert isinstance(Foo, type)
>     return o
>
> class Foo:
>     ...
>
> @ensure_Foo_is_a_class
> def Foo():
>     ...
>
> This terrible code currently would not raise an assertion.  But if we made 
> the proposed change to the implementation of decorators, it would.  I doubt 
> anybody does this sort of nonsense, I just wanted to fully flesh out the 
> topic.
>

You would be here declaring that a @monkeypatch decorator is terrible
code. I'm not sure whether you're right or wrong. You may very well be
right.

def monkeypatch(cls):
    basis = globals()[cls.__name__]
    for attr in dir(cls): setattr(basis, attr, getattr(cls, attr))
    return basis

@monkeypatch
class SomeClass:
    def new_method(self): ...

Currently this works, since SomeClass doesn't get assigned yet. This
could be made to work across versions by writing it as
@monkeypatch(SomeClass) instead (and then the actual class name would
become immaterial).

> If this approach seems interesting, here's one wrinkle to iron out.  When an 
> object has multiple decorators, would we want to re-bind after each decorator 
> call?  That is, would
>
> @dekor1
> @dekor2
> @dekor3
> class C:
>     ...
>
> turn into approach A:
>
> class C:
>     ...
> C = dekor1(dekor2(dekor3(C)))
>
> or approach B:
>
> class C:
>     ...
> C = dekor3(C)
> C = dekor2(C)
> C = dekor1(C)
>
> I definitely think "approach B" makes more sense.
>

If you're going to do it at all, best go the whole way. Each decorator
functions independently, and a decorated class is a class like any
other, so approach B makes far more sense to me.

ChrisA
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/KSXPPKYUPWYOGW2MROMQJRXPWBEH5BIW/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to