>>> Декартово произведение
Декартово произведение последовательностей или множеств можно получить с помощью спискового включения или множественного включения. Например:
>>> [(x, y) for x in (1, 2) for y in (-2, -1)]
[(1, -2), (1, -1), (2, -2), (2, -1)]
>>>
>>> {(x, y) for x in {1, 2} for y in {-2, -1}}
{(1, -1), (2, -2), (1, -2), (2, -1)}
В модуле itertools
имеется функция product
для получения декартовых произведений. Получим тот же результат с ее помощью.
>>> from itertools import product
>>> [(i, j) for i, j in product((1, 2), (-2, -1))]
[(1, -2), (1, -1), (2, -2), (2, -1)]
>>>
>>> {(i, j) for i, j in product({1, 2}, {-2, -1})}
{(1, -1), (2, -2), (1, -2), (2, -1)}
С помощью product
также можно умножить последовательность или множество на себя один или больше раз:
>>> [(i, j) for i, j in product((1, 2), repeat=2)]
[(1, 1), (1, 2), (2, 1), (2, 2)]
>>> {(i, j, k) for i, j, k in product({1, 2}, repeat=3)}
{(1, 2, 1), (2, 1, 1), (2, 2, 2), (1, 1, 2), (1, 2, 2), (2, 1, 2), (2, 2, 1), (1, 1, 1)}
>>> Срез
Срез работает для объектов list
, tuple
, str
, bytes
и для всех объектов, классы которых реализуют методы __getitem__
и __setitem__
. Несколько примеров:
>>> [0, 1, 2, 3, 4][1:4]
[1, 2, 3]
>>> (0, 1, 2, 3, 4)[1:4]
(1, 2, 3)
>>> 'abcde'[1:4]
'bcd'
>>> b'abcde'[1:4]
b'bcd'
>>> [x**2 for x in range(10)][1:4]
[1, 4, 9]
Менее очевидный пример (см. также Почти как последовательность):
>>> range(10)[1:4]
range(1, 4)
Это работает, поскольку класс range
реализует метод __getitem__
.
>>> >>> range.__getitem__
<slot wrapper '__getitem__' of 'range' objects>
>>> __getitem__
и __setitem__
Реализация классом dunder-методов __getitem__
и __setitem__
позволяет работать с объектами этого класса с помощью оператора []
. Например:
>>> class Example():
... def __getitem__(self, s):
... return s
...
... def __setitem__(self, s, val):
... print(s, val)
...
>>> e = Example()
>>> e[0] = 3.14
0 3.14
>>> e[1]
1
В качестве параметра s
методы __getitem__
и __setitem__
могут получить не только числовой индекс, но и срез - объект класса slice
:
>>> e[0:3] = (1, 2, 3, 4, 5)
slice(0, 3, None) (1, 2, 3, 4, 5)
>>> e[0:3]
slice(0, 3, None)
И должны реализовавать логику работы со срезом.
>>> Срез может
Срез производит новую последовательность, кроме случаев, когда он используется слева от знака присваивания. Срез, для которого не указаны нижняя и верхняя границы, создает копию последовательноти:
>>> x = [0, 1, 2, 3, 4, 5]
>>> y = x[:]
>>> y
[0, 1, 2, 3, 4, 5]
>>> x is not y
True
Разумеется, копия создается только для изменяемой последовательности. Для неизменяемой - не создается:
>>> x = (0, 1, 2, 3, 4, 5)
>>> y = x[:]
>>> y
(0, 1, 2, 3, 4, 5)
>>> x is y
True
Присваивание срезу без нижней и верхней границ замещает все элементы существующей последовательности, а не создает новую, что видно по неизменному id
списка x
:
>>> id(x)
2256739361480
>>> x[:] = [7, 7, 7]
>>> x
[7, 7, 7]
>>> id(x)
2256739361480
>>> Срез умеет
Кроме нижней и верхней границы, срез имеет третий параметр - шаг, по умолчанию равный 1. Значение шага N > 1 позволяет получить каждый N-ый элемент среза, заданного нижней и верхней границами, причем элементы рассматриваются слева направо:
>>> x = [0, 1, 2, 3, 4]
>>> x[::2] # каждый 2-й элемент
[0, 2, 4]
Отрицательные значения шага предписывают рассматривать элементы среза справа налево:
>>> x[::-1] # список в обратном порядке
[4, 3, 2, 1, 0]
>>> x[::-2] # каждый 2-й элемент в обратном порядке
[4, 2, 0]
Срез с шагом -1 позволяет реверсировать строку:
>>> 'Привет, Python!'[::-1]
'!nohtyP ,тевирП'
Срез позволяет задавать границы за пределами последовательности - и это не приводит к ошибке:
>>> [0, 1, 2][:5] # первые 5 элементов
[0, 1, 2]
>>> [0, 1, 2][-5:] # последние 5 элементов
[0, 1, 2]
>>> [0, 1, 2][::5] # каждый 5-й элемент
[0]
>>> [0, 1, 2][5:] # элементы начиная с индекса 5
[]
>>> [0, 1, 2][:-5] # элементы по индекс 5
[]
Комментариев нет:
Отправить комментарий