Математический практикум по Питону.
Вводится базовые операции (методы) над важным объектом из Питона (Python) -- списоком (list). Показано как добавлять/удалять элементы и упорядочивать.
Ключевые слова: append, pop, extend, insert, del, id, copy, deepcopy, reverse и sort.
Это предварительная версия! Любые замечания приветсвуются.
Список не только хранить данные, но и подддерживает добавление новых элементов (в его конец), а также извлечение и удаление подсписков. по мимо этого упорядочивать элементы.
# Введем список.
l = [5, 23, -11, 23, 44]
len( l ) # Размер исходного списка.
Список на то и списк, что к нему можно добавить элемент (в его конец).
l.append(7) # Метод append, аргумент -- добавляемый элемент.
l # Элемент 7 добавился в конец (т.е. самый правый) списка.
len( l ) # Размер списка увеличился на 1 элемент.
Взять элемент с конца списка. Полезно при однократной обработки элементов (обработал и забыл).
# Испольуется метод pop. Элемент будет возвращен как значение.
l.pop() # Возвращаются с конца, т.е. в обратном порядке от добавления.
# Список будет уменьшен на один элемент, т.е. сокращен по размер.
l, len(l) # Получили исходный список.
# На самом деле извлесть элемент можно не только с конца.
l.pop(2) # Например в даном случае извлекается 2 элемент.
# Обычная версия эквивалентна pop(-1). Индексы нумеруются с 0.
l # Выведем элементы оставшегося списка.
Расширение списка
# Добавим два элемента?
l.append([5, 3]) # Или как?
l # Добавили, но наверно не так как хотели.
К списку был добавлен элемент [5,3].
# Добавляет в конец текущего списка элементы из другого списка.
l.extend([23,3]) # Аргумент метода extend должен быть списом.
l
d = [6, -4] # Например, другой список.
l.extend( d ) # Добавляем его элементы в конец нашего списка.
l
d.extend(6) # Когда аргумент не явлется списком, то ошибка.
Вставляет элемент на заданное место и сдвигает другие (далее следующие) дальше. Фактически раздвигает элементы и освобождает себе место. Потом его занимает.
l.insert(2, 101) # Используется метод insert.
l # Аргументом являются добавляемые элементы.
l.insert(5, [-5, -6]) # Так не получится.
l # Точнее вряд ли то, что мы ожидали.
# Вставили число 9 перед первым вхождением 23.
l.insert( l.index(23), 9) # index ищет индекс элемента.
l
l
l[3:6]
# Удаляет элемент с данным индексом (ами)
del l[3:6]
l
# Удаляем один или более разрозненных элементов.
del l[1], l[1] # Подумай почему индекс указан ожин и тот же.
l
# Вырезаем (удаляем) первый элемент из списка равный данному.
l.remove(23)
l
dd = [2]
dd
del dd[0] # При удалении последнего элемента сам список остается.
dd # Пустой, но список.
f = [2, 7, 8]
f
f.clear() # Можно все радикльно очистить.
f # Список пуст
# Присваиваем новый объект,
f = [] # пустой список.
Упр. В чем разница с методом clean? Возможно лучше сначала весь ноутбук прочесть.
Списки нужны для хранения данных. Если мы захотим все числа умножить на два, то возможно мы бы написали:
l * 2 # Хотим умножить все элементы списка на два.
И увидели бы результат, который скоре всего не соответсвует нашим ожиданиям. Дело в том, что список является объектом сам по себе. Поэтому он имеет свои смысловые нагрузки на операции. Например, + объединяет списки (конкатенация), точнее она ставит один список (второй) в конец другому (первому).
# Контакенация, один список добавили в конец к другому.
[1, -5] + [-7, 5, 18] # Получили новый список
l + [2] # как append добавили 2 в конец списка.
# Операция выполнена, но не сохранена.
l # Поэтому старое значение списка l.
# Операции умножение соответствует многократной конкатенации (т.е. повтору) самого себя:
[2, 5] * 3
# Только для целых чисел.
l * 2. # Для плавающей точки будет даже ошибка.
Упр. Как циклически сдвинуть элементы списка? Последнее подразумевает, что все элементы сдвинутся на один вперед, а первый попадет в конец.
[3,5,6] - [6] # Списки вычетать нельзя.
Бывает важным скопировать объект. Рассмотрим на примере списка какие с этим связаны нюансы.
l
d = l
d
d[1] = 11
d
l # Сюрприз! Значение в l тоже поменялось.
В питоне на самом деле в переменных хранятся не значения, а ссылки на объекты. Поэтому при копировании переменной копируется ссылка. Для правильного копирования необходимо сам объект скопировать.
e = l.copy() # Делаем копию списка.
e
e[1] = 22
e
l # А так все как надо: элемент не изменился.
Адрес объекта
# Возвращает уникальный идентификатор --
id(l) # handler -- объекта.
# Идентификаторы при присвоение значения переменной совпадают.
id(l) == id(d) # в d ранее присвоили l.
a = id(l) # Сохраним значение идентификатора до изменения.
l[2] = 5 # Изменяем содержимое списка.
b = id(l) # сохраняем идентификатора и после изменения.
l
# Изменение объектв не ведет к изменению его идентификатора.
a == b
a = id(l) # Аналогично.
l.append(-3)
b = id(l)
l
a == b # Даже при добавлении элемента.
print("id of id", id(d), ",", "id of e", id(e), '. Они равны:', id(d) == id(e))
# При создании копии самого объекта идентификатор изменился.
t = [1, 2, 3]
q = [t] * 2
q
q[0][1] = 11
q
Упр. Объясни почему у списка q изменение произошло в двух местах.
Но, не все так просто
# Берем список с подсписком.
f = [ 5, [3, -2], [5, 8]]
g = f.copy() # Делаем копию его.
g[0] = 1 # Сделали изменение.
g
f # Все ок.
g[1] # Под индексом 1 у нас список.
# А теперь добавили к списку под индексом 1 элемент
g[1].append(-1) # -- число -1.
g # Все ок.
# Посмотрим что с исходным списоком.
f # Хм....у исходного первый индекс тоже изменился... непорядок!
from copy import deepcopy # Палочка выручалочка.
g = deepcopy( f )
g[1].append( -9 )
g
f # Ура! Первый индекс не изменился.
Упр. Почему copy не спасает?
А равны ли?
Знак == позволяет проверить равенство объектов по сути, т.е. по смысловому значению. А не исходя из внутреннего представления объекта.
# Равенство, в частности, списков проверяется по содержимому.
[1, [4, 7], 7] == [1, [4, 7], 7]
# Даже если числа имеют разный тип. Всегда можно тип привести.
[1, [4, 7], 7.] == [1, [4., 7], 7] # Один фиг же что 4, что 4..
# Если объекты разные по сути, то и такой ответ.
[1, [4, 7], 7] == [1, [5, 7], 7] # 4 же не равно 5.
a = [1, 2, 5]
b = a.copy()
a == b # Объекты равны несмотря на то, что они представлены разными списками, т.е. объектами.
id(a) == id(b) # Как мы помним у объектов a и b разный handler (поэтому это и разные объекты).
Для проверки ссылаются ли переменные на один объект используется оператор is.
a is b # Фактически эквиваленто id(a) == id(b).
Оператор is очень важен для Питона!
Упорядочивание
l = [5, -1, 6, -3, 4]
e = l.copy()
# Упорядочиваем (сортируем) сам список.
l.sort() # Копию не создает.
l # Изменяется сам список.
# Упорядочивание в обратом порядке.
e.sort( reverse = True )
e
Порядок
e = [5, 4, 11]
ee = e.copy()
# Организует список в обратном направлении.
e.reverse() # Метод reverse изменяет сам список.
e
# Можно и так, но будет создан новый список.
ee[::-1] # Сложный индекс полезная вещь!
f = [5, 8, 5, -1, 14, 5.0]
# Метод count возвращает количество раз объект встречается.
f.count(5) # Подсчитаем встречаемости числа 5.
# Для отсутствующего в списке объекта.
f.count( 7 ) # Ествественно возвращается 0.
# Не возбраняется искать объекты произвольной структуры.
f.count( 'a' ) # Ищем строку a.