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