python / cpython

The Python programming language
https://www.python.org
Other
63.4k stars 30.36k forks source link

Implement PEP 649 and PEP 749 #119180

Open JelleZijlstra opened 5 months ago

JelleZijlstra commented 5 months ago

PEP-649 has been accepted and should be implemented in Python 3.14. Let's use this issue to track the implementation:

Things to revisit:

I am planning to work on the interpreter core first.

cc @larryhastings @carljm @samuelcolvin

Linked PRs

Alc-Alc commented 3 months ago

PEP-649 has been accepted and should be implemented in PEP 649. Let's use this issue to track the implementation:

Just a clarification / nit, shouldn't the second occurrence of 649 actually be PEP 749?

JelleZijlstra commented 3 months ago

Thanks, I think I meant to say "in Python 3.14". Edited.

Jens-Dittrich commented 1 week ago

Hi everyone,

just wanted to share a (condensed) example where I had to use Forward references outside of type annotations, but in specific parameters of generics as below:

from typing import TypeVar, Generic

BaseClassType = TypeVar("BaseClassType")

class GenericClass(Generic[BaseClassType]):
    def a_method(self) -> BaseClassType:
        pass

class ConcreteClass(GenericClass["ConcreteFriendClass"]):
    pass

GenericClassType = TypeVar("GenericClassType", bound=GenericClass)

class GenericFriendClass(Generic[GenericClassType]):
    def a_method(self) -> GenericClassType:
        pass

class ConcreteFriendClass(GenericFriendClass[ConcreteClass]):
    pass

instance = ConcreteClass()
friend = ConcreteFriendClass()

res = instance.a_method()

Reason is, that ConcreteClass and ConcreteFriendClass are somehow coupled to each other from a business perspective. Not sure, the design is really great or could be improved, but what I want you guys to point you to is the statement of definition of Class ConcreteClass where the friend's class name is specified as forward reference. PyCharm is already able to correctly determine the type of variable res to be of ConcreteFriedClass - so it is at least ForwardReference-ish.

Question now, is this tbh quite corner case also in scope of the ticket, in that case I am glad to contribute above a test case. Just remove the Forward Reference in that line and it shall work. Or is it out of scope, maybe by a flaw of my own understanding or postponed to a later release etc.

EDIT: I just happened to realise that I can retrieve the type parameter at runtime in 3.12 and it turns out to be a Forward Reference

from typing import get_args, ForwardRef
from types import get_original_bases

assert ForwardRef("ConcreteFriendClass") == get_args(get_original_bases(ConcreteClass)[0])[0]

/EDIT

Happy to have a conversation on that.

Regards, Jens

JelleZijlstra commented 1 week ago

@Jens-Dittrich your use case is already solved in Python 3.12, where PEP-695 provides a syntax for generic bounds that is lazily evaluated. If you have further questions, please post on https://discuss.python.org instead so we can keep this issue focused on implementing the Python 3.14 changes.