Кафедра дискретной математики МФТИ

Курс математической статистики

Никита Волков

На основе http://www.inp.nsk.su/~grozin/python/

Python

При программировании на питоне первые полезные результаты начинают получаться минут через 5 после начала работы над проектом. Не надо изобретать никаких велосипедов: всё, что может понадобиться, доступно или в стандартной библиотеке, или в одном из многочисленных дополнительных пакетов. Программы получаются элегантные и лаконичные, их легко и приятно писать и читать. Имеется широкий выбор высококачественных инструментов программиста: интегрированные среды разработки, отладчики и средства тестирования и т.д. Питон прекрасно приспособлен для написания больших и сложных программных комплексов. И всё это совершенно не зависит от железа и операционной системы (конечно, если не вызывать низкоуровневых системно-зависимыех библиотек).

Главный минус - питон, мягко говоря, не славится потрясающим быстродействием. Писать программы сложных вычислений на питоне, конечно, глупо. Но есть ряд способов обойти это ограничение. Если программа занимается регулярной обработкой больших массивов чисел с плавающей точкой, то использование numpy радикально повышает её быстродействие. Пакет numpy и его расширение scipy фактически делают matlab ненужным - дают ту же функциональность с более приятным языком программирование. Есть ряд пакетов для построения высококачественных графиков, например, matplotlib. Другое средство повышения быстродействия - cython. Пишется программа, выглядящая почти как питонская, но со вставленными статичестими декларациями типов. cython транслирует её в исходный код на C, что часто даёт быстродействие, сравнимое с вручную написанным C. Программа на cython-е может свободно вызывать функции из библиотек на C; её можно использовать из обычного питона. Ну и наконец можно написать критически важные для быстродействия системы в целом вычисления на другом языке (C например), и вызывать эти внешние программы из питона. Питон при этом выполняет роль клея - реализует логику высокого уровня, системно-независимый GUI и т.д.

Питон - сильно типизированный язык с динамической типизацией. Всё, с чем работает программа - объекты; каждый из них принадлежит определённому типу. Если программа пытается выполнить какую-то операцию над объектом такого типа, который не поддерживает эту операцию, произойдёт ошибка времени выполнения. Описаний переменных в питоне нет. Одна и та же переменная может в разные моменты иметь значения - объекты разных типов. Ошибка в типах может проявиться много времени спустя после того, как программа сдана в эксплуатацию, особенно если она происходит в редко используемом участке кода. Язык допускает ситуацию, когда мы сначала присвоим какой-то переменной целое число, потом строку, потом ещё что-то, но это плохой стиль. Переменная заводится для одного конкретного использования, и естественно, чтобы её значения в любой момент подходили для этого использования и имели одинаковый тип. В исходный текст на питоне 3.5 можно включить (необязательные) аннотации типов переменных и функций, и прогнать её через программу статической проверки типов.

Питонячий стиль кода

Обязательно прочитайте инструкцию по стилю кода: http://pep8.ru/doc/pep8/

Желательно соблюдать стиль кода. Однако, поскольку у нас не курс программирование, то полное соблюдение стиля не требуется. Перечислим кратко основные правила:

  • Отступы составляют ровно 4 пробела, табуляции не используются. К слову, в Питоне нет ключевых слов по типу { и } в C и begin и end в Паскале. Блоки кода разделяются пробелами.
  • Все переменные должны иметь понятные названия и состоять только из строчных букв. Например, вместо того, чтобы назвать выборку как X, лучше назвать ее sample. В качестве разделителей используйте подчеркивания. В редких случаях можно и отступать от этого правила, если обозначения понятны из решаемой задачи.
  • Вокруг всех знаков арифметических операций, присваивания и пр. обязательны пробелы с двух сторон. Исключение - запись вида a=b в аргументах функции. Примеры будут далее.
  • Разделяйте логические куски программы пустыми строками. Врядли вы сможете написать код строк на 10-15, в который нельзя вставить ни одну пустую строку, разделяющую код на логические части. ПЕРЕД всеми логическими кусками кода должен быть комментарий к этому куску кода.
  • Все функции (кроме самых маленьких) должны содержать подробную документацию, написанную по правилам оформления документаций.
  • Если комментарий дается на строке с кодом, то оформить его стоит так:

