Hello, I try to implement a patch for ``isinstance()`` and ``issubclass()``. It's here <https://github.com/pprados/cpython/tree/updage_isinstance> (variation possible). I not patch mypy now <https://github.com/pprados/cpython/tree/updage_isinstance>
# Without patch and Tuple $ ./python -m timeit -s 'isinstance("",(int,str))' 50000000 loops, best of 5: 6.29 nsec per loop # With patch and Tuple $ ./python -m timeit -s 'isinstance("",(int,str))' 50000000 loops, best of 5: 5.27 nsec per loop # With patch and Union $ ./python -m timeit -s 'isinstance("",int|str)' 50000000 loops, best of 5: 5.23 nsec per loop Le sam. 7 sept. 2019 à 04:34, Andrew Barnert via Python-ideas < python-ideas@python.org> a écrit : > On Friday, September 6, 2019, 5:41:23 PM PDT, Steven D'Aprano < > st...@pearwood.info> wrote: > > >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: > > I didn't even consider that this might be an old feature that was taken > away, rather than a new feature that was added. Oh well, at least it gave > me an excuse to configure and build 3.9. :) > > > I don't know the reason for this change, but in the absense of a > > compelling reason, I think it should be reversed. > > My thinking is in the opposite direction. I'm assuming Guido or Jukka or > whoever wouldn't have made this change without a compelling reason. And if > we can't guess that reason, then someone (who cares more about pushing this > change than me) has to do the research or ask the right people to find out. > Without knowing that, we can't really decide whether it's worth reversing > for all types, or just for union types specifically, or whether the > proposal needs to be rethought from scratch (or scrapped, if that's not > possible), and the conservative default should be the last one. > > But hopefully the default won't matter, because someone will care enough > to find out the reasons and report them to us. (Or maybe Guido will just > see this discussion and have the answers on the top of his head.) > > > 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. > > But it's not just a "consenting adults" feature that users can do whatever > they want with, it's a feature that's used prevalently and fundamentally in > the standard library—including being the very core of typing.py—and always > with the consistent purpose of supporting (a couple of minor variations on > the idea of) subtyping. So sure, technically it is inheritance testing with > a bolt-on to add whatever you want (and of course historically, that _is_ > how it evolved), but in practice, it's subtype testing. > > Thanks to the usual practicality-beats-purity design, it isn't actually > testing _exactly_ subtype either, of course. After all, while it would be > silly to register `int` with `collections.abc.Sequence`, there's nothing > actually stopping you from doing so, and that obviously won't actually make > `int` a subtype of `Sequence`, but it will fool `issubclass` into believing > it is. But, except when you're intentionally breaking things for good or > bad reasons, what it tests is much closer to subtype than inheritance. In > fact, even when you break things for good reasons, often it's to better > match the subtyping expectation, not to violate it. (Consider `Sequence` > and `Mapping`, which act as if they were structural subtyping tests like > the other collection ABCs, despite the fact that it's actually impossible > to distinguish the two types that way so they cheat with a registry. Try > doing that with Swift or Go. :) > > > This Stackoverflow post: > > > > union types in scala with subtyping: A|B <: A|B|C > <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. > > Without reading the whole question carefully, and without refreshing my > fuzzy memory of Scala's type system, I think there are two things going on > here. > > First, the OP in that question seems to be trying to build his own > disjunction type that acts like a union in other languages (including, > apparently, Scala.js?), and he just didn't know how to code it right. > > So, why would anyone do that in the first place? Well, the bigger issue is > that Scala's unions aren't quite the same thing we're talking about here in > the first place—despite the fact that they're what inspired this whole > thread. In most languages, the union of int and str is a special type > that's defined by including all int values and all str values (and nothing > else), or something similar to that. In Scala, the union of int and str is > defined as the least upper bound of int and str on the lattice of all types > (which of course provably does include all int values and all str values, > because int and str are subtypes). In simple cases this ends up doing the > same thing. And when they differ, it's usually that Scala can infer > something cool that other languages can't. But I do vaguely remember one > case where Scala couldn't infer a type for me and (unlike, say, Haskell or > Kotlin—which may fail more often, but can always tell you exactly why they > failed and what you need to add to fix it) it couldn't tell that it > couldn't infer it, and it went and did something crazy like… an > infinitely-long compile that ate up all my disk space or something? I > forget. > > > But I will point out that the name of the function is *issubclass*, not > > *issubtype*. > > Sure, and the `class` statement creates a `type` instance. Which are > sometimes called `classes` and sometimes `types`. Since 2.3, all classes > are types and all types are classes, and the root of the metaclass > hierarchy is called `type`, and Python just mixes and matches the two words > arbitrarily, and it almost never causes confusion. (Of course in pre-2.3 > Python, they were completely unrelated things, and `issubclass` only worked > on classes, hence the name.) > > If you try and import a meaning from another language, then sometimes it > can get confusing. But think about it: in, say, Java, "subclass" explicitly > means only a concrete class inheriting implementation from another concrete > class; a class implementing an interface is not subclassing. Which means a > test for subclassing in the Java sense would be (a) not what Python does, > and (b) pointless. > _______________________________________________ > 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/F7BFCNAIRTHH5QRHIBACN7B5U2LLRBU4/ > Code of Conduct: http://python.org/psf/codeofconduct/ >
_______________________________________________ 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/ZLKFABJ4SSJJNHFXOELY2QJEON7J7NLV/ Code of Conduct: http://python.org/psf/codeofconduct/