On Fri, Sep 06, 2019 at 07:44:19PM +0000, Andrew Barnert wrote:

> > Union, and unions, are currently types:
> 
> > py> isinstance(Union, type)
> > True
> > 
> > py> isinstance(Union[int, str], type)
> > True
> 
> What version of Python are you using here?

Ah, I didn't realise that the behaviour has changed! I was using Python 
3.5, but I just tried again in 3.8:

py> isinstance(Union, type)
False

py> isinstance(Union[str, int], type)
False

So it seems that both the implementation and the interface of unions 
have changed radically between 3.5 and now. My mistake for assuming that 
backwards compatibility would have meant they were the same.

In 3.5:

py> Union.__bases__
(<class 'typing.Final'>,)
py> Union.__mro__
(typing.Union, <class 'typing.Final'>, <class 'object'>)
py> Union.__class__
<class 'typing.UnionMeta'>

In 3.8, the first two raise AttributeError, the third:

py> Union.__class__
<class 'typing._SpecialForm'>


I don't know the reason for this change, but in the absense of a 
compelling reason, I think it should be reversed.


Steven (me):

> > But I disagree that int|str is a subclass of int|str|bytes. There's 
> > no subclass relationship between the two: the (int|str).__bases__ 
> > won't include (int|str|bytes), 

Andrew replied:

> First, `issubclass` is about subtyping, not about declared inheritance.

That could be debated. help(subclass) says:

"Return whether 'cls' is a derived from another class or is the same 
class."

but of course ABCs and virtual subclassing do exist. My position is that 
in Python, issubclass is about inheritance, but you can fake it if you 
like, in which case "consenting adults" applies. If you do, it's still 
*subclassing*. If you want to call this "subtyping", I won't argue too 
strongly.

This Stackoverflow post:

https://stackoverflow.com/questions/45255270/union-types-in-scala-with-subtyping-ab-abc

suggests that Scala considers that int|str is *not* a subtype of 
int|str|bytes, but Scala.js considers that it is. I don't know if that 
distinction still applies, or why, or the arguments for or against 
treating int|str as a subtype of int|str|bytes, but if Scala treated it 
as *not* a subtype, I don't think the question is as cut-and-dried as 
you make out.

But I will point out that the name of the function is *issubclass*, not 
*issubtype*. If you want to test for a subtype relationship with unions, 
this should work:


# Python 3.5
py> Union[int, str].__union_set_params__ < Union[int, str, 
bytes].__union_set_params__
True


# Python 3.8
py> set(Union[int, str].__args__) < set(Union[int, str, bytes].__args__)
True


A little clunky, but if it were needed, we could improve the API. 
(Perhaps even by calling it "issubclass" as you say.)


-- 
Steven
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@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/5HIKI2BC6OIQUP3E67VFPXH5EFYJGCRN/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to