summaryrefslogtreecommitdiffhomepage
path: root/ru-ru/python-ru.html.markdown
blob: b1aeec2adebf2c89892ce74f9e7afd5fc986a3fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
---
language: Python
lang: ru-ru
contributors:
    - ["Louie Dinh", "http://ldinh.ca"]
    - ["Steven Basart", "http://github.com/xksteven"]
translators:
    - ["Andre Polykanine", "https://github.com/Oire"]
    - ["Anton Grouchtchak", "https://github.com/Teraskull"]
filename: learnpython-ru.py
---

Язык Python был создан Гвидо ван Россумом в начале 90-х. Сейчас это один из
самых популярных языков. Я влюбился в Python за понятный и доходчивый синтаксис — это
почти что исполняемый псевдокод.

Замечание: Эта статья относится только к Python 3.
Если вы хотите изучить Python 2.7, обратитесь к [другой статье](/docs/ru-ru/pythonlegacy-ru/).

```python
# Однострочные комментарии начинаются с символа решётки.

""" Многострочный текст может быть
    записан, используя 3 знака " и обычно используется
    в качестве встроенной документации
"""

####################################################
## 1. Примитивные типы данных и операторы
####################################################

# У вас есть числа
3  # => 3

# Математика работает вполне ожидаемо
1 + 1   # => 2
8 - 1   # => 7
10 * 2  # => 20
35 / 5  # => 7.0

# Результат целочисленного деления округляется в меньшую сторону
# как для положительных, так и для отрицательных чисел.
5 // 3       # => 1
-5 // 3      # => -2
5.0 // 3.0   # => 1.0  # работает и для чисел с плавающей запятой
-5.0 // 3.0  # => -2.0

# Результат деления возвращает число с плавающей запятой
10.0 / 3  # => 3.3333333333333335

# Остаток от деления
7 % 3  # => 1

# Возведение в степень
2**3  # => 8

# Приоритет операций указывается скобками
1 + 3 * 2    # => 7
(1 + 3) * 2  # => 8

# Булевы значения - примитивы (Обратите внимание на заглавную букву)
True   # => True
False  # => False

# Для отрицания используется ключевое слово not
not True   # => False
not False  # => True

# Булевы операторы
# Обратите внимание: ключевые слова "and" и "or" чувствительны к регистру букв
True and False  # => False
False or True   # => True

# True и False на самом деле 1 и 0, но с разными ключевыми словами
True + True  # => 2
True * 8     # => 8
False - 5    # => -5

# Операторы сравнения обращают внимание на числовое значение True и False
0 == False   # => True
1 == True    # => True
2 == True    # => False
-5 != False  # => True

# Использование булевых логических операторов на типах int превращает их в булевы значения, но возвращаются оригинальные значения
# Не путайте с bool(ints) и bitwise and/or (&,|)
bool(0)   # => False
bool(4)   # => True
bool(-6)  # => True
0 and 2   # => 0
-5 or 0   # => -5

# Равенство — это ==
1 == 1  # => True
2 == 1  # => False

# Неравенство — это !=
1 != 1  # => False
2 != 1  # => True

# Ещё немного сравнений
1 < 10  # => True
1 > 10  # => False
2 <= 2  # => True
2 >= 2  # => True

# Проверка, находится ли значение в диапазоне
1 < 2 and 2 < 3  # => True
2 < 3 and 3 < 2  # => False

# Сравнения могут быть записаны цепочкой
1 < 2 < 3  # => True
2 < 3 < 2  # => False

# (is vs. ==) ключевое слово is проверяет, относятся ли две переменные к одному и тому же объекту, но == проверяет если указанные объекты имеют одинаковые значения.
a = [1, 2, 3, 4]  # a указывает на новый список, [1, 2, 3, 4]
b = a             # b указывает на то, что указывает a
b is a            # => True, a и b относятся к одному и тому же объекту
b == a            # => True, Объекты a и b равны
b = [1, 2, 3, 4]  # b указывает на новый список, [1, 2, 3, 4]
b is a            # => False, a и b не относятся к одному и тому же объекту
b == a            # => True, Объекты a и b равны

# Строки определяются символом " или '
"Это строка."
'Это тоже строка.'

# И строки тоже могут складываться!
"Привет " + "мир!"  # => "Привет мир!"

# Строки (но не переменные) могут быть объединены без использования '+'
"Привет " "мир!"  # => "Привет мир!"

# Со строкой можно работать, как со списком символов
"Привет мир!"[0]  # => 'П'

# Вы можете найти длину строки
len("Это строка")  # => 10

# Вы также можете форматировать, используя f-строки (в Python 3.6+)
name = "Рейко"
f"Она сказала, что ее зовут {name}."  # => "Она сказала, что ее зовут Рейко"
# Вы можете поместить любой оператор Python в фигурные скобки, и он будет выведен в строке.
f"{name} состоит из {len(name)} символов."  # => "Рэйко состоит из 5 символов."


# None является объектом
None  # => None

# Не используйте оператор равенства "==" для сравнения
# объектов с None. Используйте для этого "is"
"etc" is None  # => False
None is None   # => True

# None, 0 и пустые строки/списки/словари/кортежи приводятся к False.
# Все остальные значения равны True
bool(0)   # => False
bool("")  # => False
bool([])  # => False
bool({})  # => False
bool(())  # => False


####################################################
## 2. Переменные и Коллекции
####################################################

# В Python есть функция Print
print("Я Python. Приятно познакомиться!")  # => Я Python. Приятно познакомиться!

# По умолчанию, функция print() также выводит новую строку в конце.
# Используйте необязательный аргумент end, чтобы изменить конец последней строки.
print("Привет мир", end="!")  # => Привет мир!

# Простой способ получить входные данные из консоли
input_string_var = input("Введите данные: ")  # Возвращает данные в виде строки
# Примечание: в более ранних версиях Python метод input() назывался raw_input()

# Объявлять переменные перед инициализацией не нужно.
# По соглашению используется нижний_регистр_с_подчёркиваниями
some_var = 5
some_var  # => 5

# При попытке доступа к неинициализированной переменной выбрасывается исключение.
# Об исключениях см. раздел "Поток управления и итерируемые объекты".
some_unknown_var  # Выбрасывает ошибку NameError

# if можно использовать как выражение
# Эквивалент тернарного оператора '?:' в C
"да!" if 0 > 1 else "нет!"  # => "нет!"

# Списки хранят последовательности
li = []
# Можно сразу начать с заполненного списка
other_li = [4, 5, 6]

# Объекты добавляются в конец списка методом append()
li.append(1)  # [1]
li.append(2)  # [1, 2]
li.append(4)  # [1, 2, 4]
li.append(3)  # [1, 2, 4, 3]
# И удаляются с конца методом pop()
li.pop()      # => возвращает 3 и li становится равен [1, 2, 4]
# Положим элемент обратно
li.append(3)  # [1, 2, 4, 3].

# Обращайтесь со списком, как с обычным массивом
li[0]  # => 1

# Обратимся к последнему элементу
li[-1]  # => 3

# Попытка выйти за границы массива приведёт к ошибке индекса
li[4]  # Выбрасывает ошибку IndexError

# Можно обращаться к диапазону, используя так называемые срезы
# (Для тех, кто любит математику, это называется замкнуто-открытый интервал).
li[1:3]   # Вернуть список из индекса с 1 по 3 => [2, 4]
li[2:]    # Вернуть список, начиная с индекса 2 => [4, 3]
li[:3]    # Вернуть список с начала до индекса 3  => [1, 2, 4]
li[::2]   # Вернуть список, выбирая каждую вторую запись => [1, 4]
li[::-1]  # Вернуть список в обратном порядке => [3, 4, 2, 1]
# Используйте сочетания всего вышеназванного для выделения более сложных срезов
# li[начало:конец:шаг]

# Сделать однослойную глубокую копию, используя срезы
li2 = li[:]  # => li2 = [1, 2, 4, 3], но (li2 is li) вернет False.

# Удаляем произвольные элементы из списка оператором del
del li[2]  # [1, 2, 3]

# Удалить первое вхождение значения
li.remove(2)  # [1, 3]
li.remove(2)  # Выбрасывает ошибку ValueError поскольку 2 нет в списке

# Вставить элемент по определенному индексу
li.insert(1, 2)  # [1, 2, 3]

# Получить индекс первого найденного элемента, соответствующего аргументу
li.index(2)  # => 1
li.index(4)  # Выбрасывает ошибку ValueError поскольку 4 нет в списке

# Вы можете складывать, или, как ещё говорят, конкатенировать списки
# Обратите внимание: значения li и other_li при этом не изменились.
li + other_li  # => [1, 2, 3, 4, 5, 6]

# Объединять списки можно методом extend()
li.extend(other_li)  # Теперь li содержит [1, 2, 3, 4, 5, 6]

# Проверить элемент на наличие в списке можно оператором in
1 in li  # => True

# Длина списка вычисляется функцией len
len(li)  # => 6


# Кортежи похожи на списки, только неизменяемые
tup = (1, 2, 3)
tup[0]  # => 1
tup[0] = 3  # Выбрасывает ошибку TypeError

# Обратите внимание, что кортеж длины 1 должен иметь запятую после последнего элемента, но кортежи другой длины, даже 0, не должны.
type((1))   # => <class 'int'>
type((1,))  # => <class 'tuple'>
type(())    # => <class 'tuple'>

# Всё то же самое можно делать и с кортежами
len(tup)         # => 3
tup + (4, 5, 6)  # => (1, 2, 3, 4, 5, 6)
tup[:2]          # => (1, 2)
2 in tup         # => True

# Вы можете распаковывать кортежи (или списки) в переменные
a, b, c = (1, 2, 3)  # a == 1, b == 2 и c == 3
# Вы также можете сделать расширенную распаковку
a, *b, c = (1, 2, 3, 4)  # a теперь 1, b теперь [2, 3] и c теперь 4
# Кортежи создаются по умолчанию, если опущены скобки
d, e, f = 4, 5, 6  # кортеж 4, 5, 6 распаковывается в переменные d, e и f
# соответственно, d = 4, e = 5 и f = 6
# Обратите внимание, как легко поменять местами значения двух переменных
e, d = d, e  # теперь d == 5, а e == 4


# Словари содержат ассоциативные массивы
empty_dict = {}
# Вот так описывается предзаполненный словарь
filled_dict = {"one": 1, "two": 2, "three": 3}

# Обратите внимание, что ключи для словарей должны быть неизменяемыми типами. Это
# сделано для того, чтобы ключ мог быть преобразован в хеш для быстрого поиска.
# Неизменяемые типы включают целые числа, числа с плавающей запятой, строки, 
# кортежи.
invalid_dict = {[1,2,3]: "123"}  # => Выбрасывает ошибку TypeError: unhashable type: 'list'
valid_dict = {(1,2,3):[1,2,3]}   # Однако значения могут быть любого типа.

# Поиск значений с помощью []
filled_dict["one"]  # => 1

# Все ключи в виде списка получаются с помощью метода keys(). Его вызов нужно
# обернуть в list(), так как обратно мы получаем итерируемый объект, о которых
# поговорим позднее. Примечание - для Python версии <3.7, порядок словарных
# ключей не гарантируется. Ваши результаты могут не точно соответствовать
# приведенному ниже примеру. Однако, начиная с Python 3.7 элементы в словаре
# сохраняют порядок, в котором они вставляются в словарь.
list(filled_dict.keys())  # => ["three", "two", "one"] в Python <3.7
list(filled_dict.keys())  # => ["one", "two", "three"] в Python 3.7+


# Все значения в виде списка можно получить с помощью values().
# И снова нам нужно обернуть вызов в list(), чтобы превратить
# итерируемый объект в список.
# То же самое замечание насчёт порядка ключей справедливо и здесь
list(filled_dict.values())  # => [3, 2, 1] в Python <3.7
list(filled_dict.values())  # => [1, 2, 3] в Python 3.7+

# При помощи ключевого слова in можно проверять наличие ключей в словаре
"one" in filled_dict  # => True
1 in filled_dict      # => False

# Попытка получить значение по несуществующему ключу выбросит ошибку KeyError
filled_dict["four"]  # Выбрасывает ошибку KeyError

# Чтобы избежать этого, используйте метод get()
filled_dict.get("one")      # => 1
filled_dict.get("four")     # => None
# Метод get поддерживает аргумент по умолчанию, когда значение отсутствует
filled_dict.get("one", 4)   # => 1
filled_dict.get("four", 4)  # => 4

# Метод setdefault() вставляет пару ключ-значение, только если такого ключа нет
filled_dict.setdefault("five", 5)  # filled_dict["five"] возвращает 5
filled_dict.setdefault("five", 6)  # filled_dict["five"] по-прежнему возвращает 5

# Добавление элементов в словарь
filled_dict.update({"four":4})  # => {"one": 1, "two": 2, "three": 3, "four": 4}
filled_dict["four"] = 4         # Другой способ добавления элементов

# Удаляйте ключи из словаря с помощью ключевого слова del
del filled_dict["one"]  # Удаляет ключ "one" из словаря

# В Python 3.5+ вы также можете использовать дополнительные параметры распаковки
{'a': 1, **{'b': 2}}  # => {'a': 1, 'b': 2}
{'a': 1, **{'a': 2}}  # => {'a': 2}


# Множества содержат... ну, в общем, множества
empty_set = set()
# Инициализация множества набором значений.
# Да, оно выглядит примерно как словарь. Ну извините, так уж вышло.
filled_set = {1, 2, 2, 3, 4}  # => {1, 2, 3, 4}

# Как и ключи словаря, элементы множества должны быть неизменяемыми.
invalid_set = {[1], 1}  # => Выбрасывает ошибку TypeError: unhashable type: 'list'
valid_set = {(1,), 1}

# Множеству можно назначать новую переменную
filled_set = some_set
filled_set.add(5)  # {1, 2, 3, 4, 5}
# В множествах нет повторяющихся элементов
filled_set.add(5)  # {1, 2, 3, 4, 5}

# Пересечение множеств: &
other_set = {3, 4, 5, 6}
filled_set & other_set  # => {3, 4, 5}

# Объединение множеств: |
filled_set | other_set  # => {1, 2, 3, 4, 5, 6}

# Разность множеств: -
{1, 2, 3, 4} - {2, 3, 5}  # => {1, 4}

# Симметричная разница: ^
{1, 2, 3, 4} ^ {2, 3, 5}  # => {1, 4, 5}

# Проверить, является ли множество слева надмножеством множества справа
{1, 2} >= {1, 2, 3}  # => False

# Проверить, является ли множество слева подмножеством множества справа
{1, 2} <= {1, 2, 3}  # => True

# Проверка на наличие в множестве: in
2 in filled_set   # => True
10 in filled_set  # => False

# Сделать однослойную глубокую копию
filled_set = some_set.copy()  # {1, 2, 3, 4, 5}
filled_set is some_set        # => False


####################################################
## 3. Поток управления и итерируемые объекты
####################################################

# Для начала создадим переменную
some_var = 5

# Так выглядит выражение if. Отступы в python очень важны!
# Конвенция заключается в использовании четырех пробелов, а не табуляции.
# Pезультат: "some_var меньше, чем 10"
if some_var > 10:
    print("some_var точно больше, чем 10.")
elif some_var < 10:  # Выражение elif необязательно.
    print("some_var меньше, чем 10.")
else:                # Это тоже необязательно.
    print("some_var равно 10.")


"""
Циклы For проходят по спискам.
Выводит:
    собака — это млекопитающее
    кошка — это млекопитающее
    мышь — это млекопитающее
"""
for animal in ["собака", "кошка", "мышь"]:
    # Можете использовать format() для интерполяции форматированных строк
    print("{} — это млекопитающее".format(animal))

"""
"range(число)" возвращает список чисел от нуля до заданного числа.
Выводит:
    0
    1
    2
    3
"""
for i in range(4):
    print(i)

"""
"range(начало, конец)" возвращает список чисел от начального числа 
к конечному, не включая конечное.
Выводит:
    4
    5
    6
    7
"""
for i in range(4, 8):
    print(i)

"""
"range(начало, конец, шаг)" возвращает список чисел от начального 
числа к конечному, увеличивая шаг за шагом.
Если шаг не указан, значение по умолчанию - 1.
Выводит:
    4
    6
"""
for i in range(4, 8, 2):
    print(i)

"""
Можно перебрать список и получить индекс и значение каждого элемента в списке
Выводит:
    0 собака
    1 кошка
    2 мышь
"""
animals = ["собака", "кошка", "мышь"]
for i, value in enumerate(animals):
    print(i, value)

"""
Циклы while продолжаются до тех пор, пока указанное условие не станет ложным.
Выводит:
    0
    1
    2
    3
"""
x = 0
while x < 4:
    print(x)
    x += 1  # Краткая запись для x = x + 1


# Обрабатывайте исключения блоками try/except
try:
    # Чтобы выбросить ошибку, используется raise
    raise IndexError("Это ошибка индекса")
except IndexError as e:
    pass                  # pass — это просто отсутствие оператора. Обычно здесь происходит восстановление после ошибки.
except (TypeError, NameError):
    pass                  # Можно обработать больше одного исключения.
else:                     # Необязательно. Добавляется за последним except.
    print("Всё хорошо!")  # Выполнится, только если не было никаких исключений.
finally:                  # Необязательно. Выполнить при любых обстоятельствах.
    print("Мы можем очистить ресурсы здесь")

# Вместо try/finally чтобы очистить ресурсы, можно использовать оператор with
with open("myfile.txt") as f:
    for line in f:
        print(line)

# Запись в файл
contents = {"aa": 12, "bb": 21}
with open("myfile1.txt", "w+") as file:
    file.write(str(contents))         # Записывает строку в файл

with open("myfile2.txt", "w+") as file:
    file.write(json.dumps(contents))  # Записывает объект в файл

# Чтение из файла
with open("myfile1.txt", "r+") as file:
    contents = file.read()            # Читает строку из файла
print(contents)                       # => '{"aa": 12, "bb": 21}'

with open("myfile2.txt", "r") as file:
    contents = json.load(file)        # Читает объект json из файла
print(contents)                       # => {"aa": 12, "bb": 21}


# Python предоставляет фундаментальную абстракцию,
# которая называется итерируемым объектом (Iterable).
# Итерируемый объект — это объект, который воспринимается как последовательность.
# Объект, который возвратила функция range() — итерируемый.

filled_dict = {"one": 1, "two": 2, "three": 3}
our_iterable = filled_dict.keys()
print(our_iterable)  # => dict_keys(['one', 'two', 'three']). Это объект, реализующий интерфейс Iterable

# Мы можем проходить по нему циклом.
for i in our_iterable:
    print(i)  # Выводит one, two, three

# Но мы не можем обращаться к элементу по индексу.
our_iterable[1]  # Выбрасывает ошибку TypeError

# Итерируемый объект знает, как создавать итератор.
our_iterator = iter(our_iterable)

# Итератор может запоминать состояние при проходе по объекту.
# Мы получаем следующий объект, вызывая функцию next().
next(our_iterator)  # => "one"

# Он сохраняет состояние при вызове next().
next(our_iterator)  # => "two"
next(our_iterator)  # => "three"

# Возвратив все данные, итератор выбрасывает исключение StopIteration
next(our_iterator)  # Выбрасывает исключение StopIteration

# Мы можем проходить по нему циклом.
our_iterator = iter(our_iterable)
for i in our_iterator:
    print(i)  # Выводит one, two, three

# Вы можете получить сразу все элементы итератора, вызвав на нём функцию list().
list(our_iterable)  # => Возвращает ["one", "two", "three"]
list(our_iterator)  # => Возвращает [] потому что состояние сохраняется


####################################################
## 4. Функции
####################################################

# Используйте def для создания новых функций
def add(x, y):
    print("x равен %s, а y равен %s" % (x, y))
    return x + y  # Возвращайте результат с помощью ключевого слова return

# Вызов функции с аргументами
add(5, 6)  # => Выводит "x равен 5, а y равен 6" и возвращает 11

# Другой способ вызова функции — вызов с именованными аргументами
add(y=6, x=5)  # Именованные аргументы можно указывать в любом порядке.

# Вы можете определить функцию, принимающую переменное число аргументов
def varargs(*args):
    return args

varargs(1, 2, 3)  # => (1,2,3)


# А также можете определить функцию, принимающую переменное число
# именованных аргументов
def keyword_args(**kwargs):
    return kwargs

# Вызовем эту функцию и посмотрим, что из этого получится
keyword_args(big="foot", loch="ness")  # => {"big": "foot", "loch": "ness"}

# Если хотите, можете использовать оба способа одновременно
def all_the_args(*args, **kwargs):
    print(args)
    print(kwargs)
"""
all_the_args(1, 2, a=3, b=4) выводит:
    (1, 2)
    {"a": 3, "b": 4}
"""

# Вызывая функции, можете сделать наоборот!
# Используйте символ * для распаковки кортежей и ** для распаковки словарей
args = (1, 2, 3, 4)
kwargs = {"a": 3, "b": 4}
all_the_args(*args)            # эквивалентно all_the_args(1, 2, 3, 4)
all_the_args(**kwargs)         # эквивалентно all_the_args(a=3, b=4)
all_the_args(*args, **kwargs)  # эквивалентно all_the_args(1, 2, 3, 4, a=3, b=4)

# Возврат нескольких значений (с назначением кортежей)
def swap(x, y):
    return y, x  # Возвращает несколько значений в виде кортежа без скобок.
                 # (Примечание: скобки исключены, но могут быть включены)

x = 1
y = 2
x, y = swap(x, y)     # => x = 2, y = 1
# (x, y) = swap(x,y)  # Снова, скобки были исключены, но могут быть включены.

# Область определения функций
x = 5

def set_x(num):
    # Локальная переменная x — это не то же самое, что глобальная переменная x
    x = num   # => 43
    print(x)  # => 43

def set_global_x(num):
    global x
    print(x)  # => 5
    x = num   # Глобальная переменная x теперь равна 6
    print(x)  # => 6

set_x(43)
set_global_x(6)

# Python имеет функции первого класса
def create_adder(x):
    def adder(y):
        return x + y
    return adder

add_10 = create_adder(10)
add_10(3)  # => 13

# Также есть и анонимные функции
(lambda x: x > 2)(3)                  # => True
(lambda x, y: x ** 2 + y ** 2)(2, 1)  # => 5

# Есть встроенные функции высшего порядка
list(map(add_10, [1, 2, 3]))          # => [11, 12, 13]
list(map(max, [1, 2, 3], [4, 2, 1]))  # => [4, 2, 3]

list(filter(lambda x: x > 5, [3, 4, 5, 6, 7]))  # => [6, 7]

# Для удобного отображения и фильтрации можно использовать списочные интерпретации
# Интерпретация списка сохраняет вывод в виде списка, который сам может быть вложенным списком
[add_10(i) for i in [1, 2, 3]]         # => [11, 12, 13]
[x for x in [3, 4, 5, 6, 7] if x > 5]  # => [6, 7]

# Вы также можете создавать интерпретации множеств и словарей.
{x for x in 'abcddeef' if x not in 'abc'}  # => {'d', 'e', 'f'}
{x: x**2 for x in range(5)}  # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}


####################################################
## 5. Модули
####################################################

# Вы можете импортировать модули
import math
print(math.sqrt(16))  # => 4.0

# Вы можете получить определенные функции из модуля
from math import ceil, floor
print(ceil(3.7))   # => 4.0
print(floor(3.7))  # => 3.0

# Вы можете импортировать все функции из модуля.
# Предупреждение: это не рекомендуется
from math import *

# Вы можете сократить имена модулей
import math as m
math.sqrt(16) == m.sqrt(16)  # => True

# Модули Python - это обычные файлы Python. Вы
# можете писать свои собственные и импортировать их. Имя
# модуля совпадает с именем файла.

# Вы можете узнать, какие функции и атрибуты
# определены в модуле.
import math
dir(math)

# Если у вас есть скрипт Python с именем math.py в той же папке,
# что и ваш текущий скрипт, файл math.py будет
# будет загружен вместо встроенного модуля Python.
# Это происходит потому, что локальная папка имеет приоритет
# над встроенными библиотеками Python.


####################################################
## 6. Классы
####################################################

# Мы используем оператор class для создания класса
class Human:

    # Атрибут класса. Он используется всеми экземплярами этого класса
    species = "Гомосапиенс"

    # Обычный конструктор, вызывается при инициализации экземпляра класса
    # Обратите внимание, что двойное подчёркивание в начале и в конце имени
    # означает объекты и атрибуты, которые используются Python, но находятся
    # в пространствах имён, управляемых пользователем.
    # Методы (или объекты или атрибуты), например:
    # __init__, __str__, __repr__ и т. д. называются специальными методами.
    # Не придумывайте им имена самостоятельно.
    def __init__(self, name):
        # Присваивание значения аргумента атрибуту
        self.name = name

        # Инициализация свойства
        self._age = 0

    # Метод экземпляра. Все методы принимают self в качестве первого аргумента
    def say(self, msg):
        return "{name}: {message}".format(name=self.name, message=msg)

    # Другой метод экземпляра
    def sing(self):
        return 'йо... йо... проверка микрофона... раз, два... раз, два...'

    # Метод класса разделяется между всеми экземплярами
    # Они вызываются с указыванием вызывающего класса в качестве первого аргумента
    @classmethod
    def get_species(cls):
        return cls.species

    # Статический метод вызывается без ссылки на класс или экземпляр
    @staticmethod
    def grunt():
        return "*grunt*"

    # property похоже на геттер.
    # Оно превращает метод age() в одноименный атрибут только для чтения.
    # Однако нет необходимости писать тривиальные геттеры и сеттеры в Python.
    @property
    def age(self):
        return self._age

    # Это позволяет установить свойство
    @age.setter
    def age(self, age):
        self._age = age

    # Это позволяет удалить свойство
    @age.deleter
    def age(self):
        del self._age


# Когда интерпретатор Python читает исходный файл, он выполняет весь его код.
# Проверка __name__ гарантирует, что этот блок кода выполняется только тогда, когда
# этот модуль - это основная программа.
if __name__ == '__main__':
    # Инициализация экземпляра класса
    i = Human(name="Иван")
    i.say("привет")                 # Выводит: "Иван: привет"
    j = Human("Пётр")
    j.say("привет")                 # Выводит: "Пётр: привет"
    # i и j являются экземплярами типа Human, или другими словами: они являются объектами Human

    # Вызов метода класса
    i.say(i.get_species())          # "Иван: Гомосапиенс"
    # Изменение разделяемого атрибута
    Human.species = "Неандертальец"
    i.say(i.get_species())          # => "Иван: Неандертальец"
    j.say(j.get_species())          # => "Пётр: Неандертальец"

    # Вызов статического метода
    print(Human.grunt())            # => "*grunt*"

    # Невозможно вызвать статический метод с экземпляром объекта
    # потому что i.grunt() автоматически поместит "self" (объект i) в качестве аргумента
    print(i.grunt())                # => TypeError: grunt() takes 0 positional arguments but 1 was given

    # Обновить свойство для этого экземпляра
    i.age = 42
    # Получить свойство
    i.say(i.age)                    # => "Иван: 42"
    j.say(j.age)                    # => "Пётр: 0"
    # Удалить свойство
    del i.age
    # i.age                         # => это выбрасило бы ошибку AttributeError


####################################################
## 6.1 Наследование
####################################################

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

# Используя класс Human, определенный выше как базовый или родительский класс, мы можем
# определить дочерний класс Superhero, который наследует переменные класса, такие как
# "species", "name" и "age", а также методы, такие как "sing" и "grunt" из класса Human,
# но также может иметь свои уникальные свойства.

# Чтобы воспользоваться преимуществами модульности по файлам, вы можете поместить
# вышеперечисленные классы в их собственные файлы, например, human.py

# Чтобы импортировать функции из других файлов, используйте следующий формат
# from "имя-файла-без-расширения" import "функция-или-класс"

from human import Human


# Укажите родительский класс(ы) как параметры определения класса
class Superhero(Human):

    # Если дочерний класс должен наследовать все определения родителя без каких-либо
    # изменений, вы можете просто использовать ключевое слово pass (и ничего больше),
    # но в этом случае оно закомментировано, чтобы разрешить уникальный дочерний класс:
    # pass

    # Дочерние классы могут переопределять атрибуты своих родителей
    species = 'Сверхчеловек'

    # Дочерние классы автоматически наследуют конструктор родительского класса, включая
    # его аргументы, но также могут определять дополнительные аргументы или определения
    # и переопределять его методы, такие как конструктор класса.
    # Этот конструктор наследует аргумент "name" от класса "Human"
    # и добавляет аргументы "superpower" и "movie":
    def __init__(self, name, movie=False,
                 superpowers=["сверхсила", "пуленепробиваемость"]):

        # добавить дополнительные атрибуты класса:
        self.fictional = True
        self.movie = movie
        # помните об изменяемых значениях по умолчанию,
        # поскольку значения по умолчанию являются общими
        self.superpowers = superpowers

        # Функция "super" позволяет вам получить доступ к методам родительского класса,
        # которые переопределяются дочерним, в данном случае, методом __init__.
        # Это вызывает конструктор родительского класса:
        super().__init__(name)

    # переопределить метод sing
    def sing(self):
        return 'Бам, бам, БАМ!'

    # добавить дополнительный метод экземпляра
    def boast(self):
        for power in self.superpowers:
            print("Я обладаю силой '{pow}'!".format(pow=power))


if __name__ == '__main__':
    sup = Superhero(name="Тик")

    # Проверка типа экземпляра
    if isinstance(sup, Human):
        print('Я человек')
    if type(sup) is Superhero:
        print('Я супергерой')

    # Получить порядок поиска разрешения метода (MRO),
    # используемый как getattr(), так и super()
    # Этот атрибут является динамическим и может быть обновлен
    print(Superhero.__mro__)    # => (<class '__main__.Superhero'>,
                                # => <class 'human.Human'>, <class 'object'>)

    # Вызывает родительский метод, но использует свой собственный атрибут класса
    print(sup.get_species())    # => Сверхчеловек

    # Вызов переопределенного метода
    print(sup.sing())           # => Бам, бам, БАМ!

    # Вызывает метод из Human
    sup.say('Ложка')            # => Тик: Ложка

    # Метод вызова, существующий только в Superhero
    sup.boast()                 # => Я обладаю силой 'сверхсила'!
                                # => Я обладаю силой 'пуленепробиваемость'!

    # Атрибут унаследованного класса
    sup.age = 31
    print(sup.age)              # => 31

    # Атрибут, который существует только в Superhero
    print('Достоин ли я Оскара? ' + str(sup.movie))


####################################################
## 6.2 Множественное наследование
####################################################

# Eще одно определение класса
# bat.py
class Bat:

    species = 'Летучая мышь'

    def __init__(self, can_fly=True):
        self.fly = can_fly

    # В этом классе также есть метод say
    def say(self, msg):
        msg = '... ... ...'
        return msg

    # И свой метод тоже
    def sonar(self):
        return '))) ... ((('

if __name__ == '__main__':
    b = Bat()
    print(b.say('привет'))
    print(b.fly)


# И еще одно определение класса, унаследованное от Superhero и Bat
# superhero.py
from superhero import Superhero
from bat import Bat

# Определите Batman как дочерний класс, унаследованный от Superhero и Bat
class Batman(Superhero, Bat):

    def __init__(self, *args, **kwargs):
        # Обычно для наследования атрибутов необходимо вызывать super:
        # super(Batman, self).__init__(*args, **kwargs)
        # Однако здесь мы имеем дело с множественным наследованием, а super()
        # работает только со следующим базовым классом в списке MRO.
        # Поэтому вместо этого мы вызываем __init__ для всех родителей.
        # Использование *args и **kwargs обеспечивает чистый способ передачи
        # аргументов, когда каждый родитель "очищает слой луковицы".
        Superhero.__init__(self, 'анонимный', movie=True,
                           superpowers=['Богатый'], *args, **kwargs)
        Bat.__init__(self, *args, can_fly=False, **kwargs)
        # переопределить значение атрибута name
        self.name = 'Грустный Бен Аффлек'

    def sing(self):
        return 'на на на на на бэтмен!'


if __name__ == '__main__':
    sup = Batman()

    # Получить порядок поиска разрешения метода (MRO),
    # используемый как getattr(), так и super()
    # Этот атрибут является динамическим и может быть обновлен
    print(Batman.__mro__)       # => (<class '__main__.Batman'>,
                                # => <class 'superhero.Superhero'>,
                                # => <class 'human.Human'>,
                                # => <class 'bat.Bat'>, <class 'object'>)

    # Вызывает родительский метод, но использует свой собственный атрибут класса
    print(sup.get_species())    # => Сверхчеловек

    # Вызов переопределенного метода
    print(sup.sing())           # => на на на на на бэтмен!

    # Вызывает метод из Human, потому что порядок наследования имеет значение
    sup.say('Я согласен')          # => Грустный Бен Аффлек: Я согласен

    # Вызов метода, существующий только во втором родителе
    print(sup.sonar())          # => ))) ... (((

    # Атрибут унаследованного класса
    sup.age = 100
    print(sup.age)              # => 100

    # Унаследованный атрибут от второго родителя,
    # значение по умолчанию которого было переопределено.
    print('Могу ли я летать? ' + str(sup.fly))  # => Могу ли я летать? False


####################################################
## 7. Дополнительно
####################################################

# Генераторы помогут выполнить ленивые вычисления
def double_numbers(iterable):
    for i in iterable:
        yield i + i

# Генераторы эффективны с точки зрения памяти, потому что они загружают только данные,
# необходимые для обработки следующего значения в итерации.
# Это позволяет им выполнять операции с недопустимо большими диапазонами значений.
# ПРИМЕЧАНИЕ: "range" заменяет "xrange" в Python 3.
for i in double_numbers(range(1, 900000000)):  # "range" - генератор.
    print(i)
    if i >= 30:
        break

# Так же, как вы можете создать интерпретации списков, вы можете создать и
# интерпретации генераторов.
values = (-x for x in [1,2,3,4,5])
for x in values:
    print(x)  # Выводит -1 -2 -3 -4 -5

# Вы также можете преобразовать интерпретацию генератора непосредственно в список.
values = (-x for x in [1,2,3,4,5])
gen_to_list = list(values)
print(gen_to_list)  # => [-1, -2, -3, -4, -5]


# Декораторы
# В этом примере "beg" оборачивает "say".
# Если say_please равно True, он изменит возвращаемое сообщение.
from functools import wraps


def beg(target_function):
    @wraps(target_function)
    def wrapper(*args, **kwargs):
        msg, say_please = target_function(*args, **kwargs)
        if say_please:
            return "{} {}".format(msg, "Пожалуйста! У меня нет денег :(")
        return msg

    return wrapper


@beg
def say(say_please=False):
    msg = "Вы не купите мне пива?"
    return msg, say_please


print(say())                 # Вы не купите мне пива?
print(say(say_please=True))  # Вы не купите мне пива? Пожалуйста! У меня нет денег :(
```

## Хотите ещё?

### Бесплатные онлайн-материалы

* [Automate the Boring Stuff with Python](https://automatetheboringstuff.com)
* [Официальная документация](http://docs.python.org/3/)
* [Hitchhiker's Guide to Python](http://docs.python-guide.org/)
* [Python Course](http://www.python-course.eu/index.php)
* [First Steps With Python](https://realpython.com/learn/python-first-steps/)
* [A curated list of awesome Python frameworks, libraries and software](https://github.com/vinta/awesome-python)
* [Official Style Guide for Python](https://peps.python.org/pep-0008/)
* [Python 3 Computer Science Circles](http://cscircles.cemc.uwaterloo.ca/)
* [Dive Into Python 3](http://www.diveintopython3.net/index.html)
* [Python Tutorial for Intermediates](https://pythonbasics.org/)
* [Build a Desktop App with Python](https://pythonpyqt.com/)