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: []})