[IronPython] in operator calls __getitem__ on class that has __len__ and __iter__ defined
dinov at microsoft.com
Fri Nov 21 00:43:58 CET 2008
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.
From: users-bounces at lists.ironpython.com [mailto:users-bounces at lists.ironpython.com] 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.
> 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.
>> From: users-bounces at lists.ironpython.com
>> [mailto:users-bounces at lists.ironpython.com] On Behalf Of Glenn Jones
>> Sent: Thursday, November 20, 2008 7:23 AM
>> To: users at lists.ironpython.com
>> 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
>>>>> p = o()
>>>>> 1 in p
>> IronPython 2 source drop 43741:
>>>>> p = o()
>>>>> 1 in p
>> 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
>> Users at lists.ironpython.com
Users mailing list
Users at lists.ironpython.com
More information about the Ironpython-users