Which is exactly what we're doing here. If you change your __getitem__ impl to return [0, 1, 2, 3][index] you'll see we call __getitem__ twice. We're just looking for __getitem__ before __iter__. Obviously CPython is doing it in the other order so we just need to switch that around.
-----Original Message----- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Michael Foord Sent: Thursday, November 20, 2008 3:34 PM To: Discussion of IronPython Subject: Re: [IronPython] in operator calls __getitem__ on class that has __len__ and __iter__ defined Michael Foord wrote: > Dino Viehland wrote: >> Interesting, the docs would seem to indicate our behavior is correct: >> >> For user-defined classes which do not define __contains__() and do >> define __getitem__(), x in y is true if and only if there is a >> non-negative integer index i such that x == y[i], and all lower >> integer indices do not raise IndexError exception. (If any other >> exception is raised, it is as if in raised that exception). >> >> If and only if is pretty strong language ☺ But we can start looking >> for __iter__ after looking for __contains__. >> > Wait. The definition above defines the conditions for 'in' with sequences (integer indexes) when __getitem__ is defined and __contains__ isn't. And in fact, the value 'x' is not passed to __getitem__ at all - but is *returned* from __getiem__ for an integer index 'i'. Passing 'x' to __getitem__ is definitely incorrect. :-) If a class defines __getitem__ and neither __iter__ nor __contains__ then Python will start calling __getitem__ with integers until x is returned or an IndexError is raised. Michael > It sounds like a doc bug then. > > 'in' has different meanings for mapping type containers (in refers to > keys) and sequences (in refers to values). For a sequence 'in' > naturally and obviously means 'is a value contained in the sequence', > and passing the value to __getitem__ clearly gives the wrong behaviour. > > For mapping types, passing the value to __getitem__ would be correct - > unfortunately there is no way to tell the types of containers apart if > they are pure Python classes (except in Python 2.6 where we have > Abstract Base Classes). Explicitly implementing __contains__ is always > better than relying on the fallback. > > Michael > >> From: [EMAIL PROTECTED] >> [mailto:[EMAIL PROTECTED] On Behalf Of Glenn Jones >> Sent: Thursday, November 20, 2008 7:23 AM >> To: [email protected] >> Subject: [IronPython] in operator calls __getitem__ on class that has >> __len__ and __iter__ defined >> >> Yet another weirdness, but not a blocker for us: >> >> With this object: >> >> class o(object): >> def __iter__(self): >> print "iter" >> return iter([1, 2, 3]) >> def __getitem__(self, index): >> print "getitem" >> return [1, 2, 3][index] >> def __len__(self): >> print "len" >> return 3 >> >> CPython: >> >>>>> p = o() >>>>> 1 in p >>>>> >> iter >> True >> >> IronPython 2 source drop 43741: >> >>>>> p = o() >>>>> 1 in p >>>>> >> getitem >> True >> >> It looks like CPython is treating it like a sequence and IronPython 2 >> is treating it like a dict. >> >> We have worked around this by implementing __contains__ >> >> Raised as Issue 19678 on CodePlex. >> >> >> PS: How can we format code blocks on CodePlex? >> >> Glenn & Orestis >> _______________________________________________ >> Users mailing list >> [email protected] >> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com >> > > -- http://www.ironpythoninaction.com/ http://www.voidspace.org.uk/blog _______________________________________________ Users mailing list [email protected] http://lists.ironpython.com/listinfo.cgi/users-ironpython.com _______________________________________________ Users mailing list [email protected] http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