код [ровно 2 пробела] # [ровно 1 пробел] комментарий

  • Если комментарий дается на отдельной строке, то он должен иметь тот же отступ, что и строка кода под ним. Скорее всего перед таким комментарием можно вставить пустую строку.
  • Не нужно комментировать очевидное.
  • Не нужно писать весь код в одной ячейке ноутбука!!!
  • Если есть возможность, при выводе десятичных чисел следует оставлять разумное число знаков после запятой.

Отдельно стоит отметить, что код должен быть понятен проверяющему. В частности, должны использоваться понятные названия переменных и присутствовать подробные комментарии. Если проверяющий не поймет код, оценка за задание может быть снижена, и будет пичалька.

Числа

Арифметические операции имеют ожидаемые приоритеты. При необходимости используются скобки.


In [1]:
1 + 2 * 3


Out[1]:
7

In [2]:
(1 + 2) * 3


Out[2]:
9

Возведение целого числа в целую степень даёт целое число, если показатель степени $\ge0$, и число с плавающей точкой, если он $<0$. Так что тип результата невозможно определить статически, если значение переменной n неизвестно.


In [3]:
n = 3
2 ** n


Out[3]:
8

In [4]:
n = -3
2 ** n


Out[4]:
0.125

Арифметические операции можно применять к целым и числам с плавающей точкой в любых сочетаниях.


In [5]:
n + 1.0


Out[5]:
-2.0

Деление целых чисел всегда даёт результат с плавающей точкой, даже если они делятся нацело. Операторы // и % дают целое частное и остаток.


In [6]:
7 / 4


Out[6]:
1.75

In [7]:
7 // 4


Out[7]:
1

In [8]:
7 % 4


Out[8]:
3

In [9]:
4 / 2


Out[9]:
2.0

Если Вы попытаетесь использовать переменную, которой не присвоено никакого значения, то получите сообщение об ошибке.


In [10]:
x


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-10-401b30e3b8b5> in <module>()
----> 1 x

NameError: name 'x' is not defined

x+=1 означает x=x+1, аналогично для других операций. В питоне строго различаются операторы (например, присваивание) и выражения, так что таких операций, как ++ в C, нет. Хотя вызов функции в выражении может приводить к побочным эффектам.


In [11]:
x = 1
x += 1
print(x)


2

In [12]:
x *= 2
print(x)


4

Удаление объекта


In [13]:
del x
x


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-13-726510e32795> in <module>()
      1 del x
----> 2 x

NameError: name 'x' is not defined

In [14]:
x = 4

Любопытная особенность питона: можно использовать привычные из математики сравнения вроде $x<y<z$, которые в других языках пришлось бы записывать как x<y and y<z.


In [15]:
1 < 2 <= 2


Out[15]:
True

In [16]:
1 < 2 < 2


Out[16]:
False

Логические выражения можно комбинировать с помощью and и or (эти операции имеют более низкий приоритет, чем сравнения). Если результат уже ясен из первого операнда, второй операнд не вычисляется. А вот так выглядит оператор if.


In [17]:
if 1 < 2 and x < 3:
    print('T')
else:
    print('F')


F

In [18]:
if 1 < 2 or x < 3:
    print('T')
else:
    print('F')


T

После строчки, заканчивающейся :, можно писать последовательность операторов с одинаковым отступом (больше, чем у строчки if). Никакого признака конца такой группы операторов не нужно. Первая строчка после else:, имеющая тот же уровень отступа, что и if и else: - это следующий оператор после if.

