4.1. Iterable Tuple

  • Immutable - cannot add, modify or remove items

  • Stores elements of any type

4.1.1. Syntax

  • data = () - empty tuple

  • data = (1, 2.2, 'abc') - tuple with values

  • data = () is faster than data = tuple()

Defining tuple() is more explicit, however empty tuple with () is used more often and it's also faster:

>>> data = ()
>>> data = tuple()

Can store elements of any type:

>>> data = (1, 2, 3)
>>> data = (1.1, 2.2, 3.3)
>>> data = (True, False)
>>> data = ('a', 'b', 'c')
>>> data = ('a', 1, 2.2, True, None)

Performance:

>>> %%timeit -r 10_000 -n 1000  
... data = ()
...
14.9 ns ± 3.28 ns per loop (mean ± std. dev. of 10000 runs, 1,000 loops each)
>>> %%timeit -r 10_000 -n 1000  
... data = tuple()
...
28.1 ns ± 8.17 ns per loop (mean ± std. dev. of 10000 runs, 1,000 loops each)

4.1.2. Type Conversion

  • tuple() - will convert its argument to tuple

  • Takes one iterable as an argument

  • Multiple arguments are not allowed

Builtin function tuple() converts argument to tuple

>>> text = 'hello'
>>> tuple(text)
('h', 'e', 'l', 'l', 'o')
>>> colors = ['red', 'green', 'blue']
>>> tuple(colors)
('red', 'green', 'blue')
>>> colors = ('red', 'green', 'blue')
>>> tuple(colors)
('red', 'green', 'blue')
>>> tuple('red', 'green', 'blue')
Traceback (most recent call last):
TypeError: tuple expected at most 1 argument, got 3

4.1.3. Optional Brackets

  • data = (1) - int

  • data = (1.) - float

  • data = (1,) - tuple

Brackets are optional, but it's a good practice to always write them:

>>> data = (1, 2, 3)
>>> data = 1, 2, 3

Single element tuple require comma at the end (important!):

>>> data = (1,)
>>> type(data)
<class 'tuple'>
>>> data = (1)
>>> type(data)
<class 'int'>

Comma after last element of multi value tuple is optional:

>>> data = (1, 2)
>>> type(data)
<class 'tuple'>
>>> data = (1, 2,)
>>> type(data)
<class 'tuple'>

4.1.4. Tuple or Int, Float, Str

  • data = 1.5 - float

  • data = 1,5 - tuple

  • data = (1) - int

  • data = (1.) - float

  • data = (1,) - tuple

>>> x = 1           # int
>>> x = 1.          # float
>>> x = 1,          # tuple
>>> x = (1)         # int
>>> x = (1.)        # float
>>> x = (1,)        # tuple
>>> x = 'one'       # str
>>> x = 'one',      # tuple
>>> x = 'one'.
Traceback (most recent call last):
SyntaxError: invalid syntax
>>> x = (12)        # int
>>> x = (1.2)       # float
>>> x = (1,2)       # tuple
>>> x = 1.,1.       # tuple
>>> x = 1.,.1       # tuple
>>> x = .1,1.       # tuple

4.1.5. Get Item

  • Returns a value at given index

  • Note, that Python start counting at zero (zero based indexing)

  • Raises IndexError if the index is out of range

  • More information in Iterable GetItem

  • More information in Iterable Slice

>>> colors = ('red', 'green', 'blue')
>>>
>>>
>>> colors[0]
'red'
>>>
>>> colors[1]
'green'
>>>
>>> colors[2]
'blue'

4.1.6. Index

  • tuple.index() - position at which something is in the tuple

  • Note, that Python start counting at zero (zero based indexing)

  • Raises ValueError if the value is not present

>>> colors = ('red', 'green', 'blue')
>>> result = colors.index('blue')
>>>
>>> print(result)
2

4.1.7. Count

  • tuple.count() - number of occurrences of value

