6

I'm wondering whether there are any good reasons to prefer a list over a tuple or vice versa in python if statments. So the following are functionally equivalent but is one preferable to the other in terms of performance and coding style or does it not matter?

if x in (1,2,3):
    foo()

if x in [1,2,3]:
    foo()

I seem to have gotten into the habit of using tuples if there are 2 or 3 values and lists for anything longer, I think because in my experience tuples tend to be short and lists long, but this seems a bit arbitrary and probably needlessly inconsistent.

I'd be interested in any examples people can give of where one would be better than the other.

Cheers

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
redrah
  • 1,204
  • 11
  • 20
  • 3
    set is preferable to both here – GP89 Sep 13 '12 at 15:14
  • Possible dupe of [the difference between lists and tuples](http://stackoverflow.com/questions/626759/whats-the-difference-between-list-and-tuples-in-python) or [python list vs. tuple when to use each](http://stackoverflow.com/questions/1708510/python-list-vs-tuple-when-to-use-each). – DSM Sep 13 '12 at 15:15
  • 2
    sets are more suitable for membership testing, ie `if x in {1,2,3}:` (I think this syntax only works in py 2.6+, maybe 2.7+) – GP89 Sep 13 '12 at 15:18
  • In regards to performance, both list and tuples perform poorly when testing for membership (`if x in aList:`), especially as they grow large. If you are repeatedly testing for membership you probably want a `set`. – Steven Rumbalski Sep 13 '12 at 15:22
  • 3
    @DSM: I don't agree; the context of an `if foo in literal_sequence:` statement is significant, and the answer is to use a set, not a tuple or a list. Neither linked question has any bearing on that subject. – Martijn Pieters Sep 13 '12 at 15:28
  • @MartijnPieters: fair enough. – DSM Sep 13 '12 at 15:33
  • 3
    I did some timings and found that testing for membership in a set literal is *slower* than testing for membership in a tuple literal. This is probably due to the time it takes to create the set. The longer the set literal was, the worse the performance became, even when the items tested were not members of the set. The takeaway is that if you are going to create a set to test for membership only once, you're better off with a tuple. If you need to test more than once, then the set is preferred. – Steven Rumbalski Sep 13 '12 at 16:06

2 Answers2

5

The initialisation of a tuple (at least in CPython) produces less bytecode than a list - but it's really nothing to worry about. I believe membership testing is pretty much the same (although not tested it).

For purely membership testing the lookup semantics are the same. From Python 2.7 onwards, it's much nicer to write (and adds an implication that it's membership testing only):

if x in {1, 2, 3}:
    pass # do something

While prior to that:

if x in set([1,2,3]):
    pass # do something

just looked a little kludgy...

Jon Clements
  • 138,671
  • 33
  • 247
  • 280
  • Thanks for the explanation. To be honest I hadn't realised you could create a set using `{}` in 2.7, as you say the implication of membership testing with a set is far more satisfying! – redrah Sep 13 '12 at 15:33
  • 1
    I did some timings and found that testing for membership in a set literal is *slower* than testing for membership in a tuple literal. This is probably due to the time it takes to create the set. The longer the set literal was, the worse the performance became, even when the items tested were not members of the set. The takeaway is that if you are going to create a set to test for membership only once, you're better off with a tuple. If you need to test more than once, then the set is preferred. – Steven Rumbalski Sep 13 '12 at 16:07
  • 1
    @StevenRumbalski, glad you tested that -- I suspected as much. The key is that, as Jon Clements says above, "The initialisation of a tuple (at least in CPython) produces less bytecode than a list." It's not just that it takes longer to produce a tuple than a set; it's that the tuple is produced only once at compile time and then [folded](http://en.wikipedia.org/wiki/Constant_folding) into the bytecode as a constant -- which is possible, of course, because tuples are immutable. However, there's yet another complication: if the tuple contains mutable values, constant folding _doesn't_ happen. – senderle Sep 13 '12 at 16:25
  • @senderle +1 Very interesting, I'd wondered whether the immutability of tuples might have a bearing on performance. I'm guessing that the performance gains we're looking at here are fairly miniscule in most cases, but I do like to know what's going on behind the scenes! – redrah Sep 13 '12 at 16:36
  • @senderle: I just tested creating my set and tuple literals using variables instead of constants. The performance advantage of tuples decreased slightly, but did not go away. I could not test `set` with mutable values because they are not hashable. – Steven Rumbalski Sep 13 '12 at 16:55
  • @StevenRumbalski, ah, good, thanks! I'd love to see an answer to that effect posted here. – senderle Sep 13 '12 at 17:03
0

The difference between list and tuple is that lists are mutable and tuples are immutable.

People tend to use tuples for heterogenous collections, similar to structs in C, and lists being for homogenous collections, similar to arrays in C.

ronak
  • 1,770
  • 3
  • 20
  • 34