Reputation: 866
I was wondering if some one could explain the difference between the "in" keyword of Python and the contains method
I was working with a sample list and found this behavior. When are the two supposed to be used? Is there some efficiency that can be achieved if I use one over the other.
>>> my_list = ["a", "b", "c"]
>>> my_list.__contains__("a")
True
>>> "a" in my_list
True
Upvotes: 5
Views: 9251
Reputation: 250981
Doing "a" in my_list
actually calls __contains__
method of my_list
if defined.
If __contains__
is not defined then __iter__
is used, if that's not defined then __getitem__
is used.
__contains__
is great way for some containers or iterables to implement fast membership check without looping through the whole sequence, for example range()
:
>>> %timeit 10**5 in range(10**9)
159 ns ± 1.16 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
https://docs.python.org/3/reference/expressions.html#membership-test-operations
For user-defined classes which define the
__contains__()
method,x in y
returnsTrue
ify.__contains__(x)
returns a true value, andFalse
otherwise.
For user-defined classes which do not define
__contains__()
but do define__iter__()
,x in y
isTrue
if some valuez
, for which the expressionx is z or x == z
is true, is produced while iterating overy
. If an exception is raised during the iteration, it is as ifin
raised that exception.
Lastly, the old-style iteration protocol is tried: if a class defines
__getitem__()
,x in y
isTrue
if and only if there is a non-negative integer indexi
such thatx is y[i] or x == y[i]
, and no lower integer index raises theIndexError
exception. (If any other exception is raised, it is as if in raised that exception).
Upvotes: 1
Reputation: 76634
The __contains__()
method of an an object is called when you use the in
statement.
For lists this is pre-defined, but you can also define your own class, add a __contains__
method and use in
on the instances of that class.
You should be using in
and not call __contains__()
directly.
Upvotes: 8
Reputation: 7944
From the docs:
For the list and tuple types, x in y is true if and only if there exists an index i such that x == y[i] is true.
string types, x in y is true if and only if x is a substring of y. An equivalent test is y.find(x) != -1.
For user-defined classes which define the
__contains__()
method, x in y is true if and only ify.__contains__(x)
is true.For user-defined classes which do not define
__contains__()
but do define__iter__()
, x in y is true if some value z with x == z is produced while iterating over y. If an exception is raised during the iteration, it is as if in raised that exception.Lastly, the old-style iteration protocol is tried: if a class defines
__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 raiseIndexError
exception.
Upvotes: 5
Reputation: 251408
Like most magic methods, the __contains__
method is not meant to be called directly. The reason __contains__
exists is precisely so that you can write obj in container
instead of having to use method-call syntax. So you should use obj in container
.
Upvotes: 2