[Tutor] Handling function parameters of mixed object and basic types

Duncan Gibson duncan at thermal.esa.int
Mon Sep 4 14:07:14 CEST 2006


I wrote:
> >    def newOutput(x):
> >        if x is None:
> >            pass
> >            return
> >        try:
> >            x.output()
> >        except AttributeError:
> >            if isinstance(x, int):
> >                pass
> >            elif isinstance(x, float):
> >                pass
> >            elif isinstance(x, str):
> >                pass
> >            else:
> >                pass
> >
> > However, when I verified this example using timeit, the results
> > were completely unexpected. The time to resolve the objects
> > remains the same, but for the built-in types raising and catching
> > the exception means that resolution of built-in types takes 3 or
> > 4 times longer.

Alan replied:
> Yes, thats because whehn you call x.output when the method doesn't
> exist Python has to navigate the entire class heirarchy looking for 
> the missing method before it can return the exception.
> 
> The solution is to extend the logic you used for None - ie put all 
> the non object cases first, then, only if it is an object, use
> isinstance.

That was my first thought when I looked at this last week, and
just put all of the isinstance(built-in) tests at the top.

However, as mentioned in the original post, but maybe not very
clearly, there are some enumeration classes that derive from int,
so I have to check for those before I check for int:

    class EnumerationType(int):
        pass

    if x is None:
        pass
    elif isinstance(x, EnumerationType):
        pass
    elif isinstance(x, int):
        pass
    ...

And of course, there may be specific Enumeration type classes
to be tested before testing for the generic, so we end up back
at square one, having to know the class hierarchy so that we can
test in the correct order.

And that's why it was so disappointing to find that doing it
the OO way to improve the code might give such poor performance.

My colleague suggested using x.__class__ and below as an index
into a jump table, but this just perpetuates the unmaintainable
instead of letting Python's class mechanisms do all this for us.

The EnumerationType class claims to have 'low memory usage and
fast performance' but maybe we need to look at re-implementing
it to derive from object and not int. Unfortunately it's one of
the key abstractions in the code, and these enumerations are
used just about everywhere.

I'll need to see if other classes derive from built-in types too...

Cheers
Duncan
    


More information about the Tutor mailing list