Larry Hastings wrote: > On 8/11/21 2:48 AM, Jukka Lehtosalo wrote: > > On Wed, Aug 11, 2021 at 10:32 AM Thomas Grainger <tagr...@gmail.com > > mailto:tagr...@gmail.com> wrote: > > Larry Hastings wrote: > > > On 8/11/21 12:02 AM, Thomas Grainger wrote: > > > > I think as long as there's a test case for something like > > > > @dataclass > > > > class Node: > > > > global_node: ClassVar[Node | None] > > > > left: InitVar[Node | None] > > > > right: InitVar[None | None] > > > > > > > > the bug https://bugs.python.org/issue33453 > > <https://bugs.python.org/issue33453> and the current > > implementation > > https://github.com/python/cpython/blob/bfc2d5a5c4550ab3a2fadeb9459b4bd948ff6. > > <https://github.com/python/cpython/blob/bfc2d5a5c4550ab3a2fadeb9459b4bd948ff6.>.. > > shows this is a tricky problem > > > > The most straightforward workaround for this is to skip the > > decorator > > > syntax. With PEP 649 active, this code should work: > > > class Node: > > > global_node: ClassVar[Node | None] > > > left: InitVar[Node | None] > > > right: InitVar[None | None] > > > Node = dataclass(Node) > > > //arry/ > > > > the decorator version simply has to work > > > > > > > > I also think that it would be unfortunate if the decorator version > > wouldn't work. This is a pretty basic use case. > > So, here's an idea, credit goes to Eric V. Smith. What if we tweak how > decorators work, /juuuust sliiiightly/, so that they work like the > workaround code above? > 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. > 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. > 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. > //arry/
You mention that you wanted this to work also for non-type hint usage of annotations, and so a ForwardRef won't work. As such, would you also change this for function decorators so you can do this? ``` @decorator @typing.no_type_check def ham(spam: ham): ... So it means: ``` def ham(spam: ham): ... ham = typing.no_type_check(ham) ham = decorator(ham) ``` Obviously it's meaningless as a type hint, hence the no_type_check opt out _______________________________________________ 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/OJKTIGCHNFTW224O6OM4NIZ3OZBK2YQI/ Code of Conduct: http://python.org/psf/codeofconduct/