SupportsString Protocol Type Annotation
Currently there are a few Protocols https://docs.python.org/3/library/typing.html#protocols defined in the typing module. One that I recently felt like was missing was a typing annotation for classes with a __str__() method defined. Seems like a fairly straightforward implementation. @runtime_checkable class SupportsString(Protocol): """An ABC with one abstract method __str__.""" __slots__ = () @abstractmethod def __str__(self) -> str: pass Perhaps there is another way to do this that I am missing?
The nice thing about Protocols is that they are so easy to define, you can just define them yourself. There's no need to have a "standard" protocol in typing.py for ever single dunder method in existence. PS. There's no need for `__slots__ = ()` assuming you're not going to inherit directly from it (there's really no point). On Tue, Oct 6, 2020 at 10:29 AM aleksiy123 <aleksiy123@gmail.com> wrote:
Currently there are a few Protocols https://docs.python.org/3/library/typing.html#protocols defined in the typing module. One that I recently felt like was missing was a typing annotation for classes with a __str__() method defined. Seems like a fairly straightforward implementation.
@runtime_checkable class SupportsString(Protocol): """An ABC with one abstract method __str__.""" __slots__ = () @abstractmethod def __str__(self) -> str: pass Perhaps there is another way to do this that I am missing? _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/C66MLT... Code of Conduct: http://python.org/psf/codeofconduct/
-- --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-change-the-world/>
On Tue, Oct 06, 2020 at 09:30:06AM -0700, aleksiy123 wrote:
Currently there are a few Protocols https://docs.python.org/3/library/typing.html#protocols defined in the typing module. One that I recently felt like was missing was a typing annotation for classes with a __str__() method defined. Seems like a fairly straightforward implementation.
Why do you care specifically about the `__str__` dunder? Calling str() is one of those protocols that should always succeed, whether the argument defines `__str__`, `__repr__`, or inherits from object. Ignoring the possibility of bugs or deliberate raising, I can't think of any object that doesn't support the str() protocol. Have I missed anything? -- Steve
On Tue, Oct 6, 2020 at 9:35 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Tue, Oct 06, 2020 at 09:30:06AM -0700, aleksiy123 wrote:
Currently there are a few Protocols https://docs.python.org/3/library/typing.html#protocols defined in the typing module. One that I recently felt like was missing was a typing annotation for classes with a __str__() method defined. Seems like a fairly straightforward implementation.
Why do you care specifically about the `__str__` dunder? Calling str() is one of those protocols that should always succeed, whether the argument defines `__str__`, `__repr__`, or inherits from object.
Ignoring the possibility of bugs or deliberate raising, I can't think of any object that doesn't support the str() protocol. Have I missed anything?
-- Steve
I was also finding this desire a little puzzling (and thought it might just be my inexperience). And since both `type` and `object` have a __str__ method*, it seems like the only way any object could NOT support the str() protocol would be to write a __str__ method and deliberately bust it. Right? Is there even a way to create a python object that does not have `__str__` in the MRO? Seeing as that is the case, and seeing as how the protocol system can't look inside your __str__ method to find out whether it is busted at type checking time, isn't `Any` all you'll ever need to type-hint the __str__ protocol? * and upon checking in fact it is the same __str__ method --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler
On Tue, Oct 6, 2020 at 6:50 PM Ricky Teachey <ricky@teachey.org> wrote:
On Tue, Oct 6, 2020 at 9:35 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Tue, Oct 06, 2020 at 09:30:06AM -0700, aleksiy123 wrote:
Currently there are a few Protocols https://docs.python.org/3/library/typing.html#protocols defined in the typing module. One that I recently felt like was missing was a typing annotation for classes with a __str__() method defined. Seems like a fairly straightforward implementation.
Why do you care specifically about the `__str__` dunder? Calling str()
is one of those protocols that should always succeed, whether the argument defines `__str__`, `__repr__`, or inherits from object.
Ignoring the possibility of bugs or deliberate raising, I can't think of any object that doesn't support the str() protocol. Have I missed anything?
I was also finding this desire a little puzzling (and thought it might just be my inexperience).
And since both `type` and `object` have a __str__ method*, it seems like the only way any object could NOT support the str() protocol would be to write a __str__ method and deliberately bust it. Right? Is there even a way to create a python object that does not have `__str__` in the MRO?
Seeing as that is the case, and seeing as how the protocol system can't look inside your __str__ method to find out whether it is busted at type checking time, isn't `Any` all you'll ever need to type-hint the __str__ protocol?
* and upon checking in fact it is the same __str__ method
There's somewhat a precedent -- though it's a questionable one (Luciano discovered this). It shows how tricky these things are though. There's a `typing.SupportsFoat` protocol that checks for the presence of a `__float__` method, and a `typing.SupportsComplex` protocol that checks for `__complex__`. Ironically, complex numbers have a `__float__` method that always fails, and floats don't have a `__complex__` method but complex(x) succeeds if x is a float... -- --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-change-the-world/>
07.10.20 06:04, Guido van Rossum пише:
Ironically, complex numbers have a `__float__` method that always fails, and floats don't have a `__complex__` method but complex(x) succeeds if x is a float...
I wonder why not remove complex.__float__ (and complex.__int__, complex.__floordiv__, etc)?
On Wed, Oct 7, 2020, 3:43 AM Serhiy Storchaka <storchaka@gmail.com> wrote:
07.10.20 06:04, Guido van Rossum пише:
Ironically, complex numbers have a `__float__` method that always fails, and floats don't have a `__complex__` method but complex(x) succeeds if x is a float...
I wonder why not remove complex.__float__ (and complex.__int__, complex.__floordiv__, etc)?
I wonder the same thing myself and I bet it gets complicated fast. I was trying to use the numbers module to type hint any number including both floats and decimal.Decimal the other evening. It doesn't work... type checkers don't know Decimal is a Number. Finally I discovered the correct current solution is just Union[Decimal, float] or Union[Decimal, float, Real] if you want to include other real numbers like fractions.Fraction. St first I was really annoyed but from what I was able to gather after some reading Monday evening, this is a known problem that is getting worked on and is because the abcs in the current numbers module are somewhat unusable for type hinting and need to be replaced/updated to make Number and friends into protocols. And I came away grateful there are smart people people working on this to make things better, rather than annoyed. I'll be interested to see what is come up with as a solution in 3.10.
On Wed, Oct 7, 2020 at 12:41 AM Serhiy Storchaka <storchaka@gmail.com> wrote:
07.10.20 06:04, Guido van Rossum пише:
Ironically, complex numbers have a `__float__` method that always fails, and floats don't have a `__complex__` method but complex(x) succeeds if x is a float...
I wonder why not remove complex.__float__ (and complex.__int__, complex.__floordiv__, etc)?
Usability in a different context. ```
z = 1j float(z) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't convert complex to float float(object()) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: float() argument must be a string or a number, not 'object'
If float(z) gave the second error message it would be rather confusing,
since z is a number. I guess the alternative would be to explicitly check
for complex in float() when producing the error message. (Or phrase it as
"real number", which actually might work.)
I think you have pointed into a reasonable way forward -- make the types
match the intention of the protocols better.
I'm not sure what to do about Decimal though. I suspect we will end up
making changes to both the numbers and decimal modules.
--
--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-change-the-world/>
07.10.20 18:43, Guido van Rossum пише:
Usability in a different context. ```
z = 1j float(z) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't convert complex to float float(object()) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: float() argument must be a string or a number, not 'object'
If float(z) gave the second error message it would be rather confusing, since z is a number. I guess the alternative would be to explicitly check for complex in float() when producing the error message. (Or phrase it as "real number", which actually might work.)
It is easy to fix. The trend is that functions which accept several different types of arguments should mention them all in a type error message instead of just the last one (e.g. "must be string, got 'complex'" while real numbers are accepted too). See https://bugs.python.org/issue41974.
I'm not sure what to do about Decimal though. I suspect we will end up making changes to both the numbers and decimal modules.
What are problems with Decimal?
participants (5)
-
aleksiy123
-
Guido van Rossum
-
Ricky Teachey
-
Serhiy Storchaka
-
Steven D'Aprano