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-subty... 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