>>> colors = ('red', 'green', 'blue', 'red', 'blue', 'red')
>>> result = colors.count('red')
>>>
>>> print(result)
3

4.1.8. Reverse

  • reversed() - Return a reverse iterator over the values of the given sequence

>>> values = (1, 2, 3)
>>> result = reversed(values)
>>>
>>> tuple(result)
(3, 2, 1)

4.1.9. Sort

  • sorted() - return a new list containing all items from the iterable in ascending order

  • Note, that the result will be a list, so we need to type cast

  • Reverse flag can be set to request the result in descending order

>>> values = (3, 1, 2)
>>> result = sorted(values)
>>>
>>> tuple(result)
(1, 2, 3)

4.1.10. Length

  • len() - Return the number of items in a container

>>> values = (1, 2, 3)
>>> result = len(values)
>>>
>>> print(result)
3

4.1.11. Built-in Functions

  • min() - Minimal value

  • max() - Maximal value

  • sum() - Sum of elements

  • len() - Length of a tuple

  • all() - All values are True

  • any() - Any values is True

List with numeric values:

>>> data = (3, 1, 2)
>>>
>>> len(data)
3
>>> min(data)
1
>>> max(data)
3
>>> sum(data)
6

List with string values:

>>> data = ('a', 'c', 'b')
>>>
>>> len(data)
3
>>> min(data)
'a'
>>> max(data)
'c'
>>> sum(data)
Traceback (most recent call last):
TypeError: unsupported operand type(s) for +: 'int' and 'str'

List with boolean values:

>>> data = (True, False, True)
>>>
>>> any(data)
True
>>> all(data)
False

4.1.12. Memory

  • Tuple is immutable (cannot be modified)

  • Whole tuple must be defined at once

  • Uses one consistent block of memory

>>> import sys
>>>
>>>
>>> data = (1, 2, 3)
>>> sys.getsizeof(data)
64
../../_images/memory-tuple.png

Figure 4.1. Memory representation for tuple

4.1.13. Recap

  • Immutable - cannot add, modify or remove items

  • Stores elements of any type

  • Fast and memory efficient

4.1.14. Assignments

Code 4.1. Solution
"""
* Assignment: Iterable Tuple Create
* Type: class assignment
* Complexity: easy
* Lines of code: 5 lines
* Time: 5 min

English:
    1. Create tuples:
        a. `result_a` without elements
        b. `result_a` with elements: 1, 2, 3
        c. `result_b` with elements: 1.1, 2.2, 3.3
        d. `result_c` with elements: 'a', 'b', 'c'
        e. `result_d` with elements: True, False
        f. `result_e` with elements: 1, 2.2, True, 'a'
    2. Run doctests - all must succeed

Polish:
    1. Stwórz tuple:
        a. `result_a` bez elementów
        b. `result_a` z elementami: 1, 2, 3
        c. `result_b` z elementami: 1.1, 2.2, 3.3
        d. `result_c` z elementami: 'a', 'b', 'c'
        e. `result_d` z elementami: True, False, True
        f. `result_e` z elementami: 1, 2.2, True, 'a'
    2. Uruchom doctesty - wszystkie muszą się powieść

Tests:
    >>> import sys; sys.tracebacklimit = 0

    >>> assert result_a is not Ellipsis, \
    'Assign your result to variable `result_a`'
    >>> assert result_b is not Ellipsis, \
    'Assign your result to variable `result_b`'
    >>> assert result_c is not Ellipsis, \
    'Assign your result to variable `result_c`'
    >>> assert result_d is not Ellipsis, \
    'Assign your result to variable `result_d`'
    >>> assert result_e is not Ellipsis, \
    'Assign your result to variable `result_e`'
    >>> assert result_f is not Ellipsis, \
    'Assign your result to variable `result_f`'

    >>> assert type(result_a) is tuple, \
    'Variable `result_a` has invalid type, should be tuple'
    >>> assert type(result_b) is tuple, \
    'Variable `result_b` has invalid type, should be tuple'
    >>> assert type(result_c) is tuple, \
    'Variable `result_c` has invalid type, should be tuple'
    >>> assert type(result_d) is tuple, \
    'Variable `result_d` has invalid type, should be tuple'
    >>> assert type(result_e) is tuple, \
    'Variable `result_e` has invalid type, should be tuple'
    >>> assert type(result_f) is tuple, \
    'Variable `result_f` has invalid type, should be tuple'

    >>> assert result_a == (), \
    'Variable `result_a` has invalid value, should be ()'
    >>> assert result_b == (1, 2, 3), \
    'Variable `result_b` has invalid value, should be (1, 2, 3)'
    >>> assert result_c == (1.1, 2.2, 3.3), \
    'Variable `result_c` has invalid value, should be (1.1, 2.2, 3.3)'
    >>> assert result_d == ('a', 'b', 'c'), \
    'Variable `result_d` has invalid value, should be ("a", "b", "c")'
    >>> assert result_e == (True, False, True), \
    'Variable `result_e` has invalid value, should be (True, False, True)'
    >>> assert result_f == (1, 2.2, True, 'a'), \
    'Variable `result_f` has invalid value, should be (1, 2.2, True, "a")'
"""

