On Thu, Jun 18, 2020 at 8:45 AM Luciano Ramalho <luciano@ramalho.org> wrote:
On Wed, Jun 17, 2020 at 9:31 PM Guido van Rossum <guido@python.org> wrote:
Could you please post a corrected version of the script?
The script and table are correct and were correct when I posted them.
Only parts of my description in my first e-mail had some errors when I wrongly reproduced some calls to issubclass().
I can't fix a message already sent, so I will write a blog post describing the problems more accurately. I apologize for the confusion.
Ah, sorry. Somehow Alex Martelli's post started a new thread in GMail and I didn't follow exactly what was going on; then I misread your reply as indicating that the script and table were wrong. My apologies!
Also, IMO the right way to test at runtime is still the numeric tower. The SupportsXxx classes are a crutch for static type checkers and their operational definition is "does the object have a __xxx__ method".
I understand that. The problem is that they are misleading, as the table shows.
Here an attempt to use typing.SupportsFloat:
c = 1+0j type(c) <class 'complex'> isinstance(c, typing.SupportsFloat) True float(c) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't convert complex to float sys.version_info sys.version_info(major=3, minor=8, micro=0, releaselevel='final', serial=0)
The opposite problem also occurs—a protocol says "no" but reality says "yes":
x = 1.1 isinstance(x, typing.SupportsComplex) False complex(x) (1.1+0j)
Thanks for your attention.
And thanks for the explanation -- your complaint is now much clearer. At *runtime* SupportsComplex and SupportsFloat and the others are predicated on "does it have a __complex__ / __float__ / etc. attribute." And float has no __complex__ method, but complex has a __float__ method, as well as an __int__ attribute -- both appear to be intended to give better error messages. However the runtime introspection implemented by typing's @runtime_checkable cannot introspect the true nature of these methods -- it just checks for their presence and returns True or False based on that. That's why SupportsFloat is a bad way to check for whether something "is" a float or even floatable. (Note that some strings are also floatable -- but SupportsFloat doesn't know.) As for why complex(x) works even though there's no x.__float__, that's because the complex() constructor accepts one or two floats as arguments and treats them as the real and imaginary parts. So I stick to my observation that the numeric tower is still the best way to check for a specific type of number, since all builtin types are registered as member of the appropriate level in the tower. What a type checker does is potentially different -- and Teddy Sudol's observation is correct that typeshed should be adjusted to set the return type of complex.__float__ and complex.__int__ to NoReturn. Somebody should probably send a PR their way. -- --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...>