Regardless of whether we pick shorthand, longhand or hybrid form, we need to decide on what the repr() of such an object would be. E.g. in an interactive session, if I print a callable type object, what will it print?
a = (int, int) -> int a (int, int) - int
or perhaps
a (__0: int, __1: int, /) -> int
or maybe
a callable[[int, int], int]
or
a <callable: (int, int) -> int>
??? -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>
a<callable: (int, int) -> int>I like this option best of the ones Guido gave (though I don't like the colon — but that's a minor nit). It's readable and consistent with the repr() of `inspect.Signature` objects. It's also clear, however, that it's representing something different from `inspect.Signature`.I wonder, though: does this feature have any use cases outside of type-hinting/variable annotations? If not, should the repr of these objects have some indication of that? A newbie to Python might (understandably) assume from this repr that these objects are... callable. Having the word "callable" in the repr might also breed confusion with the builtin `callable` function, as well, perhaps?Not sure I can think of anything better, however. Best, Alex -------- Original message --------From: Guido van Rossum <guido@python.org> Date: 27/10/2021 16:52 (GMT+00:00) To: None via Typing-sig <typing-sig@python.org>, S Pradeep Kumar <gohanpra@gmail.com> Subject: [Typing-sig] repr() of callable type Regardless of whether we pick shorthand, longhand or hybrid form, we need to decide on what the repr() of such an object would be. E.g. in an interactive session, if I print a callable type object, what will it print?>>> a = (int, int) -> int>>> a(int, int) - int>>> or perhaps>>> a(__0: int, __1: int, /) -> int>>> or maybe>>> acallable[[int, int], int]>>>
or>>> a<callable: (int, int) -> int>>>> ???-- --Guido van Rossum (python.org/~guido)Pronouns: he/him (why is my pronoun here?)
On Wed, Oct 27, 2021 at 11:36 AM Alex Waygood <alex.waygood@gmail.com> wrote:
a <callable: (int, int) -> int>
I like this option best of the ones Guido gave (though I don't like the colon — but that's a minor nit). It's readable and consistent with the repr() of `inspect.Signature` objects. It's also clear, however, that it's representing something different from `inspect.Signature`.
I wonder, though: does this feature have any use cases outside of type-hinting/variable annotations? If not, should the repr of these objects have some indication of that? A newbie to Python might (understandably) assume from this repr that these objects are... callable. Having the word "callable" in the repr might also breed confusion with the builtin `callable` function, as well, perhaps?
Not sure I can think of anything better, however.
One reason why I am favoring the first or second option is that we already have other types whose repr() is exactly what you enter (or at least a normalized version). In particular, repr(list[int]) == "list[int]", and so for all generic builtins, per PEP 585. (And these follow the PEP 484 example, since repr(typing.List[int]) == "typing.List[int]".) Indeed, PEP 604 follows the same pattern for the new union operator: repr(int | str) == "int | str". So I think we have considerable precedent here. (Generics and unions aren't used outside annotations either.) -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>
On Wed, Oct 27, 2021 at 11:01 PM Guido van Rossum <guido@python.org> wrote:
One reason why I am favoring the first or second option is that we already have other types whose repr() is exactly what you enter (or at least a normalized version).
A very good reason indeed, and not at all opinionated, for https://docs.python.org/3/reference/datamodel.html#object.__repr__:
If at all possible, this should look like a valid Python expression that could be used to recreate an object with the same value
Regards Kristoffel
On 27 Oct 2021, at 22:01, Guido van Rossum <guido@python.org> wrote:
One reason why I am favoring the first or second option is that we already have other types whose repr() is exactly what you enter (or at least a normalized version). In particular, repr(list[int]) == "list[int]", and so for all generic builtins, per PEP 585. (And these follow the PEP 484 example, since repr(typing.List[int]) == "typing.List[int]".) Indeed, PEP 604 follows the same pattern for the new union operator: repr(int | str) == "int | str". So I think we have considerable precedent here. (Generics and unions aren't used outside annotations either.)
That all makes sense. In that case, I prefer Option 1. It seems much prettier and clearer to me, and I don't see any particular advantages with Option 2. Best, Alex
Option 1 sounds good to me too. If we go with shorthand, then the data type representing it could remain `Callable`. Shorthand is just syntactic sugar for Callable. That would make it easier to reason about runtime behavior such as `f = (int) -> str`, because it would be equivalent to `f = Callable[[int], str]`. In Python versions with the new syntax, the `repr` for Callable would be `(int) -> str` and, in older versions, it would remain `typing.Callable[[int], str]`. On Thu, Oct 28, 2021 at 1:49 AM Alex Waygood <alex.waygood@gmail.com> wrote:
On 27 Oct 2021, at 22:01, Guido van Rossum <guido@python.org> wrote:
One reason why I am favoring the first or second option is that we already have other types whose repr() is exactly what you enter (or at least a normalized version). In particular, repr(list[int]) == "list[int]", and so for all generic builtins, per PEP 585. (And these follow the PEP 484 example, since repr(typing.List[int]) == "typing.List[int]".) Indeed, PEP 604 follows the same pattern for the new union operator: repr(int | str) == "int | str". So I think we have considerable precedent here. (Generics and unions aren't used outside annotations either.)
That all makes sense. In that case, I prefer Option 1. It seems much prettier and clearer to me, and I don't see any particular advantages with Option 2.
Best, Alex
-- S Pradeep Kumar
On Thu, Oct 28, 2021 at 3:21 PM S Pradeep Kumar <gohanpra@gmail.com> wrote:
Option 1 sounds good to me too.
Okay, let's go with that.
If we go with shorthand, then the data type representing it could remain `Callable`. Shorthand is just syntactic sugar for Callable. That would make it easier to reason about runtime behavior such as `f = (int) -> str`, because it would be equivalent to `f = Callable[[int], str]`. In Python versions with the new syntax, the `repr` for Callable would be `(int) -> str` and, in older versions, it would remain `typing.Callable[[int], str]`.
I think it will have to be a new implementation (in C), since it's not a good idea to have a built-in operation (which this certainly will be) return a type defined in a .py file. We did this for list[int] and int|str too; the types for that can be imported from the types (not typing!) module, under the names GenericAlias and UnionType. So perhaps types.CallableType? -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>
participants (4)
-
Alex Waygood
-
Guido van Rossum
-
Kristoffel Pirard
-
S Pradeep Kumar