Оператора, аналогичного case или switch, в питоне нет. Используйте длинную последовательность if ... elif ... elif ... else.


In [19]:
n = 4
if n == 1:
    print('один')
elif n == 2:
    print('два')
elif n == 3:
    print('три')
else:
    print('много')


много

Есть и условные выражения:


In [20]:
(0 if x < 0 else 1) + 1


Out[20]:
2

Обычно в начале пишется основное выражение, оно защищается условием в if, а после else пишется исключительный случай.

В питоне немного встроенных функций. Большинство надо импортировать. Элементарные функции импортируют из модуля math. Заниматься импортозамещением (писать свою реализацию синуса) не нужно.


In [21]:
from math import sin, pi

In [22]:
pi


Out[22]:
3.141592653589793

In [23]:
round(pi, 2)


Out[23]:
3.14

In [24]:
print('{:.2f}'.format(pi))


3.14

In [25]:
sin(pi / 6)


Out[25]:
0.49999999999999994

Любой объект имеет тип.


In [26]:
type(2)


Out[26]:
int

In [27]:
type(int)


Out[27]:
type

In [28]:
type(type)


Out[28]:
type

In [29]:
type(2.1)


Out[29]:
float

In [30]:
type(True)


Out[30]:
bool

Имена типов по совместительству являются функциями, преобразующими в этот тип объекты других типов (если такое преобразование имеет смысл).


In [31]:
float(2)


Out[31]:
2.0

In [32]:
int(2.0)


Out[32]:
2

In [33]:
int(2.9)


Out[33]:
2

In [34]:
int(-2.9)


Out[34]:
-2

Преобразование числа с плавающей точкой в целое производится путём отбрасывания дробной части, а не округления.

Строки

Питон хорошо приспособлен для работы с текстовой информацией. В нём есть много операций для работы со строками, несколько способов записи строк (удобных в разных случаях). В современных версиях питона (3.x) строки юникодные, т.е. они могут содержать одновременно русские и греческие буквы, немецкие умляуты и китайские иероглифы.


In [35]:
s = 'Какая-нибудь строка \u00F6 \u03B1 \u2230 \u342A'
print(s)


Какая-нибудь строка ö α ∰ 㐪

In [36]:
'Эта строка может содержать " внутри'


Out[36]:
'Эта строка может содержать " внутри'

In [37]:
"Эта строка может содержать ' внутри"


Out[37]:
"Эта строка может содержать ' внутри"

In [38]:
s = 'Эта содержит и \', и \"'
print(s)


Эта содержит и ', и "

In [39]:
s = """Строка,
занимающая
несколько
строчек
"""
print(s)


Строка,
занимающая
несколько
строчек


In [40]:
s == "Строка,\nзанимающая\nнесколько\nстрочек\n"


Out[40]:
True

Несколько строковых литералов, разделённых лишь пробелами, слипаются в одну строку. Подчеркнём ещё раз: это должны быть литералы, а не переменные со строковыми значениями. Такой способ записи особенно удобен, когда нужно передать длинную строку при вызове функции.


In [41]:
s = 'Такие ' 'строки ' 'слипаются'
print(s)


Такие строки слипаются

In [42]:
print('Такие\n'
      'строки\n'
      'слипаются')


Такие
строки
слипаются

В питоне нет специального типа char, его роль играют строки длины 1. Функция ord возвращает (юникодный) номер символа, а обратная ей функция chr возвращает символ (строку длины 1).


In [43]:
n = ord('а')
n


Out[43]:
1072

In [44]:
chr(n)


Out[44]:
'а'

Функция len возвращает длину строки. Она применима не только к строкам, но и к спискам, словарям и многим другим типам, про объекты которых разумно спрашивать, какая у них длина.


In [45]:
s = '0123456789'
len(s)


Out[45]:
10

Символы в строке индексируются с 0. Отрицательные индексы используются для счёта с конца: s[-1] - последний символ в строке, и т.д.


