On Thu, Sep 5, 2019 at 9:31 PM Steven D'Aprano <st...@pearwood.info> wrote:
>
> On Thu, Sep 05, 2019 at 07:15:27PM +1000, Chris Angelico wrote:
>
> > Hang on hang on.... what's this situation where you're checking types
> > of a zillion objects?
>
> An earlier version of the statistics module used lots of isinstance
> checks in order to support arbitrary numeric types, and was a lot
> slower. The current version avoids most of those at the cost of being a
> lot less clear and elegant, but it improved performance somewhat.

That's fair, although if someone's concerned about squeaking the
performance as hard as possible, they'll probably be using numpy.

> On my PC, an isinstance check against a single concrete type (not an
> ABC) is about three times as expensive as a float arithmetic operation,
> so in a tight loop it may not be an insignificant cost.

How often do you check against a union type (or, in current code,
against a tuple of types)? This proposal wouldn't affect anything that
checks against a single type.

> > I think there's a bigger problem there than
> > whether isinstance(x, int|str) is slower than isinstance(x, (int,str))
> > ! Even if this change DOES have a measurable impact on the time to do
> > those checks, it only applies to unions, and if that's a notable
> > proportion of your total run time, maybe there's a better way to
> > architect this.
>
> Maybe... but in my experience, only at the cost of writing quite ugly
> code.

Perhaps. But for this to matter, you would need:
1) some sort of complicated dispatch handler that has to handle
subclasses (so you can't just look up type(x) in a dict)
2) handling of multiple types the same way (so you want to do union
isinstances rather than each one being done individually)
3) little enough other code that a performance regression in
isinstance makes a measurable difference
4) clean code that you don't want to disrupt for the sake of performance

Seems like a fairly uncommon case to me. Maybe I'm wrong.

> But having said all that, I'm not sure that we should be rejecting this
> proposal on the basis of performance when we haven't got any working
> code to measure performance of :)

Definitely. I don't think performance should be a major consideration
until code cleanliness has been proven or disproven.

> isinstance is a wrapper around PyObject_IsInstance(obj, class_or_tuple),
> and if I'm reading the C code correctly, PyObject_IsInstance is roughly
> equivalent to this Python pseudo-code:
>
>     # Except in C, not Python
>     def isinstance(obj, class_or_tuple):
>         if type(class_or_tuple) is tuple:
>             for C in class_or_tuple:
>                 if isinstance(obj, C):
>                     return True
>         else:
>             ...
>
>
> If Union is a built-in, we could have something like this:
>
>     def isinstance(obj, class_or_tuple):
>         if type(class_or_tuple) is Union:
>             class_or_tuple = class_or_tuple.__union_params__
>         # followed by the same code as above
>
> typing.Union already defines .__union_params__ which returns a tuple of
> the classes used to construct the union, so in principle at least, there
> need be no significant performance hit from supporting Unions.

That seems like a pretty good optimization!

ChrisA
_______________________________________________
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/AROEQ5Q74PC6MWBUBQQY2BP4HNTFP65A/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to