# Tuple without elements
# type: tuple
result_a = ...

# Tuple with elements: 1, 2, 3
# type: tuple[int]
result_b = ...

# Tuple with elements: 1.1, 2.2, 3.3
# type: tuple[float]
result_c = ...

# Tuple with elements: 'a', 'b', 'c'
# type: tuple[str]
result_d = ...

# Tuple with elements: True, False
# type: tuple[bool]
result_e = ...

# Tuple With elements: 1, 2.2, True, 'a'
# type: tuple[int|float|bool|str]
result_f = ...

Code 4.2. Solution
"""
* Assignment: Iterable Tuple Select
* Type: class assignment
* Complexity: easy
* Lines of code: 1 lines
* Time: 5 min

English:
    1. Define `result: tuple` representing all species
    2. To convert table use multiline select with `alt` or `alt+shift`
       key in your IDE
    3. Do not use `slice`, `getitem`, `for`, `while` or any other
       control-flow statement
    4. Run doctests - all must succeed

Polish:
    1. Zdefiniuj `result: tuple` z nazwami gatunków
    2. Do konwersji tabelki wykorzystaj zaznaczanie wielu linijek za pomocą
       klawisza `alt` lub `alt+shift` w Twoim IDE
    3. Nie używaj `slice`, `getitem`, `for`, `while` lub jakiejkolwiek innej
       instrukcji sterującej
    4. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * `ALT` + `left mouse button` = multiple select
    * `ALT` + `SHIFT` + `left mouse button drag` = vertical selection

Tests:
    >>> import sys; sys.tracebacklimit = 0

    >>> assert result is not Ellipsis, \
    'Assign your result to variable `result`'
    >>> assert type(result) is tuple, \
    'Variable `result` has invalid type, should be tuple'
    >>> assert all(type(x) is str for x in result), \
    'All elements in result should be str'
    >>> assert len(result) == 5, \
    'Variable `result` length should be 5'
    >>> assert result.count('virginica') == 2, \
    'Result should have 2 elements of virginica'
    >>> assert result.count('setosa') == 1, \
    'Result should have 1 element of setosa'
    >>> assert result.count('versicolor') == 2, \
    'Result should have 2 elements of versicolor'

    >>> assert ('sepal_length' not in result
    ...     and 'sepal_width' not in result
    ...     and 'petal_length' not in result
    ...     and 'petal_width' not in result
    ...     and 'species' not in result)
"""

