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/