print("1) " + str(123)) # создать строку из любого другого значения
print("2) " + str(5.6))
print("3) " + str([10, 20, 30])) # str создает строку
1) 123 2) 5.6 3) [10, 20, 30]
str
превращает любой python объект в читаемый текст. Обычно этот текст используется для отладки. Замечание. Есть еще один метод, похожий на str
, это repr
, он тоже превращает любой pyhton объект в текст, но, в отличие от str
пытается выдать максимальное количество информации о содержимом объекта.
l = [10, 20, 30]
print(str(l))
print(repr(l))
r = range(10)
print(str(r))
print(repr(r))
# подождем, пока изучим более сложные типы, в которых эти методы дадут разный результат
[10, 20, 30] [10, 20, 30] range(0, 10) range(0, 10)
Метод list
превращает любое перечисление в список:
print(list((1, 2))) # был tuple 1, 2
print(list("abc"))
print(list(range(10)))
print(list([10, 20, 30])) # это можно использовать как копирование списка, см. далее
[1, 2] ['a', 'b', 'c'] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [10, 20, 30]
print(tuple([10, 20, 30])) # превратили список в tuple
print(tuple("abc")) # превратили текст в tuple
(10, 20, 30) ('a', 'b', 'c')
Оператор цикла for
позволяет перебирать все значения последовательности. Синтаксис
for {переменная} in {последовательность}:
# отступ 4 пробела для тела цикла
# действия c переменной
Переменной последовательно присваивается каждое из значений последовательности. Для каждого значения переменной вызывается тело цикла:
for x in [10, 20, 30]:
print(x)
10 20 30
for x in "hello":
print(x) # x присваивается очередной символ строки
h e l l o
for t in "one", "two", "three": # tuple из трех элементов
print(t)
one two three
for i in range(6): # range очень часто используется именно в циклах
print(i)
0 1 2 3 4 5
Изредка, при переборе списка нужно все-таки знать индексы элементов, тогда можно, например, использовать range:
l = [10, 20, 30, 40]
for i in range(len(l)): # от 0 до длины списка - 1
print(f"Элемент с индексом {i} это {l[i]}")
Элемент с индексом 0 это 10 Элемент с индексом 1 это 20 Элемент с индексом 2 это 30 Элемент с индексом 3 это 40
Но настояший "питоновый" способ перебора элементов перечисления с индексом такой:
for i, x in enumerate(l):
print(f"Элемент с индексом {i} это {x}")
Элемент с индексом 0 это 10 Элемент с индексом 1 это 20 Элемент с индексом 2 это 30 Элемент с индексом 3 это 40
Функция enumerate
получает перечисление и вовращает новое перечисление, которое состоит из tuple, где первый элемент - это индекс, а второй - элемент исходного перечислания:
list(enumerate([10, 20, 30])) # демонстрируем
[(0, 10), (1, 20), (2, 30)]
В enumerate
можно передать дополнительный аргумент, с какого индекса начинать:
for i, x in enumerate(l, 3):
print(f"Элемент с индексом {i} это {x}")
Элемент с индексом 3 это 10 Элемент с индексом 4 это 20 Элемент с индексом 5 это 30
Как перебрать список с конца в начало? Даже для этого можно обойтись без индексов
for x in l[::-1]:
print(x)
40 30 20 10
list1 = [10, 20, 30]
list2 = [10, 20, 30]
list3 = list1
list4 = list(list1) # "копирование" списка
list5 = list1[:] # все элементы с начала до конца, т.е. мы опять "копируем" список
list1[0] = 11 # заменим 10 на 11
for l in list1, list2, list3, list4, list5:
print(l)
[11, 20, 30] [10, 20, 30] [11, 20, 30] [10, 20, 30] [10, 20, 30]
Оказалось, что в list3
тоже изменилось первое значение!!
Квадратные скобки при описании списка создают новый список. Присваивание - это копирование ссылки. Т.е. list3
это переменная, которая ссылается на тот же самый список, что и list1
. Поэтмоу измнения в этом списке "видны" и через list1
, и через list2
.
list4
- был создан операцией list
, она скопировала значения из list1
. Ну а list5
получен оператором [:]
(slice), этот оператор создает новый список, копируя значения из указанного диапазона.
Другие примеры, когда нужно быть аккуратным:
def f(l):
l.append(42)
l = [100, 200, 300, 400]
t = 'local t'
t = 'global t'
l = [10, 20, 30]
m = ["abc", "xyz"]
f(l)
print(l)
f(m)
print(m)
print(t)
[10, 20, 30, 42] ['abc', 'xyz', 42] global t
В этом примере оказывается, что после вызова функции f
в переданный список добавляется 42, а присваивание списка [100, 200, 300, 400]
как будто не имеет эффекта.
Чтобы разобраться, нужно понять, что в этой программе есть две совершенно разных переменных l
. Одна переменная глобальная, она определена вне функции. А другая переменная l
- определена внутри функции. Она определена как ее параметр. Назовем ее локальной l
.
При вызове f(m)
локальной переменной l
присваивается список из глобальной переменной m
. Операция l.append
добавляет число 42 в этот список. А он доступен и через глобальную m
, и через локальную l
, поэтому после завершения функции мы видим, что список изменен.
А вот операция l = [100, 200, 300, 400]
создает новый список, присваивает его локальной переменной l
и это никаким образом не влияет на старый список, который, как и раньше, остается доступен через глобальную m
.
Первый вызов f(l)
ничем не отличается от вызова f(m)
кроме того, что фактический аргумент функции (то, с чем ее вызвали) по названию совпадает с формальным аргументом (параметром l
).
rows = [[]] * 4 #
print(rows)
rows[0].append(42)
print(rows)
[[], [], [], []] [[42], [42], [42], [42]]
Мы повторили один и тот же пустой список 4 раза. Поэтому в большом списке мы 4 раза ссылаемся на один и тот же пустой список. Т.е. l[0]
, l[1]
, l[2]
, l[3]
- это один и тот же список, поэтому он и изменяется "одновременно".
is
и ==
¶a = [10, 20, 30]
b = a
c = [10, 20, 30]
print(a == b) # == сравнивает содержимое объектов
print(a == c)
print(a is b) # is проверяет на одинаковость сами обеъкты
print(a is c) # здесь будет False, это разные объекты.
# хотя содержимое одинаково
True True True False
Смотрим на примерах
a = [10, 20, 30]
[x, y, z] = a
print(x, y, z) # переменным присвоились элементы списка!
10 20 30
Это работает, только если сходятся размеры списка и того, куда присваивается:
[x, y] = a # ошибка здесь
[x, y, z, t] = a # и здесь
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-9-2641b95b3bb5> in <module>() ----> 1 [x, y] = a # ошибка здесь 2 [x, y, z, t] = a # и здесь ValueError: too many values to unpack (expected 2)
Чаще это используют с tuple, например, потому что при задании tuple можно не ставить скобки
x, y = 10, 20
print(x, y)
10 20
справа создался tuple (10, 20), и он сразу же присвоился tuple из переменных x и y.
Любимый пример программистами на Python для использования этой возможнсти:
x, y = y, x
print(x, y) # Значения поменялись местами
20 10
Давайте вспомним, как рекомендовалось делать перебор элементов списка с индексами:
a = [10, 20, 30]
for x in a:
print(x)
for ind, x in enumerate(a):
print(ind, x)
10 20 30 0 10 1 20 2 30
Идея в том, что enumerate
это последовательность из tuple (0, 10)
(1, 20)
(2, 30)
. Когда срабатывает ind, x = (0, 10)
, ind
становится 0, x
становится 10.
Лист комприхеншон. Это удобный способ создавать списки, обрабатывать последовательности.
l = [10, 20, 30]
l2 = [x + 1 for x in l]
print(l2)
[11, 21, 31]
В общем случае вы пишете [
выражение c переменной for
переменная in
последовательность ]
. Переменной по очереди присваиваются все элементы последовательности, для каждого элемента последовательности вычисляется выражения, значения выражений собираются в новый список.
['x' * i for i in range(10)]
['', 'x', 'xx', 'xxx', 'xxxx', 'xxxxx', 'xxxxxx', 'xxxxxxx', 'xxxxxxxx', 'xxxxxxxxx']
[str(i) for i in range(10)] # строки с числами от 0 до 9
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
['(' + s + ')' for s in ("cat", "dog", "cow")] # перебор tuple
['(cat)', '(dog)', '(cow)']
Есть другие возможности, можно добавлять условия, делать двойные переборы и все это совмещать
#if показывает, какие элементы должны попасть в результат
[x for x in range(10) if x % 3 != 0]
[1, 2, 4, 5, 7, 8]
[x // 3 for x in range(10) if x % 3 == 0]
[0, 1, 2, 3]
# присваивает значение первой пеменной, перебирает вторую
# потом присваивает новое значение первой переменной, снова перебирает вторую
# и т.д.
[(i, j) for i in range(4) for j in range(4)]
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3), (3, 0), (3, 1), (3, 2), (3, 3)]
l = [[10, 20, 30], ['a', 'b', 'c'], [True, False]]
[x for sublist in l for x in sublist] # получился "плоский" список
[10, 20, 30, 'a', 'b', 'c', True, False]
Вложенные переборы, if можно чередовать, очень много возможностей по обработке списков одними только list comprehension.