DATA = [
    'sepal_length,sepal_width,petal_length,petal_width,species',
    '5.8,2.7,5.1,1.9,virginica',
    '5.1,3.5,1.4,0.2,setosa',
    '5.7,2.8,4.1,1.3,versicolor',
    '6.3,2.9,5.6,1.8,virginica',
    '6.4,3.2,4.5,1.5,versicolor',
]

# Tuple with species names
# type: tuple[str]
result = ...

Code 4.3. Solution
"""
* Assignment: Iterable Tuple Mean
* Type: homework
* Complexity: medium
* Lines of code: 8 lines
* Time: 8 min

English:
    1. Calculate mean for each numerical values column
    2. To convert table use multiline select with `alt` key in your IDE
    3. Do not use `str.split()`, `slice`, `getitem`, `for`, `while`
       or any other control-flow statement
    4. Run doctests - all must succeed

Polish:
    1. Wylicz średnią arytmetyczną dla każdej z kolumn numerycznych
    2. Do konwersji tabelki wykorzystaj zaznaczanie wielu linijek
       za pomocą klawisza `alt` w Twoim IDE
    3. Nie używaj `str.split()`, `slice`, `getitem`, `for`, `while`
       lub jakiejkolwiek innej instrukcji sterującej
    4. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * `mean = sum(...) / len(...)`
    * `ALT` + `left mouse button` = multiple select
    * `ALT` + `SHIFT` + `left mouse button drag` = vertical selection
    * `ALT` + `SHIFT` + `right` = select word to the right (macOS)
    * `ALT` + `SHIFT` + `left` = select word to the left (macOS)
    * `CTRL` + `SHIFT` + `right` = select word to the right (Windows)
    * `CTRL` + `SHIFT` + `left` = select word to the left (Windows)
    * `CTRL` + `right` = jump over the word to the right
    * `CTRL` + `left` = jump over the word to the left
    * `CTRL` + `ALT` + L = Reformat Code on Windows
    * `CMD` + `ALT` + L = Reformat Code on macOS

Tests:
    >>> import sys; sys.tracebacklimit = 0

    >>> assert sepal_length is not Ellipsis, \
    'Assign your result to variable `sepal_length`'
    >>> assert sepal_width is not Ellipsis, \
    'Assign your result to variable `sepal_width`'
    >>> assert petal_length is not Ellipsis, \
    'Assign your result to variable `petal_length`'
    >>> assert petal_width is not Ellipsis, \
    'Assign your result to variable `petal_width`'

    >>> assert type(sepal_length) is float, \
    'Variable `sepal_length` has invalid type, should be float'
    >>> assert type(sepal_width) is float, \
    'Variable `sepal_width` has invalid type, should be float'
    >>> assert type(petal_length) is float, \
    'Variable `petal_length` has invalid type, should be float'
    >>> assert type(petal_width) is float, \
    'Variable `petal_width` has invalid type, should be float'

    >>> sepal_length
    5.86

    >>> sepal_width
    3.02

    >>> petal_length
    4.14

    >>> petal_width
    1.34
"""

DATA = [
    'sepal_length,sepal_width,petal_length,petal_width,species',
    '5.8,2.7,5.1,1.9,virginica',
    '5.1,3.5,1.4,0.2,setosa',
    '5.7,2.8,4.1,1.3,versicolor',
    '6.3,2.9,5.6,1.8,virginica',
    '6.4,3.2,4.5,1.5,versicolor',
]

# Arithmetic mean from tuple with 5.8, 5.1, 5.7, 6.3, 6.4
# type: float
sepal_length = ...

# Arithmetic mean from tuple with 2.7, 3.5, 2.8, 2.9, 3.2
# type: float
sepal_width = ...

# Arithmetic mean from tuple with 5.1, 1.4, 4.1, 5.6, 4.5
# type: float
petal_length = ...

# Arithmetic mean from tuple with 1.9, 0.2, 1.3, 1.8, 1.5
# type: float
petal_width = ...