[Python-Dev] RE: PySequence_Contains

Guido van Rossum guido@digicool.com
Sat, 05 May 2001 16:48:33 -0500


> [Guido]
> > This kind of thing happens everywhere -- instances always define all
> > slots but using the slots sometimes fails when the corresponding
> > __foo__ doesn't exist.  Decisions based on the presence or absence of
> > a slot are therefore in general not reliable; the only exception is
> > the decision to *call* the slot or not.  The correct solution is not
> > to catch AttributeError and pretend that the slot didn't exist (which
> > would mask an AttributeError occurring inside the __contains__ method
> > if there was one),

[Tim]
> Ya, it sucks.  I was inspired by that instance_contains() itself makes
> dubious assumptions about what an AttributeError means when the functions
> *it* calls raise it <wink>.

Actually, instance_contains checks for AttributeError only after
calling instance_getattr(), whose only purpose is to return the
requested attribute or raise AttributeError, so here it is safe: the
__contains__ function hasn't been called yet.

> > but to reimplement the default behavior in the instance slot
> > implementation.
> 
> The "backward compatibility" comment in instance_contains() was scary:
> compatibility with *what*?

With previous behavior of 'x in instance'.  Before we had
__contains__, 'x in y' *always* iterated over the items of y as a
sequence, comparing them to x one at a time.  The loop does that.

> instance_contains() is pretty darn new.  I
> assumed it meant there was *some* good (but unidentified) reason we had to
> use PyObject_Cmp() instead of PyObject_RichCompareBool(..., Py_EQ) if
> instance_item() "worked".

No, that was probably just an oversight -- clearly it should have used
rich comparisons.  (I guess this is a disadvantage of the approach I'm
recommending here: if the default behavior changes, the
reimplementation of the default behavior in the class must be changed
too.)

> But I haven't thought of one, except to ensure
> that
> 
>     some_complex  in  some_instance_with___getitem__
> 
> continues to blow up -- but that's not a good reason.

Indeed not.

> So:
> 
> > In this case, that means that PySequence_Contains() can be simplified
> > (no need to test for AttributeError), and instance_contains() should
> > fall back to a loop over iter(self) rather than trying to use
> > instance_item().
> 
> Will do!

Thanks!

--Guido van Rossum (home page: http://www.python.org/~guido/)