3

I'm fairly new to python and have found that I need to query a list about whether it contains a certain item.
The majority of the postings I have seen on various websites (including this similar stackoverflow question) have all suggested something along the lines of

for i in list
    if i == thingIAmLookingFor
        return True

However, I have also found from one lone forum that

if thingIAmLookingFor in list
    # do work

works.

I am wondering if the if thing in list method is shorthand for the for i in list method, or if it is implemented differently.

I would also like to which, if either, is more preferred.

Community
  • 1
  • 1
DanBlakemore
  • 2,306
  • 2
  • 20
  • 23
  • 1
    `thingIAmLookingFor in list` is basically the same as iterating over the list and compare each element. Btw, don't name your variable `list`. – Felix Kling Oct 19 '11 at 23:01
  • Oh, so it is implemented with the same code as was suggested. Makes sense since lists aren't ordered. Also, in serious code, I always try to use meaningful names ;-]. – DanBlakemore Oct 19 '11 at 23:10
  • @DanBlakemore - it's implemented that way for lists, perhaps, but almost all other datatypes will implement it more appropriately. For instance, a dict doesn't iterate across all its keys. In this one particular case they happen to work alike. That's just a coincidence. – Kirk Strauser Oct 19 '11 at 23:12
  • @Kirk Strauser, I did follow the __contains__ hint from your other comment and discover that it is implemented for other python containers as well as available to be implemented for custom containers. – DanBlakemore Oct 19 '11 at 23:19

4 Answers4

4

In your simple example it is of course better to use in.

However... in the question you link to, in doesn't work (at least not directly) because the OP does not want to find an object that is equal to something, but an object whose attribute n is equal to something.

One answer does mention using in on a list comprehension, though I'm not sure why a generator expression wasn't used instead:

if 5 in (data.n for data in myList):
    print "Found it"

But this is hardly much of an improvement over the other approaches, such as this one using any:

if any(data.n == 5 for data in myList):
    print "Found it"
Community
  • 1
  • 1
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • true, there may be some cases where you need the loop. I'm not sure this example is one though. – Colin Coghill Oct 19 '11 at 22:58
  • The above solution using "any" is idiomatic Python (the one obvious way to do it). The other solution than runs "in" on a generator expression is atypical and non-pythonic. – Raymond Hettinger Oct 20 '11 at 23:11
2

the "if x in thing:" format is strongly preferred, not just because it takes less code, but it also works on other data types and is (to me) easier to read.

I'm not sure how it's implemented, but I'd expect it to be quite a lot more efficient on datatypes that are stored in a more searchable form. eg. sets or dictionary keys.

Colin Coghill
  • 1,549
  • 15
  • 18
  • 1
    `foo in bar` in shorthand for `bar.__contains__(foo)`. Any class can define `__contains__` to be an appropriately efficient search. For example, an SQL table wrapper could make `__contains__` execute an indexed database query returning a boolean value so you can search through millions of rows in a few milliseconds. – Kirk Strauser Oct 19 '11 at 23:09
  • 1
    With the standard CPython implementation, even on a list it can be expected to be more efficient in a constant-factor sense because the looping can be done internally in the C interpreter. – Karl Knechtel Oct 20 '11 at 01:19
1

The if thing in somelist is the preferred and fastest way.

Under-the-hood that use of the in-operator translates to somelist.__contains__(thing) whose implementation is equivalent to: any((x is thing or x == thing) for x in somelist).

Note the condition tests identity and then equality.

Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
1
for i in list
    if i == thingIAmLookingFor
        return True

The above is a terrible way to test whether an item exists in a collection. It returns True from the function, so if you need the test as part of some code you'd need to move this into a separate utility function, or add thingWasFound = False before the loop and set it to True in the if statement (and then break), either of which is several lines of boilerplate for what could be a simple expression.

Plus, if you just use thingIAmLookingFor in list, this might execute more efficiently by doing fewer Python level operations (it'll need to do the same operations, but maybe in C, as list is a builtin type). But even more importantly, if list is actually bound to some other collection like a set or a dictionary thingIAmLookingFor in list will use the hash lookup mechanism such types support and be much more efficient, while using a for loop will force Python to go through every item in turn.

Obligatory post-script: list is a terrible name for a variable that contains a list as it shadows the list builtin, which can confuse you or anyone who reads your code. You're much better off naming it something that tells you something about what it means.

Ben
  • 68,572
  • 20
  • 126
  • 174