for¶for i in range(100): # делать 100 раз, i примет значения от 0 до 99
if i % 17 == 0:
print(i)
0 17 34 51 68 85
while¶Мы с вами разобрали циклы for и while. Цикл for является наиболее часто используемым в питоне, однако иногда он все же неудобен.
Например, если вы не знаете, сколько раз вам необходимо будет совершить определенное действие.
Для такого рода проблем существует цикл while.
Помните, while не замена for
Вот пример некорректного использования while, тут правильно использовать for:
a = 0
while a < 5:
print (a)
a += 1
0 1 2 3 4
А, например, если вы ведете диалог с пользователем и выполняете какое-то действие,
пока он не введет "stop", то без while обойтись будет сложно.
answer = input("Input number: ")
while answer != "stop":
answer = int(answer)
if answer % 2 == 0:
print("even")
else:
print("odd")
answer = input("Input number: ")
Input number: 10 even Input number: 10 even Input number: stop
break и continue¶Два важных соуса к циклам for и while - это операторы break и continue
break позволяет досрочно выйти из цикла
# Проверка того, что число простое
a = input()
a = int(a)
if a > 1:
is_prime = True
for i in range(2, a): # итерироваться, начиная с 2 и заканчивая a - 1
if a % i == 0: # если число делится на что-то из этого без остатка,
# то оно не простое
is_prime = False
break # можем досрочно завершить цикл,
# у нас нет смысла что-либо проверять дальше
else:
is_prime = False
print(is_prime)
11 True
continue позволяет досрочно перейти к следующей итерации цикла
for i in range(5):
if i == 2:
continue
print(i)
0 1 3 4
pass - просто говорит, что в данном месте хорошо бы что-то написать, а пока - заглушка
for i in range(0, 5):
if i % 13 == 0:
pass # insert fix here
print(i)
0 1 2 3 4
Какие виды коллекций в Python вы помните?
Итерация (лат. iteratio — «повторение») — повторение какого-либо действия.
Итерация в программировании — один шаг цикла / одно исполнение заданных команд.
Можно пройтись по списку, просто по очереди обращаясь к каждому из его элементов (итерируясь по списку) по индексу.
Для этого полезна функция len, которая, как и в случае строки, возвращает длину списка.
my_lst3 = [1, 7, -5, 0, 32]
for i in range(len(my_lst3)):
print (my_lst3[i])
1 7 -5 0 32
Однако в случае списков (и вообще всех коллекций в Python) можно использовать цикл for напрямую!
Именно этот путь и рекомендуется использовать; первый путь обычно говорит о том, что автор кода еще не очень опытный :^)
for elem in my_lst3:
print(elem)
1 7 -5 0 32
for можно применить и для строк. В этом случае вы будете идти (итерироваться) по символам строки
s = "Hello, world"
for c in s:
print(c)
H e l l o , w o r l d
Можно проверить, есть ли элемент в списке с помощью ключевого слова in
a = [1, 3, 10]
if 5 in a:
print ("5 is in a")
else:
print ("5 is not in a")
5 is not in a
У итерации по элементам контейнера есть особенность - переменная, которой последовательно присваиваются значения элементов из контейнера, может быть затем использована.
Это полезно, когда, например, мы ищем первый элемент, удолетворяющий заданному свойству
a = [1, 3, 4, 100, 34]
for i in a:
if i % 2 == 0:
break
i
4
Проблема в том, что если элемента не найдено, то i примет значение последнего элемента в списке.
a = [1, 3, 7, 11]
for i in a:
if i % 2 == 0:
break
i
11
Еще одна проблема, что если i не было ранее объявлено, а мы решили пройтись по пустому списку, то i останется необъявленным и мы получим ошибку:
del i # remove variable i
a = []
for i in []:
if i % 2 == 0:
break
i
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-69-b6ded53dcdda> in <module>() 4 if i % 2 == 0: 5 break ----> 6 i NameError: name 'i' is not defined
Обе проблемы решаются использованием else в for-цикле!
Обратите внимание, что else расположено на одном уровне с for и относится именно к нему!
else в этом случае выполняется, только если выход из for не был осуществлен при помощи break (то есть мы прошли по всем значениям в контейнере)
a = [1, 3, 7, 11]
for i in a:
if i % 2 == 0:
break
else:
i = None
print("No even elements")
print (i)
No even elements None
Обе проблемы решаются использованием else в for-цикле!
Обратите внимание, что else расположено на одном уровне с for и относится именно к нему!
else в этом случае выполняется, только если выход из for не был осуществлен при помощи break (то есть мы прошли по всем значениям в контейнере)
a = []
for i in a:
if i % 2 == 0:
break
else:
i = None
print("No even elements")
print (i)
No even elements None
Если искомый элемент все же есть, то все работает хорошо!)
a = [1, 3, 7, 12]
for i in a:
if i % 2 == 0:
break
else:
i = None
print("No even elements")
print (i)
12
Работает не только для списка, а для всех коллекций/контейнеров
if not a: # if a is empty
print("a is empty")
b = [1]
if b: # if b is not empty
print("b is not empty")
b is not empty
Подсказка: есть 3 способа!
Для вложенных списков и просто изменяемых объектов в изменяемых объектов - функция deepcopy модуля copy
from copy import deepcopy
lst1 = ['a','b',['ab','ba']]
lst2 = deepcopy(lst1)
lst2[2][1] = "d"
lst2[0] = "c";
print(lst1)
print(lst2)
['a', 'b', ['ab', 'ba']] ['c', 'b', ['ab', 'd']]
Список, как и многие другие встроенные типы в Python, имеет набор функций, предназначенных для работы с ним и вызываемых с помощью конструкции вида lst.method_name
.append - Добавление в список
Хочется уметь достраивать список в ходе работы программы. Например, можем создать список всех нечетных чисел до 20
lst = []
for i in range(20 + 1):
if i % 2 == 1:
lst.append(i)
print(lst)
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
.extend - добавление в конец нашего списка всех элементов из другого
Конкатенация!
a = [1, 4]
b = [1, 2, 7]
c = a + b
print(a, b, c)
[1, 4] [1, 2, 7] [1, 4, 1, 2, 7]
a[1] = 5
print(a, b, c)
[1, 5] [1, 2, 7] [1, 4, 1, 2, 7]
lst = [1, 4]
lst.extend([1, 2, 7])
lst
[1, 4, 1, 2, 7]
.count - подсчёт числа вхождений какого-то элемента в списке
lst = [1, 7, -5, 6, 0, 1]
lst.count(1)
2
.sort - сортировка списка на месте
lst = [1, 7, -5, 6, 0, 1]
lst.sort()
lst
[-5, 0, 1, 1, 6, 7]
lst = [1, 7, -5, 6, 0, 1]
.index - поиск первого индекса значения в списке; если значения нет, то возникнет ошибка
lst = [-5, 0, 1, 1, 6, 7]
lst.index(0)
1
Для строк существует множество методов.
Обратите внимание, что, в отличие от списка, если эти методы подразумевают модификацию строки, то они возвращают новую строку.
.strip - удалить перенос строки и прочие "белые" символы по краям строки.
Существуют аналоги - .rstrip и .lstrip, удаляющие эти символы только с одной стороны.
a = " hello \n"
b = a.strip()
print("START", a, "END")
print(b)
START hello END hello
.replace - заменить все вхождения одной подстроки на другую
a = "hello, hello, hello"
b = a.replace("hello", "hell")
print(b)
hell, hell, hell
.find - найти вхождение подстроки в строку. Если подстроки нет в строке, то вернуть -1
a = "Hello, world"
a.find("world")
7
a.find("wild")
-1
a = "hello, hello, hello"
f_ind = a.find("hello")
print(f_ind)
print(a.find("hello", f_ind + 1))
0 7
Метод позволит вам искать в строке, начиная с определенной позиции, это поможет вам в домашнем задании :^)
?a.find
Чтобы проверить, содержится ли строка в другой строке, можно просто использовать ключевое слово in
print("wo" in "world")
print("he" in "world")
True False
Но если вам нужно искать в специфичном месте строки, то есть специальные методы!
.startswith - начинается ли строка на данную подстроку
a = "hello, hello, hello"
print(a.startswith("hello"))
print(a.startswith("ello"))
True False
.endswith - заканчивается ли строка на данную подстроку
a = "hello, hello, hello"
print(a.endswith("hello"))
print(a.endswith("he"))
True False
.join - объединить строкой-разделителем несколько других строк в контейнере
", ".join(["1", "2", "apple"])
'1, 2, apple'
a = list("ATGATAGATAG")
a
['A', 'T', 'G', 'A', 'T', 'A', 'G', 'A', 'T', 'A', 'G']
"G".join(a)
'AGTGGGAGTGAGGGAGTGAGG'
my_dict = {'Cats': 10,
'Rats': 20,
'Mice': 52}
Что будет, если мы запросим значение словаря по ключу 'Dogs'?
my_dict['Dogs']
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-8-cd4e80ef3946> in <module> ----> 1 my_dict['Dogs'] KeyError: 'Dogs'
Можно использовать метод .get(key, default_value=None) для того, чтобы в случае отсутствия ключа в словаре получать какое-то значение по умолчанию.
print(my_dict.get("Dogs"))
None
my_dict.get("Cats", 5)
10
А как просто проверить, есть ли такой ключ в словаре?
Как и для других коллекций, для проверки наличия ключа в словаре используется слово in
if "Dogs" in my_dict:
print("Oh my!")
else:
print("Nice!")
Nice!
Учтите, что методы словаря, "возвращающие" хранимое в нем, возвращают не-совсем-списки, с этим объектом нельзя работать так же, как со списком
Пройтись по ключам словаря (итерировать) можно двумя способами
my_dict.keys()
dict_keys(['Cats', 'Rats', 'Mice'])
for key in my_dict.keys():
print (key)
Cats Rats Mice
for key in my_dict:
print (key)
Cats Rats Mice
my_dict.values()
dict_values([10, 20, 52])
for value in my_dict.values():
print (value)
10 20 52
for key in my_dict.keys():
value = my_dict[key]
print(key, value)
Cats 10 Rats 20 Mice 52
В чем тут недостаток?
my_dict.items()
dict_items([('Cats', 10), ('Rats', 20), ('Mice', 52)])
for key, value in my_dict.items():
print(key, value)
Cats 10 Rats 20 Mice 52
list(my_dict.keys())
['Cats', 'Rats', 'Mice']
list(my_dict.values())
[10, 20, 52]
list(my_dict.items())
[('Cats', 10), ('Rats', 20), ('Mice', 52)]
a = {"A": 0,
"T": 1,
"G": 2,
"C": 3,
"G": 4,
"U": 5}
a
{'A': 0, 'C': 3, 'G': 4, 'T': 1, 'U': 5}
a
{'A': 0, 'C': 3, 'G': 4, 'T': 1, 'U': 5}
del a['U']
a
{'A': 0, 'C': 3, 'G': 4, 'T': 1}
Все хорошо? Попробуем еще раз!
del a['U']
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-142-a67e9e64d21f> in <module>() ----> 1 del a['U'] KeyError: 'U'
Можно использовать метод .pop - он правильнее
a = {"A" : 0, "T" : 1, "G": 2, "C" : 3, "G" : 4, "U" : 5}
a.pop('U')
a
{'A': 0, 'C': 3, 'G': 4, 'T': 1}
a.pop('U')
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-144-f443700df4c8> in <module>() ----> 1 a.pop('U') KeyError: 'U'
a.pop('U', None)
a = {"A": 0,
"T": 1,
"G": 2,
"C": 3,
"G": 4,
"U": 5}
for key in a.keys():
if key == "C":
a.pop(key)
a = {"A": 0,
"T": 1,
"G": 2,
"C": 3,
"G": 4,
"U": 5}
for key in a.keys():
if key == "C":
a.pop(key)
--------------------------------------------------------------------------- RuntimeError Traceback (most recent call last) <ipython-input-4-ae436969eca3> in <module> 6 "U": 5} 7 ----> 8 for key in a.keys(): 9 if key == "C": 10 a.pop(key) RuntimeError: dictionary changed size during iteration
Как обойти проблему?
Можно обойти проблему так:
a = {"A": 0, "TC": 1,
"G": 2, "CG": 3,
"GC": 4, "U": 5}
keys = list(a.keys())
for key in keys:
if "C" in key:
a.pop(key)
a
{'A': 0, 'G': 2, 'U': 5}
До версии Python3.5 включительно никто не гарантировал вам никакого порядка ключей в словаре. То есть то, как они вам выдавались функцией keys и т.д не зависело ни от порядка вставки элементов, не от результата их сравнения напрямую.
Однако с версии Python3.6 в наиболее распространненой реализации (CPython), а с версии Python3.7 - в любой, порядок ключей в словаре соответствует порядку их вставки в него. Если ключ уже существовал в словаре и вы его перезаписали, то порядок ключей не изменится.
Получение значения по ключу и добавление нового ключа в словарь происходит значительно быстрее, чем если бы вам пришлось перебирать список в поисках нужного значения.
Вследствие этого есть огромный набор задач, где словари использовать можно и нужно.
Вместе со списками — возможность представить структуру данных любой сложности (дополнительная информация — json).
Словари "кушают" много памяти. Все операции на словарях быстры в среднем — отдельная операция может длиться очень долго.
Если очень хочется сделать ключом словаря список, то нужно использовать не list, а другой тип данных — кортеж tuple.
Кортеж, на первый взгляд, отличается от списка только заменой квадратных скобок на круглые, например:
ta = (1, 2, 5, 4)
ta[0]
1
Как сделать кортеж длиной 1?
a = (1)
print(a)
1
a = (1, )
print(a)
(1,)
Кортеж во многом похож на список, но главным отличием является то, что кортеж неизменяем.
ta[0] = 5
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-150-387a39ba50ab> in <module>() ----> 1 ta[0] = 5 TypeError: 'tuple' object does not support item assignment
Можно ли использовать список как ключ словаря?
dt = {}
dt[(1, 2)] = "Hello"
dt[(2, 1)] = "world"
dt
{(1, 2): 'Hello', (2, 1): 'world'}
dt[(1, 2)]
'Hello'
Кроме возможности служить ключом словаря, в случае кортежей, операции доступа (получить элемент кортежа, срез и т.д.) выполняются для кортежа быстрее. Python может оптимизировать работу программы, в которой создается множество кортежей малой длины, что для списков недоступно.
С другой стороны, любая операция редактирования кортежа приводит к созданию нового кортежа, что в больших количествах может замедлить работу программы и съесть память вашего компьютера.
В некоторых случаях удобно пользоваться типом данных "множество" set.
Это именно множество в математическом смысле этого слова, то есть его элементы уникальны и не могут повторяться (в отличие от списка и кортежа).
s = {-10, 20, 45}
s.add(348)
s.add(-100000)
s.add(-10)
s
{-100000, -10, 20, 45, 348}
my_set1 = {1, 7, 9} # first way to create set
my_set2 = set([0, -4, 10, 1]) # second way
lst = [1, 10, -5, -5, 20]
my_set = set(lst)
my_set
{-5, 1, 10, 20}
for elem in my_set:
print(elem)
1 10 -5 20
a = {}
type(a)
dict
a = set(); type(a)
set
Множества используются в типичном решении того, как оставить в списке только уникальные элементы
lst = [1, 10, -5, -5, 20, -10, 20, 0, 0, 0]
my_set = set(lst)
unique_lst = list(my_set)
unique_lst
[0, 1, 10, 20, -10, -5]
На множествах определены операции объединения, пересечения и разности.
my_set1 & my_set2 # intersection
{1}
my_set1 | my_set2 # join
{-4, 0, 1, 7, 9, 10}
my_set1 - my_set2 # difference
{7, 9}
my_set1.symmetric_difference(my_set2)
{-4, 0, 7, 9, 10}
Проверку на наличие элемента в множестве можно провести при помощи уже известного вам ключевого слова in
5 in my_set1
False
nucleotides = {"A", "G", "T", "U", "C"}
n = input()
if not (n in nucleotides):
print ("error")
A
nucleotides = {"A", "G", "T", "U", "C"}
n = input()
if n not in nucleotides:
print ("error")
a error
Множество — изменяемый тип (не может быть ключом словаря, но может быть значением словаря, что можно применить в задании 6).
Изменяемость нужна, чтобы использовать удобные в некоторых ситуациях методы .add, .pop и .remove (см. help(set.add) и т.п.).
print (my_set1.pop())
my_set1
5
{7, 9}
my_set1.add(5)
my_set1
{5, 7, 9}
Порядок элементов в множестве по-прежнему не гарантирован и не зависит ни от чего. У вас результат запуска может отличаться, к примеру)
s = {-10, 20, 45}
s.add(348)
s.add(-100000)
s
{-100000, -10, 20, 45, 348}
frozenset¶Неизменяемым аналогом set является frozenset. В отличии от обычного множества его можно использовать в качестве ключа в словаря.
my_frozen = frozenset([4, 5, 6])
my_frozen
frozenset({4, 5, 6})
my_frozen.add(4)
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-176-06075b4ac502> in <module>() ----> 1 my_frozen.add(4) AttributeError: 'frozenset' object has no attribute 'add'
сollections!¶В модуле collections есть несколько модификаций стандартного словаря, позволяющих делать некоторые действия значительно проще (к примеру, подсчет разных элементов в списке)
Counter¶from collections import Counter
nucleotides = ["A", "T", "G", "C"]
seq = "ATAATATATATGAGGCGGCGCGCGCG"
cnt = Counter(seq)
print(cnt)
for n in nucleotides:
print (cnt[n])
Counter({'G': 9, 'A': 7, 'T': 5, 'C': 5})
7
5
9
5
defaultdict¶from collections import defaultdict
dl_dict = defaultdict(list)
# для каждого ключа, которого нет в словаре, но мы его запросили - создать по-умолчанию пустой список
print(dl_dict)
print(dl_dict[1])
print(dl_dict)
dl_dict[1].append("A")
dl_dict[1].append("A")
dl_dict[2].append("A")
dl_dict[100].append("C")
print ("dict: ", dl_dict, sep=" ")
print ("dict[1]", dl_dict[1], sep=" ")
print ("dict[20]", dl_dict[20], sep=" ")
print ("dict", dl_dict, sep=" ")
defaultdict(<class 'list'>, {})
[]
defaultdict(<class 'list'>, {1: []})
dict: defaultdict(<class 'list'>, {1: ['A', 'A'], 2: ['A'], 100: ['C']})
dict[1] ['A', 'A']
dict[20] []
dict defaultdict(<class 'list'>, {1: ['A', 'A'], 2: ['A'], 100: ['C'], 20: []})