In [46]:
s[0]


Out[46]:
'0'

In [47]:
s[3]


Out[47]:
'3'

In [48]:
s[-1]


Out[48]:
'9'

In [49]:
s[-2]


Out[49]:
'8'

Можно выделить подстроку, указав диапазон индексов. Подстрока включает символ, соответствующий началу диапазона, но не включает соответствующий концу. Удобно представлять себе, что индексы соответствуют положениям между символами строки. Тогда подстрока s[n:m] будет расположена между индексами n и m.


In [50]:
s[1:3]


Out[50]:
'12'

In [51]:
s[:3]


Out[51]:
'012'

In [52]:
s[3:]


Out[52]:
'3456789'

In [53]:
s[:-1]


Out[53]:
'012345678'

In [54]:
s[3:-2]


Out[54]:
'34567'

In [55]:
s[::2]


Out[55]:
'02468'

Если не указано начало диапазона, подразумевается от начала строки; если не указан его конец - до конца строки.

Строки являются неизменяемым типом данных. Построив строку, нельзя изменить в ней один или несколько символов. Операции над строками строят новые строки - результаты, не меняя своих операндов. Сложение строк означает конкатенацию, а умножение на целое число (с любой стороны) - повторение строки несколько раз.


In [56]:
s = 'abc'; t = 'def'
s + t


Out[56]:
'abcdef'

In [57]:
s * 3


Out[57]:
'abcabcabc'

Операция in проверяет, содержится ли символ (или подстрока) в строке.


In [58]:
'a' in s


Out[58]:
True

In [59]:
'd' in s


Out[59]:
False

In [60]:
'ab' in s


Out[60]:
True

In [61]:
'b' not in s


Out[61]:
False

У объектов типа строка есть большое количество методов. Метод lstrip удаляет все whitespace-символы (пробел, tab, newline) в начале строки; rstrip - в конце; а strip - с обеих сторон. Им можно передать необязательный аргумент - символы, которые нужно удалять.


In [62]:
'   строка   '.lstrip()


Out[62]:
'строка   '

In [63]:
'   строка   '.rstrip()


Out[63]:
'   строка'

In [64]:
'   строка   '.strip()


Out[64]:
'строка'

lower и upper переводят все буквы в маленькие и заглавные.


In [65]:
'СтРоКа'.lower()


Out[65]:
'строка'

In [66]:
'СтРоКа'.upper()


Out[66]:
'СТРОКА'

Проверки: буквы (маленькие и заглавные), цифры, пробелы.


In [67]:
'АбВг'.isalpha()


Out[67]:
True

In [68]:
'абвг'.islower()


Out[68]:
True

In [69]:
'АБВГ'.isupper()


Out[69]:
True

In [70]:
'0123'.isdigit()


Out[70]:
True

In [71]:
' \t\n'.isspace()


Out[71]:
True

Строки имеют тип str.


In [72]:
type(s)


Out[72]:
str

In [73]:
s = str(123)
s


Out[73]:
'123'

In [74]:
n = int(s)
n


Out[74]:
123

In [75]:
int('123x')


---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-75-528edaa9c06f> in <module>()
----> 1 int('123x')

ValueError: invalid literal for int() with base 10: '123x'

In [76]:
x = float('123.456E-7')
x


Out[76]:
1.23456e-05

Метод format особенно полезен для вывода.


In [77]:
'str: {}  int: {}  float: {}'.format(s, n, x)


Out[77]:
'str: 123  int: 123  float: 1.23456e-05'

Ширина поля 5 (больше, если не влезет); десятичный, шестнадцатиричный и двоичный форматы.


In [78]:
print('''{:5d}
{:5x}
{:5b}'''.format(n, n, n))


  123
   7b
1111011

Ширина поля 10 (больше, если не влезет); после десятичной точки 5 цифр; формат с фиксированной точкой или экспоненциальный.


