6.1. Type Tuple

  • Immutable - cannot add, modify or remove items

  • Stores elements of any type

6.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)

6.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

6.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'>

6.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

6.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'

6.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

6.1.7. Count

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

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

6.1.8. Reverse

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

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

6.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)

6.1.10. Length

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

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

6.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

6.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/type-tuple-memory.png

Figure 6.1. Memory representation for tuple

6.1.13. Recap

  • Immutable - cannot add, modify or remove items

  • Stores elements of any type

  • Fast and memory efficient

6.1.14. Assignments

Code 6.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_b` with elements: 1, 2, 3
        c. `result_c` with elements: 1.1, 2.2, 3.3
        d. `result_d` with elements: 'a', 'b', 'c'
        e. `result_e` with elements: True, False, None
        f. `result_f` 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_b` z elementami: 1, 2, 3
        c. `result_c` z elementami: 1.1, 2.2, 3.3
        d. `result_d` z elementami: 'a', 'b', 'c'
        e. `result_e` z elementami: True, False, None
        f. `result_f` 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, None), \
    'Variable `result_e` has invalid value, should be (True, False, None)'
    >>> 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, None
# type: tuple[bool|None]
result_e = ...

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

Code 6.2. Solution
"""
* Assignment: Iterable Tuple Select
* Type: class assignment
* Complexity: easy
* Lines of code: 1 lines
* Time: 3 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 6.3. Solution
"""
* Assignment: Iterable List Count
* Type: class assignment
* Complexity: easy
* Lines of code: 5 lines
* Time: 5 min

English:
    1. Count number of occurrences of value 1 in:
        a. `result_a` - number of occurrences in DATA_A
        b. `result_b` - number of occurrences in DATA_B
        c. `result_c` - number of occurrences in DATA_C
        d. `result_d` - number of occurrences in DATA_D
        e. `result_e` - number of occurrences in DATA_E
        f. `result_f` - number of occurrences in DATA_F
    2. Run doctests - all must succeed

Polish:
    1. Zlicz liczbę wystąpień wartości 1 w:
        a. `result_a` - liczba wystąpień w DATA_A
        b. `result_b` - liczba wystąpień w DATA_B
        c. `result_c` - liczba wystąpień w DATA_C
        d. `result_d` - liczba wystąpień w DATA_D
        e. `result_e` - liczba wystąpień w DATA_E
        f. `result_f` - liczba wystąpień w DATA_F
    2. Uruchom doctesty - wszystkie muszą się powieść

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

    >>> 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 int, \
    'Variable `result_a` has invalid type, should be int'
    >>> assert type(result_b) is int, \
    'Variable `result_b` has invalid type, should be int'
    >>> assert type(result_c) is int, \
    'Variable `result_c` has invalid type, should be int'
    >>> assert type(result_d) is int, \
    'Variable `result_d` has invalid type, should be int'
    >>> assert type(result_e) is int, \
    'Variable `result_e` has invalid type, should be int'
    >>> assert type(result_f) is int, \
    'Variable `result_f` has invalid type, should be int'

    >>> assert result_a == 0, \
    'Variable `result_a` has invalid value. Check your calculations.'
    >>> assert result_b == 1, \
    'Variable `result_b` has invalid value. Check your calculations.'
    >>> assert result_c == 1, \
    'Variable `result_c` has invalid value. Check your calculations.'
    >>> assert result_d == 0, \
    'Variable `result_d` has invalid value. Check your calculations.'
    >>> assert result_e == 1, \
    'Variable `result_e` has invalid value. Check your calculations.'
    >>> assert result_f == 3, \
    'Variable `result_f` has invalid value. Check your calculations.'

    >>> pprint(result_a)
    0
    >>> pprint(result_b)
    1
    >>> pprint(result_c)
    1
    >>> pprint(result_d)
    0
    >>> pprint(result_e)
    1
    >>> pprint(result_f)
    3
"""

DATA_A = ()
DATA_B = (1, 2, 3)
DATA_C = (1.0, 2.0, 3.0)
DATA_D = ('1', '2', '3')
DATA_E = (True, False)
DATA_F = (1, 1.0, True, '1')

# Number of occurrences of value 1 in DATA_A
# type: int
result_a = ...

# Number of occurrences of value 1 in DATA_B
# type: int
result_b = ...

# Number of occurrences of value 1 in DATA_C
# type: int
result_c = ...

# Number of occurrences of value 1 in DATA_D
# type: int
result_d = ...

# Number of occurrences of value 1 in DATA_E
# type: int
result_e = ...

# Number of occurrences of value 1 in DATA_F
# type: int
result_f = ...

Code 6.4. Solution
"""
* Assignment: Iterable Tuple Index
* Type: class assignment
* Complexity: easy
* Lines of code: 1 lines
* Time: 3 min

English:
    1. Define variable `result` with
       an index of an element `c` in `DATA`
    2. Run doctests - all must succeed

Polish:
    1. Zdefiniuj zmienną `result`
       z indeksem elementu `c` w `DATA`
    2. Uruchom doctesty - wszystkie muszą się powieść

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

    >>> assert result is not Ellipsis, \
    'Assign your result to variable `result`'

    >>> assert type(result) is int, \
    'Variable `result` has invalid type, should be int'

    >>> assert result == 2, \
    'Variable `result` has invalid value. Check your calculations.'

    >>> pprint(result)
    2
"""

DATA = ('a', 'b', 'c', 'd')


# Index of an element `c` in `DATA`
# type: int
result = ...