Создадим список из целых чисел и назовём его numbers
:
numbers = [1, 0, 3, -5, 9, -8, -10, -12, 3, 7, 8]
Напишем код, который будет проверять, положителен ли первый элемент списка или нет. Создадим для этого условную конструкцию if-else
.
if numbers[0] > 0:
print("Yes")
else:
print("No")
Yes
В части с if
мы прописываем условие, в зависимости от которого Python будет делать выбор, что выводить на экран, а после двоеточия перечисляем действия, которые будут выполняться в случае, если элемент удовлетворяет условию. В части с else
мы уже не пишем никакого условия – оператор else
сам по себе означает «в случае, если условие в выражении с if
не выполнено».
Часть с else
является необязательной: программа может существовать только с условием if
. Тогда в случае невыполнения условия ничего происходить не будет, Python просто перейдет к следующим строкам кода.
# то же условие для второго элемента – ничего
if numbers[1] > 0:
print("Yes")
# для первого элемента – то же, что с else
if numbers[0] > 0:
print("Yes")
Yes
Теперь поставим перед собой такую задачу: распределить все элементы списка numbers
на два списка, список negatives
из отрицательных чисел и список non_negatives
из неотрицательных чисел. Помимо условия воспользуемся циклом for
и методом .append()
, который добавляет элемент в конец списка.
negatives = []
non_negatives = []
for i in numbers:
if i < 0:
negatives.append(i)
else:
non_negatives.append(i)
Сначала создадим два пустых списка negatives
и non_negatives
, в них мы будем записывать соответствующие элементы из списка numbers
.
Как устроен цикл for
выше? Кодом выше мы доносим до Python мысль: пробегайся по всем элементам списка numbers
(for i in numbers
), проверяй для каждого элемента выполнение условия (if i < 0
) и записывай этот элемент либо к одному списку, либо к другому.
Вообще любой цикл for
имеет такую структуру: сначала указывается, по каким значениям нужно пробегаться, а потом, что нужно делать. Действия, которые нужно выполнить в цикле, указываются после двоеточия в for
– эта часть назвается телом цикла.
Буквы в конструкции for
могут быть любые, совсем необязательно брать букву i
. Python сам поймет, что мы имеем в виду, запуская цикл.
Посмотрим, как выглядят списки negatives
и non_negatives
:
print(negatives)
print(non_negatives)
[-5, -8, -10, -12] [1, 0, 3, 9, 3, 7, 8]
Значения добавляются в списки последовательно, в том порядке, в котором они идут в исходном списке numbers
. Если мы хотим их отсортировать, нам понадобится метод .sort()
:
negatives.sort()
non_negatives.sort()
print(negatives)
print(non_negatives)
[-12, -10, -8, -5] [0, 1, 3, 3, 7, 8, 9]
«Наслаивать» методы на списках друг на друга нельзя, их нужно применять последовательно, посколько они (за редким исключением, например, методы .index()
или .count()
) ничего не возвращают, а сразу модифицируют список. Так, метод .append()
добавляет элемент в конец списка, но при этом возвращает пустой объект None
:
# попробуем сохранить результат .append в переменную
# и получим пустоту и безысходность...
L = [1, 0, 3]
L2 = L.append(8)
print(L2)
None
К слову, если методы не изменяют исходный элемент, а возвращают его модифицированную копию, использовать несколько методов сразу можно. В частности, это актуально для строк. Попробуем сначала сделать все буквы в тексте заглавными, а потом разбить его на части по пробелу – всё одной строкой кода:
"a b c".upper().split()
['A', 'B', 'C']
Применить методы в другом порядке в данном случае не получится: если мы сначала применим .split()
, результатом будет список, а метод .upper()
существует только для строк:
"a b c".split().upper()
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-10-046f35cfad99> in <module> ----> 1 "a b c".split().upper() AttributeError: 'list' object has no attribute 'upper'
Кортежи встречаются не только в программировании, но и в математике. В математике под кортежем обычно понимают упорядоченную совокупность элементов, то есть совокупность, порядок элементов которой фиксирован. В кортеже мы точно знаем, какой элемент является первым, какой – вторым, и так далее.
Внешне кортежи несильно отличаются от списков. Единственное внешнее отличие – элементы кортежа заключаются в круглые, а не в квадратные скобки.
# список (list)
L1 = [8, 9, 0]
# кортеж (tuple)
T1 = (8, 9, 0)
Но, несмотря на кажущееся сходство, кортежи и списки – принципиально разные объекты. Главное отличие кортежей от списков заключается в том, что кортежи – неизменяемые объекты. Другими словами, изменять элементы кортежа нельзя. Проверим:
# список – все ок
L1[1] = 90
L1
[8, 90, 0]
# кортеж – нельзя
T1 = (8, 9, 0)
T1[1] = 90
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-13-9cfa7f9d5edd> in <module> 2 3 T1 = (8, 9, 0) ----> 4 T1[1] = 90 TypeError: 'tuple' object does not support item assignment
Если посмотреть на методы, применяемые к кортежам и спискам (например, набрать T1.
или L1.
и нажать Tab), то можно заметить, что методов для кортежей сильно меньше по сравнению с методами для списков. Во многом это связано с тем, что кортеж нельзя изменить.
Иногда это свойство бывает полезным (некоторая «защита» от изменений), иногда – не очень, но для нас пока важно познакомиться с разными объектами в Python, чтобы потом не удивляться. Ведь многие более продвинутые функции могут возвращать результат или, наоборот, принимать на вход только кортежи или только списки.
Теперь немного поговорим о словарях. Обсуждая словари в Python, удобно проводить аналогию с обычными словарями (бумажными или электронными). Что такое словарь? Перечень из пар: слово-значение или слово-список значений, если значений несколько. Вот и словарь в Python – это объект, структура данных, которая позволяет хранить пары соответствий. Создадим маленький словарь с именами студентов и их оценками:
d = {"Anna" : 10, "Peter" : 9}
Можем запросить перечень ключей этого словаря:
d.keys()
dict_keys(['Anna', 'Peter'])
Или перечень значений:
d.values()
dict_values([10, 9])
Или сразу всё в виде упорядоченных пар, на первом месте – ключ, на втором – значение:
d.items()
dict_items([('Anna', 10), ('Peter', 9)])
Теперь попробуем вызвать какое-нибудь значение по его ключу, это понадобится нам в дальнейшем для выгрузки информации из веб-страниц или из API. Как и в случае со списками или кортежами, к элементам словаря можно обращаться, используя квадратные скобки. Только выбор элемента производится не по индексу, а по ключу: сначала указываем название словаря, а потом в квадратных скобках – ключ, по которому мы хотим вернуть значение. Например, выясним оценку Анны:
d["Anna"]
10
А что будет, если мы попробуем вызвать значение по несуществующему ключу?
d["Liz"]
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-19-529450de6949> in <module> ----> 1 d["Liz"] KeyError: 'Liz'
Что ожидаемо, мы получим ошибку. Теперь представьте себе такую ситуацию: у нас есть список студентов (ключей) и мы хотим в цикле вернуть по ним их оценки (значения). Какого-то одного из студентов в словаре нет. Что произойдет? На каком-то этапе Python выдаст ошибку, мы вывалимся из цикла, и на этом наша работа остановится. Обидно, да? Чтобы такого избежать, получать значение по ключу можно другим способом – используя метод .get()
:
d.get("Liz") # ни результата, ни ошибки
d.get("Anna") # а здесь всё как обычно
10
На этом мы пока закончим знакомство со структурами данных в Python, некоторые полезные сюжеты будем обсуждать по ходу курса, чтобы не было информационного перегруза.