Jobu
Jobu

Reputation: 631

In Python 2.7, how should I check if I can use the `in` keyword to see if an object contains an item?

Before performing a test like

if something in the_object:
    ...

I would like to test if it's safe to use the in keyword on the_object. I believe that in will work in this usage if the_object has one of several methods such as __contains__ and __iter__.

Is there a test similar to the following I can use, but that checks for compatibility with in instead of containing __iter__?

import collections

if isinstance(the_object, collections.Iterable):
    if something in the_object:
        ...

Or should I just

try:
    if something in the_object:
        ...
except TypeError:
    # move on 

Upvotes: 0

Views: 172

Answers (1)

Jakob Lovern
Jakob Lovern

Reputation: 1341

Note: I have made this answer a CW post simply to mark this question as answered. The real credit goes to juanpa.arrivillaga and Nick A, in the comments.

It's easier to ask for forgiveness than permission

in looks to see of an object contains __contains__() first, then looks for __iter__(), then finally looks for __getitem__(). While you could check for each of them, doing a try...except would allow in to do it for you, or to error if it can't.

Here's the section that juanpa.arrivillaga linked to:

6.10.2. Membership test operations

The operators in and not in test for membership. x in s evaluates to True if x is a member of s, and False otherwise. x not in s returns the negation of x in s. All built-in sequences and set types support this as well as dictionary, for which in tests whether the dictionary has a given key. For container types such as list, tuple, set, frozenset, dict, or collections.deque, the expression x in y is equivalent to any(x is e or x == e for e in y).

For the string and bytes types, x in y is True if and only if x is a substring of y. An equivalent test is y.find(x) != -1. Empty strings are always considered to be a substring of any other string, so "" in "abc" will return True.

For user-defined classes which define the __contains__() method, x in y returns True if y.__contains__(x) returns a true value, and False otherwise.

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 raise IndexError exception. (If any other exception is raised, it is as if in raised that exception).

The operator not in is defined to have the inverse true value of in.

Upvotes: 1

Related Questions