why not "'in' in 'in'"?

Tim Peters tim.one at comcast.net
Thu Jun 13 21:57:12 EDT 2002


[Grant Griffin]
> One of the things I like about Python is that it works as expected.
> However, I sometimes accidently expect it to allow one to use "in"
> to determine if one string is "in" another, e.g.:
>
> >>> 'in' in 'in'
>
> which yields a traceback:
>
>    Traceback (most recent call last):
>      File "<interactive input>", line 1, in ?
>    TypeError: 'in <string>' requires character as left operand
>
> ...
>
> So why is the "in" operator limited to single characters when used as a
> membership operator?

In The Beginning, "x in y" was implemented as if via:

def like_in(x, y):
    for element in y:
        if cmp(x, element) == 0:
            return 1
    return 0

That's still close(*) to what it does if the class of y doesn't implement
the newer-fangled __contains__ method.  Ponder what like_in(x, y) does when
x and y are strings:  it can't possibly return 1 unless x is a 1-character
string, because each value element takes on is a 1-character string.
Therefore "str1 in str2" raised an exception when len(str1) != 1, as you
almost certainly didn't intend to use this as an expensive and obscure way
to spell 0.  If that's what you really wanted, fine, but then Guido wanted
to help you achieve that goal by forcing you to use some way even more
expensive and obscure <wink>.

But that was then.  Python does allow defining __contains__ methods now,
precisely so that a type can define the meaning of "x in y" in whatever way
makes most sense for type(y).  The meaning of "in" is no longer *defined* by
like_in, and consequently Guido agrees that the string behavior is much
harder to justify now.

So if somebody wants this change enough to submit a patch (code, doc, + test
suite changes), it's likely to be accepted for 2.3.  As code changes go,
this one should be particularly easy.  We have an internal bet going as to
whether this invitation is enough to kill the idea <wink>.

some-parts-of-this-were-actually-true-ly y'rs  - tim


(*) The default implementation today uses "x == element" instead of cmp, so
that a type implementing only __eq__ works fine.  Other than that, same
thing.






More information about the Python-list mailing list