isinstance() necessary and helpful, sometimes

Alex Martelli aleax at aleax.it
Fri Jan 25 22:55:32 CET 2002


Raymond Hettinger wrote:
        ...
> 1. It would be great to keep open the possibility of a SuperTable.

Yes.

> 2. hasattr() bugs me because I want to ensure that all of the expected
>     methods are available not just one.  Also, passing the attribute name
>     as a string has a bad feel to it though I can't say why.
> 3. except AttributeError runs the risk of trapping real errors.  It is too
>     all inclusive to be used safely as a means of making sure an object
>     has the required interface.

You don't need to pass the attribute name as a string, by using
'except AttributeError' in a way that avoids the risks of point 3.  I.e.,
rather than:

    if hasattr(x, 'myattr'):
        return floop(x.myattr(fleep()))
    else:
        return 2323

you could code:

    try:
        myattr = x.myattr
    except AttributeError:
        return 2323
    else:
        return floop(myattr(fleep()))

with basically the same semantics.  The first case has (to me) the
slight stylistic defect of doing (basically) the same work twice, in
that the work needed for hasattr(x,'myattr') somewhat duplicates
that later needed for the fetching of x.myattr.  The second one is
far from perfect either, of course, since the 'main' case is further
removed from where it should be (right up front).  But the rough
and concise alternative:
    try: return floop(x.myattr(fleep()))
    except AttributeError: return 2323
while having the great stylistic advantage of 'main case up front'
does run the risk of your point 3 -- hiding a "real" AttributeError
due to some bug inside functions fleep or floop or method
myattr (sigh).

> Executive Summary:  It would be darned nice if there were a
> straightforward way of assuring a that a particular interface were
> available but not require a particular object class.

Yes.  PEP 246 would, I think, be just the right way of providing
it: rather than just giving a yes/no answer it has the further
chance of wrapping the object as and if needed.

> I haven't looked inside the source code for iterator, but would expect to
> see something similar to the test hasattr(s,'next').  So, the point is

Hmmm, it's subtler than that -- see PyObject_GetIter in 
Objects/abstract.c.  Summing up, from slot tp_iter of the object's
type a pointer to a function is retrieved (if null, there's a further 
check for a sequence, which is then iter-wrapped differently).  
That function is called on the object and must return an
iterator (this is indeed checked, but throught the type again).

When the next-step is performed, this is how:

static PyObject *
slot_tp_iternext(PyObject *self)
{
        static PyObject *next_str;
        return call_method(self, "next", &next_str, "()");
}

which is basically just a call -- no hasattr check; an exception,
if need be, is just propagated (a NULL return, and the global
exception settings appropriately set).


Alex




More information about the Python-list mailing list