6.5. Iterable Recap
Recap information about
tuple
,list
andset
tuple
- fast and memory efficientlist
- extensible and flexibleset
- unique elements, fast lookup
Why are there separate tuple and list data types? [2]
Lists and tuples, while similar in many respects, are generally used in fundamentally different ways. Tuples can be thought of as being similar to Pascal records or C structs; they're small collections of related data which may be of different types which are operated on as a group. For example, a Cartesian coordinate is appropriately represented as a tuple of two or three numbers.
Lists, on the other hand, are more like arrays in other languages. They
tend to hold a varying number of objects all of which have the same type
and which are operated on one-by-one. For example, os.listdir('.')
returns a list of strings representing the files in the current directory.
Functions which operate on this output would generally not break if you
added another file or two to the directory.
Tuples are immutable, meaning that once a tuple has been created, you can't replace any of its elements with a new value. Lists are mutable, meaning that you can always change a list's elements. Only immutable elements can be used as dictionary keys, and hence only tuples and not lists can be used as keys.
>>> data = [1, 2, 3]
>>> id(data)
4441671808
>>>
>>> data += [4, 5, 6]
>>> id(data)
4441671808
>>>
>>> data
[1, 2, 3, 4, 5, 6]
>>> data = (1, 2, 3)
>>> id(data)
4437523008
>>>
>>> data += (4, 5, 6)
>>> id(data)
4450573696
>>>
>>> data
(1, 2, 3, 4, 5, 6)
6.5.1. Tuple
Immutable - cannot add, modify or remove items
Stores elements of any type
Keeps order of inserting elements
Possible to getitem and slice
Elements can duplicate
One contingent block of data in memory
Whole tuple must be defined at once
6.5.2. List
Mutable - can add, remove, and modify items
Stores elements of any type
Keeps order of inserting elements
Possible to getitem and slice
Elements can duplicate
Implemented in memory as list of references to objects
Objects are scattered in memory
6.5.3. Set
Mutable - can add, remove, and modify items
Stores only hashable elements (int, float, bool, None, str, tuple)
Does not keep order of inserting elements
It is not possible to getitem and slice
Elements cannot duplicate
Set is unordered data structure and do not record element position or insertion
6.5.4. Memory Footprint
Python 3.12
Python 3.13
>>> from sys import getsizeof
>>>
>>>
>>> getsizeof( (1,2,3) )
64
>>>
>>> getsizeof( [1,2,3] )
88
>>>
>>> getsizeof( {1,2,3} )
216
6.5.5. Memory
6.5.6. Performance
Date: 2024-10-22
Python: 3.13.0
IPython: 8.28.0
System: macOS 15.0.1
Computer: MacBook M3 Max
CPU: 16 cores (12 performance and 4 efficiency) / 3nm
RAM: 128 GB RAM LPDDR5
O(n)
- lookup (contains) in list and tupleO(1)
- lookup (contains) in set
Short sequence of elements:
>>> %%timeit -r 10_000 -n 10_000 # doctest: +SKIP
... 0 in (1, 2, 3)
...
15.9 ns ± 1.51 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
15.8 ns ± 1.5 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
15.8 ns ± 1.35 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
>>> %%timeit -r 10_000 -n 10_000 # doctest: +SKIP
... 0 in [1, 2, 3]
...
15.9 ns ± 1.55 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
15.7 ns ± 0.957 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
15.8 ns ± 1.31 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
>>> %%timeit -r 10_000 -n 10_000 # doctest: +SKIP
... 0 in {1, 2, 3}
...
8.06 ns ± 1.07 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
8.03 ns ± 0.967 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
8.08 ns ± 0.997 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
Long sequence of elements:
>>> %%timeit -r 10_000 -n 10_000 # doctest: +SKIP
... 0 in (1, 2, 3, 4, 5, 6, 7, 8, 9)
...
35.3 ns ± 2.27 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
35.3 ns ± 2.3 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
35.3 ns ± 2.15 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
>>> %%timeit -r 10_000 -n 10_000 # doctest: +SKIP
... 0 in [1, 2, 3, 4, 5, 6, 7, 8, 9]
...
35.3 ns ± 2.32 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
35.3 ns ± 2.27 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
35.3 ns ± 2.05 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
>>> %%timeit -r 10_000 -n 10_000 # doctest: +SKIP
... 0 in {1, 2, 3, 4, 5, 6, 7, 8, 9}
...
8.05 ns ± 1.01 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
7.99 ns ± 0.973 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)
7.99 ns ± 0.903 ns per loop (mean ± std. dev. of 10000 runs, 10,000 loops each)