In [79]:
print('''{:10.5f}
{:10.5e}
{:10.5f}
{:10.5e}'''.format(x, x, 1 / x, 1 / x))


   0.00001
1.23456e-05
81000.51840
8.10005e+04

Списки

Списки могут содержать объекты любых типов (в одном списке могут быть объекты разных типов). Списки индексируются так же, как строки.


In [80]:
l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
l


Out[80]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [81]:
len(l)


Out[81]:
10

In [82]:
l[0]


Out[82]:
0

In [83]:
l[3]


Out[83]:
3

In [84]:
l[10]


---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-84-e4a648ff0fa9> in <module>()
----> 1 l[10]

IndexError: list index out of range

In [85]:
l[-1]


Out[85]:
9

In [86]:
l[-2]


Out[86]:
8

In [87]:
l[1:3]


Out[87]:
[1, 2]

Обратите внимание, что l[:3]+l[3:]==l.


In [88]:
l[:3]


Out[88]:
[0, 1, 2]

In [89]:
l[3:]


Out[89]:
[3, 4, 5, 6, 7, 8, 9]

In [90]:
l[3:3]


Out[90]:
[]

In [91]:
l[3:-2]


Out[91]:
[3, 4, 5, 6, 7]

In [92]:
l[:-2]


Out[92]:
[0, 1, 2, 3, 4, 5, 6, 7]

Списки являются изменяемыми объектами. Это сделано для эффективности. В списке может быть 1000000 элементов. Создавать его копию каждый раз, когда мы изменили один элемент, слишком дорого.


In [93]:
l[3] = 'три'
l


Out[93]:
[0, 1, 2, 'три', 4, 5, 6, 7, 8, 9]

Можно заменить какой-нибудь подсписок на новый список (в том числе другой длины).


In [94]:
l[3:3] = [0]
l


Out[94]:
[0, 1, 2, 0, 'три', 4, 5, 6, 7, 8, 9]

In [95]:
l[3:3] = [10, 11, 12]
l


Out[95]:
[0, 1, 2, 10, 11, 12, 0, 'три', 4, 5, 6, 7, 8, 9]

In [96]:
l[5:7] = [0, 0, 0, 0]
l


Out[96]:
[0, 1, 2, 10, 11, 0, 0, 0, 0, 'три', 4, 5, 6, 7, 8, 9]

In [97]:
l[3:] = []
l


Out[97]:
[0, 1, 2]

In [98]:
l[len(l):] = [3, 4]
l


Out[98]:
[0, 1, 2, 3, 4]

Некоторые из этих операций могут быть записаны в другой форме.


In [99]:
l = [0, 1, 2, 3, 4, 5, 6, 7]
del l[3]
l


Out[99]:
[0, 1, 2, 4, 5, 6, 7]

In [100]:
del l[3:5]
l


Out[100]:
[0, 1, 2, 6, 7]

In [101]:
l.insert(3, 0)
l


Out[101]:
[0, 1, 2, 0, 6, 7]

In [102]:
l.append(8)
l


Out[102]:
[0, 1, 2, 0, 6, 7, 8]

In [103]:
l.extend([9, 10, 11])
l


Out[103]:
[0, 1, 2, 0, 6, 7, 8, 9, 10, 11]

Элементы списка могут быть разных типов.


In [104]:
l = [0, [1, 2, 3], 'abc']
l[1][1] = 'x'
l


Out[104]:
[0, [1, 'x', 3], 'abc']

Когда мы пишем m=l, мы присваиваем переменной m ссылку на тот же объект, на который ссылается l. Поэтому, изменив этот объект (список) через l, мы увидим эти изменения и через m - ведь список всего один.


In [105]:
l = [0, 1, 2, 3, 4, 5]
m = l
l[3] = 'три'
m


Out[105]:
[0, 1, 2, 'три', 4, 5]

