mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-23 17:41:41 +00:00
1042 lines
49 KiB
Markdown
1042 lines
49 KiB
Markdown
---
|
||
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 знака " и обычно используется
|
||
в качестве встроенной документации
|
||
"""
|
||
|
||
####################################################
|
||
## 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/)
|