[Python-Dev] Re: PEP 649: Deferred Evaluation Of Annotations

2021年8月11日 05:03:41 -0700

On 8/11/21 2:48 AM, Jukka Lehtosalo wrote:
On Wed, Aug 11, 2021 at 10:32 AM Thomas Grainger <[email protected] <mailto:[email protected]>> 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/
_______________________________________________
Python-Dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/OA4J23TU3XACE5NAUUQNQQ52BXGNHUIS/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to