Операция is проверяет, являются ли m и l одним и тем же объектом.


In [106]:
m is l


Out[106]:
True

Если мы хотим видоизменять m и l независимо, нужно присвоить переменной m не список l, а его копию. Тогда это будут два различных списка, просто в начальный момент они состоят из одних и тех же элементов. Для этого в питоне есть идиома: l[:] - это подсписок списка l от начала до конца, а подсписок всегда копируется.


In [107]:
m = l[:]

Теперь m и l - два независимых объекта, имеющих равные значения.


In [108]:
m is l


Out[108]:
False

In [109]:
m == l


Out[109]:
True

Их можно менять независимо.


In [110]:
l[3] = 0
l


Out[110]:
[0, 1, 2, 0, 4, 5]

In [111]:
m


Out[111]:
[0, 1, 2, 'три', 4, 5]

Как и для строк, сложение списков означает конкатенацию, а умножение на целое число - повторение списка несколько раз. Операция in проверяет, содержится ли элемент в списке.


In [112]:
[0, 1, 2] + [3, 4, 5]


Out[112]:
[0, 1, 2, 3, 4, 5]

In [113]:
2 * [0, 1, 2]


Out[113]:
[0, 1, 2, 0, 1, 2]

In [114]:
l = [0, 1, 2]
l += [3, 4, 5]
l


Out[114]:
[0, 1, 2, 3, 4, 5]

In [115]:
2 in l


Out[115]:
True

Простейший вид цикла в питоне - это цикл по элементам списка.


In [116]:
for x in l:
    print(x)


0
1
2
3
4
5

Можно использовать цикл while. В этом примере он выполняется, пока список l не пуст. Этот цикл гораздо менее эффективен, чем предыдущий - в нём на каждом шаге меняется список l. Он тут приведён не для того, чтобы ему подражали, а просто чтобы показать синтаксис цикла while.


In [117]:
while l:
    print(l[0])
    l = l[1:]


0
1
2
3
4
5

In [118]:
l


Out[118]:
[]

Очень часто используются циклы по диапазонам целых чисел.


In [119]:
for i in range(4):
    print(i)


0
1
2
3

Функция range(n) возвращает диапазон целых чисел от 0 до $n-1$ (всего $n$ штук) в виде специального объекта range, который можно использовать в for цикле. Можно превратить этот объект в список функцией list. Но этого делать не нужно, если только такой список не нужен для проведения каких-нибудь списковых операций. Число n может быть равно 1000000. Зачем занимать память под длинный список, если он не нужен? Для написания цикла достаточно короткого объекта range, который хранит только пределы.


In [120]:
r = range(4)
r


Out[120]:
range(0, 4)

In [121]:
list(r)


Out[121]:
[0, 1, 2, 3]

Функции range можно передать первый параметр - нижний предел.


In [122]:
for i in range(2, 4):
    print(i)


2
3

In [123]:
r = range(2, 4)
r


Out[123]:
range(2, 4)

In [124]:
list(r)


Out[124]:
[2, 3]

Можно также передать шаг третьим аргументом


In [125]:
for i in range(1, 10, 2):
    print(i)


1
3
5
7
9

In [126]:
r = range(1, 10, 2)
r


Out[126]:
range(1, 10, 2)

In [127]:
list(r)


Out[127]:
[1, 3, 5, 7, 9]

Функция list превращает строку в список символов.


In [128]:
l = list('абвгд')
l


Out[128]:
['а', 'б', 'в', 'г', 'д']

Как написать цикл, если в его теле нужно использовать и номера элементов списка, и сами эти элементы? Первая идея, которая приходит в голову по аналогии с C - это использовать range.


In [129]:
for i in range(len(l)):
    print(i, '  ', l[i])


0    а
1    б
2    в
3    г
4    д

Можно поступить наоборот - устроить цикл по элементам списка, а индексы вычислять.


