? 'in' operator and fallback to __getitem__

Discussion in 'Python' started by timh, May 18, 2009.

  1. timh

    timh Guest

    Hi

    I am trying to understand something about how the 'in' operator (as in
    the following expression)

    if 'aa' in x:
    do_something()

    When trying to implement in support on a class it appears that if
    __contains__ doesn't exist
    in falls back to calling __getitem__

    However strange things happen to the name passed to __getitem__ in the
    following example (and in fact in all varients I have triend the name/
    key passed to __getitem__ is always the integer 0

    For instance

    Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
    [GCC 4.3.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> class xx(object):

    .... def __getitem__(self,name):
    .... raise KeyError(name)
    ....
    >>> aa = xx()
    >>> aa['kk']

    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 3, in __getitem__
    KeyError: 'kk'
    >>> 'kk' in aa

    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 3, in __getitem__
    KeyError: 0


    I am running on ubuntu, and this happens to 2.5.4 as well. I must say
    I am surprised and
    am at a loss as to what is actually going on.

    Can anyone enlighten me (or should I go and read some 'c' code ;-)

    Rgds

    Tim
     
    timh, May 18, 2009
    #1
    1. Advertising

  2. timh wrote:

    > However strange things happen to the name passed to __getitem__ in the
    > following example (and in fact in all varients I have triend the name/
    > key passed to __getitem__ is always the integer 0


    I think it's scanning the container as a sequence and not as a mapping,
    hence the access by index.
     
    Marco Mariani, May 18, 2009
    #2
    1. Advertising

  3. timh

    Jeff McNeil Guest

    On May 18, 11:22 am, timh <> wrote:
    > Hi
    >
    > I am trying to understand something about how the 'in' operator (as in
    > the following expression)
    >
    > if 'aa' in x:
    >    do_something()
    >
    > When trying to implement in support on a class it appears that if
    > __contains__ doesn't exist
    > in falls back to calling __getitem__
    >
    > However strange things happen to the name passed to __getitem__ in the
    > following example (and in fact in all varients I have triend the name/
    > key passed to __getitem__ is always the integer 0
    >
    > For instance
    >
    > Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
    > [GCC 4.3.3] on linux2
    > Type "help", "copyright", "credits" or "license" for more information.>>> class xx(object):
    >
    > ...    def __getitem__(self,name):
    > ...       raise KeyError(name)
    > ...>>> aa = xx()
    > >>> aa['kk']

    >
    > Traceback (most recent call last):
    >   File "<stdin>", line 1, in <module>
    >   File "<stdin>", line 3, in __getitem__
    > KeyError: 'kk'>>> 'kk' in aa
    >
    > Traceback (most recent call last):
    >   File "<stdin>", line 1, in <module>
    >   File "<stdin>", line 3, in __getitem__
    > KeyError: 0
    >
    > I am running on ubuntu, and this happens to 2.5.4 as well.  I must say
    > I am surprised and
    > am at a loss as to what is actually going on.
    >
    > Can anyone enlighten me (or should I go and read some 'c' code ;-)
    >
    > Rgds
    >
    > Tim


    See http://docs.python.org/library/functions.html#iter, that ought to
    clear it up.

    Thanks,

    Jeff
    mcjeff.blogspot.com
     
    Jeff McNeil, May 18, 2009
    #3
  4. timh

    Tim Hoffman Guest

    Hi Marco

    Thats definately what I think is happening.

    I tried the following

    >>> class yy(object):

    .... def __getitem__(self,name):
    .... raise KeyError(name)
    .... def __contains__(self,name):
    .... raise KeyError(name)
    ....
    >>> aa = yy()
    >>> 'll' in aa

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    File "<stdin>", line 5, in __contains__
    KeyError: 'll'
    >>> [i in aa]

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    NameError: name 'i' is not defined
    >>> [i for i in aa]

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    File "<stdin>", line 3, in __getitem__
    KeyError: 0
    >>>



    Which suggests to me there must be some sort of order of precedence
    between __contains__ and __getitem__
    and 'for' statement must change the order in some manner.

    Thanks for the reply


    T

    On May 18, 11:24 pm, Marco Mariani <> wrote:
    > timh wrote:
    > > However strange things happen to the name passed to __getitem__ in the
    > > following example (and in fact in all varients I have triend the name/
    > > key passed to __getitem__ is always the integer 0

    >
    > I think it's scanning the container as a sequence and not as a mapping,
    > hence the access by index.
     
    Tim Hoffman, May 18, 2009
    #4
  5. timh

    Jeff McNeil Guest

    On May 18, 11:31 am, Tim Hoffman <> wrote:
    > Hi Marco
    >
    > Thats definately what I think is happening.
    >
    > I tried the following
    >
    > >>> class yy(object):

    >
    > ...   def __getitem__(self,name):
    > ...     raise KeyError(name)
    > ...   def __contains__(self,name):
    > ...     raise KeyError(name)
    > ...>>> aa = yy()
    > >>> 'll' in aa

    >
    > Traceback (most recent call last):
    >   File "<stdin>", line 1, in ?
    >   File "<stdin>", line 5, in __contains__
    > KeyError: 'll'>>> [i in aa]
    >
    > Traceback (most recent call last):
    >   File "<stdin>", line 1, in ?
    > NameError: name 'i' is not defined>>> [i for i in aa]
    >
    > Traceback (most recent call last):
    >   File "<stdin>", line 1, in ?
    >   File "<stdin>", line 3, in __getitem__
    > KeyError: 0
    >
    >
    >
    > Which suggests to me there must be some sort of order of precedence
    > between __contains__ and __getitem__
    > and 'for' statement must change the order in some manner.
    >
    > Thanks for the reply
    >
    > T
    >
    > On May 18, 11:24 pm, Marco Mariani <> wrote:
    >
    > > timh wrote:
    > > > However strange things happen to the name passed to __getitem__ in the
    > > > following example (and in fact in all varients I have triend the name/
    > > > key passed to __getitem__ is always the integer 0

    >
    > > I think it's scanning the container as a sequence and not as a mapping,
    > > hence the access by index.

    >
    >


    Whoops, I just realized I posted the wrong link...

    http://docs.python.org/reference/expressions.html#in

    Jeff
     
    Jeff McNeil, May 18, 2009
    #5
  6. timh

    Terry Reedy Guest

    Tim Hoffman wrote:

    >>>> [i for i in aa]

    > Traceback (most recent call last):
    > File "<stdin>", line 1, in ?
    > File "<stdin>", line 3, in __getitem__
    > KeyError: 0
    >
    >
    > Which suggests to me there must be some sort of order of precedence
    > between __contains__ and __getitem__
    > and 'for' statement must change the order in some manner.


    The 'in' part of for statements has nothing to do with the 'in'
    comparison operator. For loops first look for .__iter__ and .__next__
    and fall back to .__getitem__.
     
    Terry Reedy, May 18, 2009
    #6
  7. timh

    Dave Angel Guest

    Tim Hoffman wrote:
    >
    > Which suggests to me there must be some sort of order of precedence
    > between __contains__ and __getitem__
    > and 'for' statement must change the order in some manner.
    >
    > Thanks for the reply
    >
    >
    > T
    >
    >

    (Please don't top-post. It makes reading the quoted portions hard,
    since they're then out of order. To solve the problem here, I had to
    delete the other parts)

    "in" is both a keyword and an operator, with entirely different semantics.

    As a keyword, it's used inside a for statement, the expression (after
    the in) must return an iterable object.

    As an operator, it's used inside an arbitrary expression. It is this
    case which is described in the docs:

    >>>For user-defined classes which define the __contains__()

    <datamodel.html#object.__contains__> method, x in y is true if and only
    if y.__contains__(x) is true.

    >>>For user-defined classes which do not define __contains__()

    <datamodel.html#object.__contains__> and do define __getitem__(),
    <datamodel.html#object.__getitem__>
    >>> x in y is true if and only if there is a non-negative integer index

    /i/ such that x == y,
    >>> and all lower integer indices do not raise IndexError

    <../library/exceptions.html#exceptions.IndexError> exception. (If any
    other exception is
    >>>raised, it is as if in <#in> raised that exception).
     
    Dave Angel, May 18, 2009
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?ISO-8859-1?Q?Phil_H=FChn?=

    i18n: Fallback more than 1 locale?

    =?ISO-8859-1?Q?Phil_H=FChn?=, Jun 3, 2004, in forum: Java
    Replies:
    3
    Views:
    799
    =?ISO-8859-1?Q?Phil_H=FChn?=
    Jun 6, 2004
  2. Tim
    Replies:
    0
    Views:
    584
  3. Gerald Aichholzer

    xi:fallback and cocoon

    Gerald Aichholzer, May 18, 2004, in forum: XML
    Replies:
    0
    Views:
    436
    Gerald Aichholzer
    May 18, 2004
  4. =?iso-8859-1?q?Jean-Fran=E7ois_Michaud?=

    Fallback for indent aligned table that overflows?

    =?iso-8859-1?q?Jean-Fran=E7ois_Michaud?=, Jun 28, 2006, in forum: XML
    Replies:
    2
    Views:
    363
    =?iso-8859-1?q?Jean-Fran=E7ois_Michaud?=
    Jul 4, 2006
  5. Marian Schedenig

    Fallback Authenticator

    Marian Schedenig, Dec 3, 2007, in forum: Java
    Replies:
    0
    Views:
    314
    Marian Schedenig
    Dec 3, 2007
Loading...

Share This Page