In [130]:
i = 0
for x in l:
    print(i, '  ', x)
    i += 1


0    а
1    б
2    в
3    г
4    д

Оба этих способа не есть идиоматический питон. Более изящно использовать функцию enumerate, которая на каждом шаге возвращает пару из индекса i и i-го элемента списка.


In [131]:
for i, x in enumerate(l):
    print(i, '  ', x)


0    а
1    б
2    в
3    г
4    д

Про такие пары мы поговорим в следующем параграфе.

Довольно часто удобно использовать цикл while True:, то есть пока рак на горе не свистнет, а выход (или несколько выходов) из него устраивать в нужном месте (или местах) при помощи break.


In [132]:
while True:
    print(l[-1])
    l = l[:-1]
    if l == []:
        break


д
г
в
б
а

Этот конкретный цикл - отнюдь не пример для подражания, он просто показывает синтаксис.

Можно строить список поэлементно.


In [133]:
l = []
for i in range(10):
    l.append(i ** 2)
l


Out[133]:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Но более компактно и элегантно такой список можно создать при помощи генератора списка (list comprehension). К тому же это эффективнее - размер списка известен заранее, и не нужно много раз увеличивать его. Опытные питон-программисты используют генераторы списков везде, где это возможно (и разумно).


In [134]:
[i ** 2 for i in range(10)]


Out[134]:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

In [135]:
[[i, j] for i in range(3) for j in range(2)]


Out[135]:
[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]

В генераторе списков могут присутствовать некоторые дополнительные элементы, хотя они используются реже. Например, в список-результат можно включить не все элементы.


In [136]:
[i ** 2 for i in range(10) if i != 5]


Out[136]:
[0, 1, 4, 9, 16, 36, 49, 64, 81]

Создадим список случайных целых чисел.


In [137]:
from random import randint

In [138]:
l = [randint(0, 9) for i in range(10)]
l


Out[138]:
[6, 1, 1, 1, 7, 3, 7, 7, 2, 0]

Функция sorted возвращает отсортированную копию списка. Метод sort сортирует список на месте. Им можно передать дополнительный параметр - функцию, указывающую, как сравнивать элементы.


In [139]:
sorted(l)


Out[139]:
[0, 1, 1, 1, 2, 3, 6, 7, 7, 7]

In [140]:
l


Out[140]:
[6, 1, 1, 1, 7, 3, 7, 7, 2, 0]

In [141]:
l.sort()
l


Out[141]:
[0, 1, 1, 1, 2, 3, 6, 7, 7, 7]

Аналогично, функция reversed возвращает обращённый список (точнее говоря, некий объект, который можно использовать в for цикле или превратить в список функцией list). Метод reverse обращает список на месте.


In [142]:
list(reversed(l))


Out[142]:
[7, 7, 7, 6, 3, 2, 1, 1, 1, 0]

In [143]:
l


Out[143]:
[0, 1, 1, 1, 2, 3, 6, 7, 7, 7]

In [144]:
l.reverse()
l


Out[144]:
[7, 7, 7, 6, 3, 2, 1, 1, 1, 0]

Метод split расщепляет строку в список подстрок. По умолчанию расщепление производится по пустым промежуткам (последовательностям пробелов и символов tab и newline). Но можно передать ему дополнительный аргумент - подстроку-разделитель.


In [145]:
s = 'abc \t def \n ghi'
l = s.split()
l


Out[145]:
['abc', 'def', 'ghi']

Чтобы напечатать элементы списка через запятую или какой-нибудь другой символ (или строку), очень полезен метод join. Он создаёт строку из всех элементов списка, разделяя их строкой-разделителем. Запрограммировать это в виде цикла было бы существенно длиннее, и такую программу было бы сложнее читать.


In [146]:
s = ', '.join(l)
s


Out[146]:
'abc, def, ghi'

In [147]:
s.split(', ')


Out[147]:
['abc', 'def', 'ghi']