Python
Описание
Для установки компилятора языка программирования скачайте инсталлятор соответствующий ващей операционной ссистеме с сайта разработчика Python.org
Так же установив Python можно использовать консольные утилиты
Установка
Windows
choco install python3
Linux: Ubuntu
sudo apt install python3
Linux: Fedora
sudo dnf install python3
Примечание
в Linux дистрибутивах установщик пакетов pip (он нам понадобится в будущем) необходимо устанавливать дополнительно.
sudo apt install python3-pip
Введение
Интерактивная среда IDLE
Для вызова интерактивной среды разработчика достаточно в консоли набрать команду:
python3
В этой интерактивной среде можно выполнять команды Python и сразу же получать результат выполнение введенной команды.
Редакторы кода и среда разработки IDE
Для написания программ на языке Python подойдет любой текстовый редактор, но для более комфортной работы рекомендуется использовать редакторы кода с подсветкой синтаксиса и отслеживанием ошибок. один из таких редакторов, это VSCODE
Так же будет полезно использовать полноценную среду разработки IDE, одной из наиболее популярных евляется PyCharm
Виртуальное окружение (venv)
Для начала работы рекомендуется подготовить виртуальное окружение, оно необходимо для того что бы вслучае использования дополнительных библиотек они не конфликтовали с другими библиотеками используемыми в других проектах, например: нет необходимости держать в одном проекте библиотеки фреймворков Django и Flask
Для того что бы создать виртуальное окружение, в папке с проектом необходимо выполнить команду:
python -m venv venv
незабудьте так же активировать ваше виртуальное окружение выполнив команду:
source venv/bin/activate
это создаст внутри проекта папку venv с компилятором и всеми необходимыми библиотеками используемые по умолчанию.
Так же для того что бы сохранить список используемых в нашем проекте библиотек, нужно создать файл reqirements.txt его можно создать автоматически выполнив команду:
pip freeze > requirements.txt
Для установки в наше виртуальное окружение необходимых библиотек нужно выполнить команду:
pip install requirements.txt
Попробуйте установить фреймворк flask используя менеджер пакетов pip и сохраните список установленных пакетов:
pip install flask
pip freeze > requirements.txt
Теперь если вы откроете файл requirements вы увидите список наших зависимостей используемые в нашем проекте
click==7.1.2
Flask==1.1.2
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
Werkzeug==1.0.1
Первая программа
Настало время написать нашу первую программу, создайте файл Hello_World.py со следующим содержимым:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Это моя первая программа
"""
Это многострочный коментарий использыется для создания докуентации к ксласам или функциям
и описывает их принцип работы.
В данном уроке мы пока не будет рассматривать примеры с документацией классов
"""
a = "World" # так помно присвоить конкретной переменной какое либо значение, в данном случее строку.
if __name__ == '__main__':
print("Hello", a) # программа напечатет в консоли Hello World
Теперь запустите нашу программу выполгив в консоле команнду:
python Hello_World.py
в консои вы должны увидеть результат нашей программы.
Примечание
Обратите внимание, что первая строка указывает какой интерпритатор мы будет использовать, она необходима если мы хотим запускать нашу команду с интерпритатором по умолчанию, например так:
./Hello_World.py
Если этой строки не будет, то мы получим ошибку.
Вторая строка отвечает за кодировку, тоесть если мы хотим вывести на экран Русские символы, то нам надо указать какую кодировку мы будем ипользовать.
Основы синтаксиса
Типы данных
Переменные в Python:
Переменная в языке программирования это название для зарезервированного места в памяти компьютера, предназначенное для хранения значений. Это означает, что когда вы создаете переменную, вы на самом деле резервируете определенное место в памяти компьютера. Основываясь на типе данных переменной, интерпретатор выделяет необходимое количество памяти и решает, что может находится в зарезервированной области памяти. Для понимания, можете думать о переменной как о коробке, в которую можно положить любую вещь, но только определенного размера. Размер в данном примере будет типом переменной. Это не совсем верное определение, но оно дает общее представление о картине в целом.
Основные форматы именования
snake_case (змеиный регистр) - С маленькой буквы. Все буквы строчные. Слова разделяются символом подчёркивания _. (Используется в переменных, функциях, модулях, файлов) PascalCase (Паскаль-регистр) - Каждое слово начинается с заглавной буквы. Подчёркивания не используются. (Используется в классах, исключениях) SCREAMING_SNAKE_CASE (кричащий змеиный регистр) - все буквы заглавные, слова разделяются подчёркиваниями. (Используется для констант, БД) _single_leading_underscore (одиночное подчёркивание в начале) - подчёркивание в начале означает, что элемент внутренний. (Используется для приватных переменных, методов внутри модулей, классов.) __double_leading_underscore (двойное подчёркивание в начале) - Python изменяет имя внутри класса (name mangling), чтобы предотвратить случайное переопределение при наследовании (Используется для защиты атрибутов и методов от переопределения)
Форматы в других языках camelCase - верблюжий регистр kebab-case - шашлычный стиль
Полный список ключевых слов Python
Все зарезервированные имена, которые нельзя использовать как переменные, функции или классы
False # Логическое значение False
True # Логическое значение True
None # Пустое значение / отсутствие значения
and # Логическое "и"
or # Логическое "или"
not # Логическое "не"
is # Проверка идентичности объектов
in # Проверка принадлежности элемента последовательности
if # Условный оператор
elif # Иначе если
else # Иначе
for # Цикл for
while # Цикл while
break # Прерывание цикла
continue # Продолжение цикла
def # Определение функции
return # Возврат значения из функции
class # Определение класса
try # Начало блока try-except
except # Обработка исключений
finally # Завершение блока try-except
raise # Генерация исключения
import # Подключение модуля
from # Импорт конкретного элемента из модуля
as # Псевдоним при импорте
with # Контекстный менеджер
lambda # Анонимная функция
pass # Пустая операция
yield # Возврат значения генератором
global # Глобальная переменная
nonlocal # Область видимости не локальная
assert # Проверка условия
del # Удаление объекта
Как проверить в Python актуальные ключевые слова
import keyword
print(keyword.kwlist)
Python чувствителен к регистру, поэтому Var, var и VAR — разные имена.
Нельзя использовать для своих переменных или функций: пробелы, дефисы -, специальные символы (@, !, %, $ и т.д.)
__init__ # Конструктор класса
__str__ # Представление объекта как строки
1variable = 5 # Нельзя начинать имя с цифры
# не рекомендуется переопределять встроенные функции и типы Python
list = [1, 2, 3] # перезапишет встроенный list
str = "Hello" # перезапишет встроенный str
id = 100 # перезапишет встроенный id()
Присвоение значения переменной:
В Python вам не нужно объявлять тип переменной вручную (как, например в С++). Объявление происходит автоматически (это называется динамическая типизация), когда вы присваиваете значение переменной. Знак равенства ( = ) используется для присвоения значения переменной. Операнд по левую сторону от знака равно ( = ) это имя переменной, операнд по правую сторону - значение присвоенное этой переменной.
# Простое присваивание
x = 10 # число
y = "hello" # строка
z = [1, 2, 3] # список
# Множественное присваивание
a, b, c = 1, 2, 3
# Распаковывается в несколько переменных.
data = [10, 20, 30, 40]
x, y, *rest = data # x - 10, y - 20, rest - 30,40 Можно использовать * в любом месте, но только один раз.
# Упаковка в кортеж
t = (x, y, *rest)
# Обмен значений
a = 1
b = 2
a, b = b, a
print(a, b) # 2 1
# Распаковка с _ для игнорируемых значений
a, _, b = [1, 2, 3]
print(a, b) # 1 3
Таблица - Обзор встроенных типов объектов
Имя |
Тип |
Описание и пример |
|---|---|---|
Целые Числа |
int |
Целые положительные или отрицательные числа -35, 0, 24, 123467890033373747428 |
Числа с плавающей точкой |
float |
Дробные числа 3.14, 2.5, -2.33333, 0.12334 |
Строки |
str |
Строки «asdf», «Hello world», «123456» |
Списки |
list |
последовательность элементов [«hello», -123, 0.34, «345»] |
Словарь |
dict |
Последовательность пар элементов содержаших ключ-значение (key-value) {«Language»: «Python», «Version»: «3.8»} |
Кортеж (Tuple) |
tup |
Неизменяемая упорядоченная последовательность элементов («hostname», 1234, -0.45, -32) |
Множество |
set |
Изменяемая неупоряоченная последовательность элементов {10, «Name», -30, 4.02, 100} |
Булевые значения |
bool |
Тип данных принимающий одно из двух значений true - истина false - ложь |
Числа, округление, системы счисления
Числа - Это не изменяемый тип данных. Числа в Python бывают трёх типов: целые, с плавающей точкой и комплексные. Примером целого числа может служить 2. Примерами чисел с плавающей точкой (или «плавающих» для краткости) могут быть 3.23 и 52.3E-4. Обозначение E показывает степени числа 10. В данном случае 52.3E-4 означает 52.3 · 10−4. Примеры комплексных чисел:(-5+4j)и(2.3-4.6j)
Примечание
Нет отдельного типа ‘long int’ (длинное целое). Целые числа по умолчанию могут быть произвольной длины.
Округление
round(2.3) # округляет число до ближайшего целого числа, и если дробная часть числа
# меньше 0.5, то число округляется вниз. Таким образом, round(2.3) будет равно 2, а не 3.
int(2.3+ 0.5) # всегда округляет число вниз, также будет равно 2
import math
num = 2.3
rounded_num = math.ceil(num)
print(rounded_num) # выводит: 3
round(number[, ndigits]) # округляет число number до ndigits знаков после запятой (по умолчанию,
# до нуля знаков, то есть, до ближайшего целого) Здесь используется так
# называемое "Банковское округление", то есть округление к ближайшему
# чётному.
Системы счисления
# двоичная система
number = 10 # Пример числа
binary_representation = bin(number)
print(binary_representation) # Выводит '0b1010'
# 0b является префиксом, обозначающим, что последующие цифры находятся в двоичной системе.
# 0o это префикс числа, означающий восьмеричную систему счисления.
# 0x этот префикс используется для шестнадцатеричных
print(binary_representation[2:]) # Выводит '1010'
# В восьмеричной
decimal_number = 64
octal_representation = oct(decimal_number) # Возвращает '0o100'
# В шестнадцатеричной
decimal_number = 255
hexadecimal_representation = hex(decimal_number) # Возвращает '0xff'
# A (или a) представляет число 10.
# B (или b) представляет число 11.
# C (или c) представляет число 12.
# D (или d) представляет число 13.
# E (или e) представляет число 14.
# F (или f) представляет число 15.
binary_number = '101' # или '0b101'
decimal_number = int(binary_number, 2) # Второй параметр это 2 - двоичная, 8 - восьмеричная, 16 - шестнадцатеричная
print(decimal_number) # Выведет 5
print(1_000_000_000) # Выведет 1000000000
Строки, форматирование
Строки - это неизменяемая упорядоченная последовательность символов, заключенная в кавычки. Строки применяются для записи текстовой информации (скажем, вашего имени) и произвольных совокупностей байтов (наподобие содержимого файла изображения). Они являются первым примером того, что в Python называется последовательностью — позиционно упорядоченной коллекцией других объектов. Для содержащихся элементов последовательности поддерживают порядок слева направо: элементы сохраняются и извлекаются по своим относительным позициям. Строго говоря, строки представляют собой последовательности односимвольных строк.
Строки можно суммировать. Тогда они объединяются в одну строку, такая операция называется «Конкатенацией строк»:
firts_string = "asdfgh"
second_string = "oiuytr"
print(firts_string + second_string)
Примечание
В Python 3 нет ASCII-строк, потому что Unicode является надмножеством (включает в себя) ASCII. Если необходимо получить строку строго в кодировке ASCII, используйте str.encode(«ascii»). По умолчанию все строки в Unicode.
Предупреждение
Нельзя производить арифметические операции над строкам и числами Например: «qwerty» + 3 Это вызовет ошибку, Но строки можно перемножать «#» * 10 выведет на экран строку ##########
Логические и физические строки
Физическая строка – это то, что вы видите, когда набираете программу. Логическая строка – Логическая строка составляется из одной или нескольких физических строк. это то, что Python видит как единое предложение.
Комментарии - начинается символом „#“, не являющимся частью строкового литерала
; - объединяет две логических строки в одну физическую
# Две логических, физических строчек
i=5
print(i)
# Две логических строки на одной физической строке
i = 5; print(i);
Рекомендовано придерживаться написания одной логической строки в каждой физической строке. Использовать разделение логической строки лишь в случае очень длинных строк.
\ - разделяет логическую стоку на две физических
# Явное объединением строк.
s = 'Это строка. \
Это строка продолжается.' #Это строка. Это строка продолжается.
print(s) #Это вторая логическая строка
month_names = ['Январь', 'февраль', # Физическая строка
'Март', 'Апрель'] # Физическая строка
# month_names = ['Январь', 'февраль', 'Март', 'Апрель'] - одна логическая строка
Управление выводом и спецсимволы
Спецсимволы (Escape-последовательности)
# \n - перенос строки (newline)
print("Привет\nМир") # Привет
# Мир
# \t - Табуляция (отступ)
print("A\tB") # A B
# \r - Возврат каретки (начало строки)
print("123\rA") # A23
# \\ - Сам символ обратного слэша
print("C:\\Python") # C:\Python
# \' - Одинарная кавычка
print('It\'s OK') # It's OK
# \" - Двойная кавычка
print("Он сказал: \"Привет!\"") # Он сказал: "Привет!"
# \b - Backspace (удаляет предыдущий символ)
print("ABC\bD") # ABD
# \u - Юникод-символ (по коду)
print('\u2764') # ❤️
Аргументы функции print()
# sep - Разделитель между элементами
print('A','B','C', sep='-') # A-B-C
# end - Что добавляется в конце строки
print('Hello', end='!') # Hello!
# file - Куда выводить текст (например, в файл)
print('Текст', file=open('out.txt','w')) # запись в файл
# flush - Немедленно записать вывод (не ждать буфера)
print('...', flush=True)
Операции над последовательностями
Проверить длину с помощью встроенной функции len() Нумерация всех символов в строке идет с нуля 0 1 2 3 4 5. Индекс simple_string [1]
simple_string = 'Spam'
len(simple_string)
# 4 (подсчитывает количество символов)
simple_string[0]
# 'S'
simple_string[1]
# 'p'
Если нужно обратиться к какому-то по счету символу, начиная с конца, то можно указывать отрицательные значения (на этот раз с единицы).
simple_string = "StringBody"
simple_string[1]
# t
simple_string[-1]
# y
Кроме обращения к конкретному символу, можно делать срезы строк, указав диапазон номеров (срез выполняется по второе число, не включая его):
example_string = "Lorem Ipsum is simply dummy text of the printing and typesetting"
example_string[0:9]
# 'Lorem Ips'
example_string[10:22]
# 'm is simply '
# Если не указывается второе число, то срез будет до конца строки:
example_string[-3:]
# 'ing'
Также в срезе можно указывать шаг:
# Так можно получить нечетные числа
a = '0123456789'
a[1::2]
# '13579'
# А таким образом можно получить все четные числа строки a:
a[::2]
# '02468'
# Срезы также можно использовать для получения строки в обратном порядке:
a[::-1]
# '9876543210'
# Переворот строки
num = input() # 12345
num_rev = num[::-1] # 54321
# Разделение строки
text = "Пример строки"
for char in text:
print(char)
# Разделение строки, с переводом в список
characters = list(text)
print(characters)
Методы для работы со строками
Методы upper, lower, swapcase, capitalize
Методы выполняют преобразование регистра строки:
string1 = 'FastEthernet'
string1.upper() #'FASTETHERNET'
string1.lower() #'fastethernet'
string1.swapcase() #'fASTeTHERNET'
string2 = 'tunnel 0'
string2.capitalize() #'Tunnel 0'
# Очень важно обращать внимание на то, что часто методы возвращают преобразованную строку
# и значит, надо не забыть присвоить ее какой-то переменной (можно той же).
string1 = string1.upper()
print(string1) #FASTETHERNET
Метод count
Метод используется подсчета, сколько раз символ или подстрока встречаются в строке:
string1 = 'Hello, hello, hello, hello'
string1.count('hello') # 3
string1.count('ello') # 4
string1.count('l') # 8
Метод find
Методу можно передать подстроку или символ, и он покажет, на какой позиции находится первый символ подстроки (для первого совпадения):
string1 = 'interface FastEthernet0/1'
string1.find('Fast') # 10
string1[string1.find('Fast')::] # 'FastEthernet0/1'
Методы startswith, endswith
Проверка, начинается или заканчивается ли строка на определенные символы:
string1 = 'FastEthernet0/1'
string1.startswith('Fast') # True
string1.startswith('fast') # False
string1.endswith('0/1') # True
string1.endswith('0/2') # False
Метод replace
Замена последовательности символов в строке на другую последовательность:
string1 = 'FastEthernet0/1'
string1.replace('Fast', 'Gigabit') # 'GigabitEthernet0/1'
Метод strip
Часто при обработке файла файл открывается построчно. Но в конце каждой строки или в начале , как правило, есть какие-то спецсимволы, например, перевод строки. По умолчанию метод strip() убирает пробельные символы. В этот набор символов входят: tnrfv
string1 = '\n\tinterface FastEthernet0/1\n'
print(string1) # (перевод строки \n)
#interface FastEthernet0/1
# (перевод строки \n)
string1.strip() #'interface FastEthernet0/1' - удаляет спецсимволы в начале и в конце строки
" hello ".strip() # 'hello'
#Методу strip можно передать как аргумент любые символы
"---hello***".strip("-*") # 'hello'
lstrip() удаление символов с лева
rstrip() удаление символов с права
Метод split
Метод разбивает строку на части, используя как разделитель какой-то символ (или символы) и возвращает список строк:
string1 = 'switchport trunk allowed vlan 10,20,30,100-200'
commands = string1.split()
print(commands) # ['switchport', 'trunk', 'allowed', 'vlan', '10,20,30,100-200']
# По умолчанию в качестве разделителя используются пробельные символы (пробелы, табы, перевод строки),
# но в скобках можно указать любой разделитель:
vlans = commands[-1].split(',')
print(vlans) #['10', '20', '30', '100-200']
Метод join
Метод позволяет объединить список, кортеж или словарь в строку разделяя ее элементы другой строкой.
myTuple = ("John", "Peter", "Vicky")
x = "-".join(myTuple)
print(x) #John-Peter-Vicky
Метод format
Метод позволяет подставлять в отмеченные в строке области символами «{}» значения из списка аргументов
например:
price = 49
txt = "The price is {} dollars"
print(txt.format(price))
Так же можно указать тип подставляемых значений:
#Строковые значения
'{} {}'.format('one', 'two') # Подставляет строки по порядку: 'one two'
#Числовые значения
'{} {}'.format(1, 2) # Подставляет числа по порядку: '1 2'
#Порядок значений можно указывать
'{1} {0}'.format('one', 'two') # Подставляет второй аргумент первым и первый вторым: 'two one'
#Можно так же подставлять значения классов
class Data(object):
def __str__(self):
return 'str' # Возвращает «читаемое» строковое представление объекта
def __repr__(self):
return 'repr' # Возвращает «официальное» представление объекта
'{0!s} {0!r}'.format(Data()) # !s вызывает __str__, !r вызывает __repr__: 'str repr'
# Отступы и выравнивания
# По правому краю, ширина 10
'{:>10}'.format('test') # ' test' (6 пробелов + 'test')
# По левому краю, ширина 10, заполняется '_'
'{:_<10}'.format('test') # 'test______'
# По центру, ширина 10
'{:^10}'.format('test') # ' test ' (по 3 пробела слева и справа)
# Срезы строк
'{:.5}'.format('xylophone') # 'xylop' (берем первые 5 символов)
# Срезы и отступы одновременно
'{:10.5}'.format('xylophone') # 'xylop ' (срез до 5 символов + выравнивание по левому краю до ширины 10)
# Числа
'{:d}'.format(42) # '42' (целое число)
'{:f}'.format(3.141592653589793) # '3.141593' (число с плавающей точкой, 6 знаков после запятой по умолчанию)
# Числа и отступы
'{:4d}'.format(42) # ' 42' (ширина 4, добавлены пробелы слева)
'{:06.2f}'.format(3.141592653589793) # '003.14' (ширина 6, 2 знака после запятой, заполняем нулями)
'{:04d}'.format(42) # '0042' (ширина 4, заполняем нулями)
# Знаковые числа
'{:+d}'.format(42) # '+42' (показываем знак числа)
'{: d}'.format(-23) # '-23' (отступ перед положительным числом не нужен, знак сохраняется для отрицательного)
'{: d}'.format(42) # ' 42' (пробел перед положительным числом)
'{:=5d}'.format(-23) # '- 23' (минус слева, числа справа, ширина 5)
'{:=+5d}'.format(23) # '+ 23' (плюс слева, числа справа, ширина 5)
# Можно вставлять значения по именам
data = {'first': 'Hodor', 'last': 'Hodor!'}
'{first} {last}'.format(**data) # 'Hodor Hodor!' (распаковка словаря по ключам)
'{first} {last}'.format(first='Hodor', last='Hodor!') # 'Hodor Hodor!' (явное именование аргументов)
# Формат даты и времени
from datetime import datetime
'{:%Y-%m-%d %H:%M}'.format(datetime(2001, 2, 3, 4, 5)) # '2001-02-03 04:05' (форматирование даты и времени)
другие примеры форматированного вывода можно найти по следующим ссылкам pyformat.info w3schools.com
Преобразования и Форматирование:
capitalize(): #Преобразует первый символ в верхний регистр.
casefold(): #Преобразует строку к нижнему регистру для нечувствительного к регистру сравнения.
lower(): #Преобразует все символы в нижний регистр.
upper(): #Преобразует все символы в верхний регистр. if i.upper() - возвращают преобразованную строку, а не булево значение.
title(): #Преобразует первый символ каждого слова в верхний регистр.
swapcase(): #Меняет регистр каждого символа на противоположный.
format(): #Форматирует строку. f'{} текс'
format_map(): #Форматирует строку, используя словарь.
Обрезка и Выравнивание:
strip(): #Удаляет пробелы в начале и в конце строки.
rstrip(): #Удаляет пробелы в конце строки.
lstrip(): #Удаляет пробелы в начале строки.
center(): #Выравнивает строку по центру.
ljust(): #Выравнивает строку по левому краю.
rjust(): #Выравнивает строку по правому краю.
zfill(): #Дополняет строку нулями слева до указанной длины.
Поиск и Замена:
count(): #Считает количество вхождений подстроки.
endswith(): #Проверяет, заканчивается ли строка указанной подстрокой.
startswith(): #Проверяет, начинается ли строка с указанной подстроки.
find(): #Находит первое вхождение подстроки. Если строка не найдена, метод вернет -1.
rfind(): #Находит последнее вхождение подстроки.
index(): #Похож на find, но вызывает ошибку, если подстрока не найдена.
rindex(): #Похож на rfind, но вызывает ошибку, если подстрока не найдена.
replace(): #Заменяет одну подстроку на другую.
Разделение и Объединение:
split(): #Разделяет строку на список строк по разделителю.
rsplit(): #Разделяет строку на список строк по разделителю справа налево.
splitlines(): #Разделяет строку на список строк по символам новой строки.
join(): #Объединяет коллекцию строк в одну строку с разделителем.
partition(): #Разбивает строку на три части по разделителю.
rpartition(): #Разбивает строку на три части по разделителю справа налево.
Проверки и Валидация:
isalnum(): #Проверяет, состоит ли строка только из буквенно-цифровых символов.
isalpha(): #Проверяет, состоит ли строка только из букв.
isdigit(): #Проверяет, состоит ли строка только из цифр.
isdecimal(): #Проверяет, состоит ли строка только из десятичных цифр.
isnumeric(): #Проверяет, состоит ли строка только из числовых символов.
isidentifier(): #Проверяет, является ли строка допустимым идентификатором.
isspace(): #Проверяет, состоит ли строка только из пробельных символов.
islower(): #Проверяет, написана ли строка в нижнем регистре.
isupper(): #Проверяет, написана ли строка в верхнем регистре.
istitle(): #Проверяет, написана ли строка в виде заголовка.
isprintable(): #Проверяет, состоит ли строка только из печатаемых символов.
isascii(): #Проверяет, состоят ли все символы строки из ASCII.
Прочие:
encode(): #Кодирует строку в указанной кодировке.
expandtabs(tabsize=8): #Заменяет символы табуляции на пробелы.
translate(): #Выполняет замену символов в строке на основе заданной таблицы замен.
Интернирование
Это процесс, при котором одна и та же строка хранится в памяти только в одном экземпляре, чтобы избежать излишнего расхода памяти, особенно когда строки повторяются или часто используются в коде.
Это сделано для того, чтобы сэкономить память и оптимизировать производительность. Если строки используются часто и они короткие, то нет смысла держать несколько одинаковых объектов в памяти.
# Если одинаковые строки имеет меньше 5 символов то они ссылаются на одну ячейку памяти
# Если больше 20 то создаются две ячейки памяти
a = 'Стр'
b = 'Стр'
print(a is b) #True
a = 'Строка которая имеет более 20 символов ASCII'
b = 'Строка которая имеет более 20 символов ASCII'
print(a is b) #False
НЕ интернирована (динамическая строка)
a = 'Стр'+'ока' # динамическая строка
print(r'C:\some\name') # C:\some\name - r убирает экранирование
print('some\name') # some
# ame
rew2 = ('два'
'666')
print(rew2) # два666 - объединяет две строчки рядом стоящие
T-строки
Списки
Списки – это изменяемые упорядоченные последовательности произвольных объектов. Списки создаются посредством заключения элементов списка в квадратные скобки. Списки могут содержать объекты любого типа, числа, строки, другие списки
names = [1,"Dave",3.14, ["Mark", 7, 9, [100,101]], 10] # разные типы данных.
Элементы списка индексируются целыми числами, первый элемент списка имеет индекс, равный нулю. Для доступа к отдельным элементам списка используется оператор индексирования
a = names[2] # Вернет третий элемент списка, "Ann"
names[0] = "Jeff" # Запишет имя "Jeff" в первый элемент списка
my_list = ['Список', 2, True] # разные типы данных.
my_list2 = [True, 2, 'Список']
print(my_list == my_list2) # Возвращает False так как очередность важна.
my = [] # Будет ровняться False
my2 = [ # при передачи данных с сервера ил на сервер
{
'us_id': 123
'us_nm': 'Red'
},
{
'us_id': 65
'us_nm': 'Green'
}
]
sp = my_list + my_list2 # Объединяет списки
Индексы и срезы: С помощью оператора среза «:» можно извлекать и изменять целые фрагменты списков:
my_list = ['Список', 2, True]
my_list[1] = 3 # Перезапись значения индекса 1
del my_list[0] # Удалит элемент списка
print(my2[0]['us_id']) # выведет значение по ключу когда в списке словарь
my_list[0] # Выведет 'Список'
my_list[-1] # Выведет True
s = [1, 2, 3, 4, 5, 6, 7, 8, 9]
r = s[:2] # 1, 2
r = s[1:-1] # 2, 3, 4, 5, 6, 7, 8, 9
r = s[-2:] # 8, 9
example_string = "Lorem Ipsum typesetting"
example_string[0:9]
# 'Lorem Ips'
example_string[-3:]
# 'ing' -1 это последний элемент
# Так можно получить нечетные числа
a = '0123456789'
a[1::2]
# '13579'
# А таким образом можно получить все четные числа строки a:
a[::2]
# '02468'
# Срезы также можно использовать для получения строки в обратном порядке:
a[::-1]
# '9876543210'
rew2 = "Привет бандит"
print(rew2[50:70])
# - вернет пустоту
rew2 = "Привет бандит"
print(rew2[3:70])
# вет бандит
[1,2,3] + [4,5] # Создаст список [1,2,3,4,5]
Методы для работы со списками
l = list() # создаст пустой список
s = list('1234567890') # [1,2,3,4,5,6,7,8,9]
s.append(10) # Добавляет элемент в конец списка
s.insert(2, 8) # Вставляет объект перед индексом. Аргумент №1 = индекс, №2 - значение
s.clear() # Очищает список
s.reverse() # Переворачивает список
s.pop(0) # Удаляет элемент, если нет аргумента pop() удалит последний элемент
s.pop(0) # Удаляет последний элемент
elem = s.pop(0) # Возвращает при удалении элемента
s.sort() # Сортирует по возрастанию
s.sort(reverse = True) # Сортирует по убыванию
s.copy() # Копирует список
s.count(5) # Выведет сколько раз встречается этот элемент в списке
s.remove("2") # Удаляет указанный элемент и не возвращает удаленный элемент
s.index() # Возвращает позицию первого вхождения элемента
s.extend('abcd') # Расширение списка [1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd']
s.extend(l) # Объединить два списка
Конвертация:
s = 'Конвертирует строку в список'
sl = list(s) # ['К', 'о', 'н', 'в', 'е', 'р', 'т', 'и', 'р', 'у', 'е', 'т', ' ', 'в', ' ',
# 'с', 'т', 'р', 'о', 'к', 'у', ' ','в' , ' ', 'с', 'п', 'и', 'с', 'о', 'к']
sl = {'a': 10, 'f': True} # Преобразование словаря в список
slk = list(sl) # ['a', 'f']
a = ['10', '20', '30']
print(','.join(a)) # 10,20,30
Арифметические операции:
s = [1, 2, 3, 4, 5, 6]
min(s) # 1
max(s) # 6
sum(s) # 21
sum(s) / len(s) # 3.5 среднее значение в списке
Копирование:
s = [1, 2, 3, 4]
r = s # не копирует а ссылается на память где стоит изначальный список. Копирование по ссылке
print(id(s) == id(r)) # True
r = s[:] # Новый список (новый объект)
r = list(s) # Новый список (новый объект)
s.copy() # Копирует список, методом создания нового списка
Распаковка:
s = [1, 2, 3, 4]
a, b, c, d = s # Распаковка по переменным
a, *d = s # a = 1 d = [2, 3, 4]
us = ['list', 23]
def us_inf(name, qty): # Передача позиционных аргументов
if not qty:
return f'{name} просто текст'
return f'{name} просто текст {qty}'
print(us_inf(*us)) # * Распаковывает в 2 разных аргумента.
# Метод split
string1 = 'switchport trunk allowed vlan 10,20,30,100-200'
commands = string1.split()
print(commands) # ['switchport', 'trunk', 'allowed', 'vlan', '10,20,30,100-200']
#По умолчанию в качестве разделителя используются пробельные символы (пробелы, табы, перевод строки),
#но в скобках можно указать любой разделитель:
vlans = commands[-1].split(',')
print(vlans) #['10', '20', '30', '100-200']
#Метод join() позволяет объеденить список, кортеж или словарь в строку разделяя ее елементы другой строкой.
myTuple = ["John", "Peter", "Vicky"]
x = "-".join(myTuple)
print(x) #John-Peter-Vicky
Словари
Словарь (dict) — это изменяемая структура данных вида ключ → значение, где: доступ идёт по ключу порядок элементов сохраняется ключи — только неизменяемые типы (строки, числа, кортежи) значения — любые типы можно добавлять, менять и удалять элементы
london = {
'id': 1, # id -ключ, 1 - значение
'name':'London',
'it_vlan':320,
'user_vlan':1010,
'mngmt_vlan':99,
'to_name': None,
'to_id': None,
'port':'G1/0/11'
}
Для того, чтобы получить значение из словаря, надо обратиться по ключу:
london = {'name': 'London1', 'location': 'London Str'}
print(london['name'], london['location']) #'London1' 'London Str'
Словари записываются в фигурных скобках и содержат пары ключ: значение. Они удобны, когда нужно связать набор данных с именованными ключами, например, описать свойства объекта.
color = 'color' # строка неизменяемые данные
D = {'food': 'Spam', 'quantity': 4, color: 'pink'} # переменая может быть ключем если в ней неизменяемые данные
Мы можем индексировать этот словарь по ключу, чтобы извлекать и изменять зна чения, связанные с ключами. Операция индексации словаря имеет такой же синтаксис, как для последовательностей, но элементом вквадратных скобках будет ключ, а не относительная позиция:
D['food'] # Извлечь значение, связанное с ключом 'food' 'Spam'
D['quantity'] += 1 # Добавить 1 к значению, связанному с ключом 'quantity'
print(D)
#{'color': 'pink', 'food': 'Spam', 'quantity': 5}
Хотя словари часто создают сразу в фигурных скобках, на практике их нередко заполняют постепенно во время работы программы. Можно начать с пустого словаря и добавлять элементы по ключу — если ключа ещё нет, он создаётся автоматически.
D = {}
D['name'] = 'Bob'
D['job'] = 'dev'
D['age'] =40
print (D)
#{'*:age 40, 'job': 'dev', 'name': 'Bob'}
print(D['name']) #Bob
В словаре в качестве значения можно использовать словарь:
london_co = {
'r1': {
'hostname': 'london_r1',
'location': '21 New Globe Walk',
'vendor': 'Cisco',
'model': '4451',
'ios': '15.4',
'ip': '10.255.0.1'
},
'r2': {
'hostname': 'london_r2',
'location': '21 New Globe Walk',
'vendor': 'Cisco',
'model': '4451',
'ios': '15.4',
'ip': '10.255.0.2'
},
'sw1': {
'hostname': 'london_sw1',
'location': '21 New Globe Walk',
'vendor': 'Cisco',
'model': '3850',
'ios': '3.6.XE',
'ip': '10.255.0.101'
}
}
# Доступ к данным вложенного словаря
london_co['r1']['ios'] #'15.4'
london_co['r1']['model'] #'4451'
london_co['sw1']['ip'] #'10.255.0.101'
# Сравнение словарей
my_dict = {'1': 'get', 'res': 'get', 'wed': 'gas',}
my_dict2 = {'res': 'get', '1': 'get', 'wed': 'gas',}
print(my_dict == my_dict2) # True
print(id(my_dict) == id(my_dict2)) # False разные объекты
# Изменение словаря
my_dict2['res'] = 7000 # Изменение значения
my_dict2['is_new'] = True # Добавления ключа и значения, если такой ключ есть то перепишет значение
del my_dict2['is_new'] # удаление ключа
# Безопасное получение значения
print(my_dict2['eslinetklucha']) # Если нет ключа выдаст ошибку KeyError
print(my_dict2.get('eslinetklucha')) # Если нет ключа вернет None ошибки не будет
print(my_dict2.get('eslinetklucha', 'Нет ключа')) # Если нет ключа вернет второй аргумент 'Нет ключа'
# Просмотр содержимого
print(my_dict2.items()) # Вызывает экземпляр класса виде кортеджей в списке
print(my_dict2.keys()) # Вызывает ключи не в списке, конвертация list()
print(my_dict2.popitem()) # Удаление последний добавленный ключ элемента
# Удаление элементов
dmy_dict2.popitem() # удалить последний добавленный ключ
del my_dict2['res'] # удалить по ключу
# Копирование словаря
print(my_dict2.copy()) # Копия, если не надо изменять оригинал
# Преобразование в словарь
my_list =[['first', 0], ['two', 2]]
my_dict = dict(my_list) # Конвертация из списка в словарь
# Распаковка
my_dict = {'1': 'get', 'res': 'get',}
red = { # Важна последовательность распаковки и ключа. так как может перезаписать ключ как в первом так и во втором значении
**my_dict # Распаковывает словарь my_dict (два ключа и 2 значения)
'wed': 'gas', # Если есть такой ключ то значение перезапишут
}
# Объединение словарей
my = {**my_dict, **red}
my = my_dict | red # Объединение словарей. Важна последовательность если одинаковые ключи
Методы для работы со словарями
clear()
позволяет очистить словарь:
copy()
создает полную копию словаря
london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
london2 = london.copy()
id(london) #25524512
id(london2) #25563296
london['vendor'] = 'Juniper'
london2['vendor'] #'Cisco'
Примечание
Если указать, что один словарь равен другому, то london2 будет ссылкой на словарь. И при изменениях словаря london меняется и словарь london2, так как это ссылки на один и тот же объект.
get()
запрашивает ключ, и если его нет, вместо ошибки возвращает None.
london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
print(london.get('ios')) #None
#Метод get() позволяет также указывать другое значение вместо None
print(london.get('ios', 'Ooops')) #Ooops
setdefault()
ищет ключ, и если его нет, вместо ошибки создает ключ со значением None, если ключ есть, setdefault возвращает значение, которое ему соответствует:
london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
ios = london.setdefault('ios')
print(ios) #None
london #{'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco', 'ios': None}
london.setdefault('name') #'London1'
#Второй аргумент позволяет указать, какое значение должно соответствовать ключу
model = london.setdefault('model', 'Cisco3580')
print(model) #Cisco3580
london
{'name': 'London1',
'location': 'London Str',
'vendor': 'Cisco',
'ios': None,
'model': 'Cisco3580'}
# Метод setdefault заменяет такую конструкцию:
if key in london:
value = london[key]
else:
london[key] = 'somevalue'
value = london[key]
keys(), values(), items()
Все три метода возвращают специальные объекты view, которые отображают ключи, значения и пары ключ-значение словаря соответственно.
Очень важная особенность view заключается в том, что они меняются вместе с изменением словаря. И фактически они лишь дают способ посмотреть на соответствующие объекты, но не создают их копию.
london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
keys = london.keys()
print(keys)
#dict_keys(['name', 'location', 'vendor'])
#Сейчас переменной keys соответствует view dict_keys, в котором три ключа: name, location и vendor.
#Но, если мы добавим в словарь еще одну пару ключ-значение, объект keys тоже поменяется:
london['ip'] = '10.1.1.1'
keys
#dict_keys(['name', 'location', 'vendor', 'ip'])
#Если нужно получить обычный список ключей, который не будет меняться с изменениями словаря, достаточно конвертировать view в список:
list_keys = list(london.keys())
list_keys
#['name', 'location', 'vendor', 'ip']
del()
Удаляет ключ и значение
london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
del london['name']
london
#{'location': 'London Str', 'vendor': 'Cisco'}
update()
Позволяет добавлять в словарь содержимое другого словаря:
r1 = {'name': 'London1', 'location': 'London Str'}
r1.update({'vendor': 'Cisco', 'ios':'15.2'})
r1
# {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco', 'ios': '15.2'}
#Аналогичным образом можно обновить значения:
r1.update({'name': 'london-r1', 'ios':'15.4'})
r1
'''
{'name': 'london-r1',
'location': 'London Str',
'vendor': 'Cisco',
'ios': '15.4'}
'''
Кортежи
Объект кортежа нельзя изменять — кортежи являются последовательностями. Функционально они используются для представления фиксированных коллекций элементов: скажем, компонентов специфической даты в календаре. Синтаксически записываются в круглых, а не квадратных скобках и поддерживают произвольные типы, произвольное вложение и обычные операции над последовательностями:
T = (1, 2, 3, 4) # Кортеж из 4 элементов
len(Т) # Длина 4
Т + (5, б) # Конкатенация (1, 2, 3, 4, 5, 6)
Т[О] # Индексация, нарезание и т.д.
tuple2 = ('password',) # в одноэлементные кортежи необходимо добавлять запятую
Примечание
Главное отличие кортежей заключается в том, что после создания их нельзя из менять, т.е. они являются неизменяемыми последовательностями.
На практике кортежи применяются в целом не так часто, как списки, но весь смысл в их неизменяемости. Если вы передаете коллекцию объектов внутри своей программы в виде списка, тогда он может быть модифицирован где угодно; если вы используете кортеж, то изменить его не удастся. То есть кортежи обеспечивают своего рода ограничение целостности, что удобно в программах, крупнее тех, которые мы будем писать здесь.
my_tuple = (1, 2, 3, )
my_tuple2 = (3, 2, 1, )
print(my_tuple == my_tuple2) # False разная последовательность значения
print(my_tuple[0]) # Взятие элемента по индексу (неудобно и легко ошибиться.)
Методы
my_tuple = (1, [2, 1], 3, 1)
print(my_tuple.count(1)) # 1 Количество элементов в кортеже, непоказывает во вложеных
print(my_tuple.index(1) # Возвращает индекс найденного первого элемента
print(my_tuple.index(1, 3+1) # второй аргумент, с какого индекса искать
tuple(list(my_tuple)) # Ковертируем кортеж в список, меняем значение, и конвертируем в картеж
my_dict = {'1': 'get', 'res': 'get', 'wed': 'gas',}
print(tuple(my_dict)) # ('1', 'res', 'wed') конверирование списка в кортеж, выдаст кортеж из ключей
my_type = (1, 2, 3)
my_type2 = ('a', 'b', 'c')
print(my_type + my_type2) # Объединяет кортежи
Именованные кортежи
Именованные кортежи (namedtuple) — это особый вид кортежей в Python, который позволяет обращаться к элементам по имени, а не только по индексу.
# Модуль collections входит в стандартную библиотеку Python
from collections import namedtuple # Импортируем функцию namedtuple из модуля collections
Person = namedtuple("Person", ["name", "age", "job"]) # Создаём новый тип данных 'Person' с именованными полями: name, age, job
# Это позволяет хранить связанные данные в объекте с доступом по имени, а не по индексу
person = Person("Mike", 25, "Programmer") # Создаём экземпляр типа Person с конкретными значениями полей
# В нашем случае: name="Mike", age=25, job="Programmer"
print(person.age) # 25
print(person.name) # Mike
# --- Получаем список полей ---
print(person._fields) # ('name', 'age', 'job')
# --- Преобразование в словарь ---
person_dict = person._asdict()
print(person_dict) # {'name': 'Mike', 'age': 25, 'job': 'Programmer'}
# --- Создание нового экземпляра с изменённым полем ---
# namedtuple неизменяем, поэтому для "изменения" создаём новый экземпляр
new_person = person._replace(age=30)
print(new_person) # Person(name='Mike', age=30, job='Programmer')
# --- Разложение на переменные (распаковка) ---
name, age, job = person
print(name, age, job) # Mike 25 Programmer
# --- Получаем значения как обычный кортеж ---
tuple_person = tuple(person)
print(tuple_person) # ('Mike', 25, 'Programmer')
# --- Проверка неизменяемости ---
try:
person.age = 26 # Ошибка! namedtuple неизменяемый
except AttributeError as e:
print(e) # "can't set attribute"
# Сортируем по возрасту
people_sorted = sorted(people, key=lambda p: p.age)
for p in people_sorted:
print(p.name, p.age)
Именованные кортежи подходят, когда нужно: хранить простые структуры данных иметь ясные имена полей но при этом не создавать полноценные классы и сохранить скорость и малую память, как у кортежей
Например: координаты, параметры, настройки, результаты вычислений и т.д.
Множество
Множество(набор) - это изменяемый неупорядоченный тип данных. В множестве всегда содержатся только уникальные элементы. Множество в Python - это последовательность элементов, которые разделены между собой запятой и заключены в фигурные скобки. С помощью множества можно легко убрать повторяющиеся элементы:
my_set = set() # Создание пустого набора
cities = ['Санкт-Петербург', 'Хабаровск', 'Казань', 'Санкт-Петербург', 'Казань']
un_cities = set(cities)
for city in un_cities:
print("Один мой друг живёт в городе " + city)
# Один мой друг живёт в городе Хабаровск
# Один мой друг живёт в городе Санкт-Петербург
# Один мой друг живёт в городе Казань
Множества полезны тем, что с ними можно делать различные операции и находить объединение множеств, пересечение и так далее. Объединение множеств можно получить с помощью метода union() или оператора «|»:
my_set2 = {[1], [2], 3} #TypeError в наборе не могут находится изменяемые элементы
# Объединение уникальные элементы
vlans1 = {10,20,30,50,100}
vlans2 = {100,101,102,102,200}
vlans1.union(vlans2) #{10, 20, 30, 50, 100, 101, 102, 200}
vlans1 | vlans2 #{10, 20, 30, 50, 100, 101, 102, 200}
#Пересечение множеств можно получить с помощью метода intersection() или оператора &
vlans1 = {10,20,30,50,100}
vlans2 = {100,101,102,102,200}
vlans1.intersection(vlans2) #{100} # Выводит повторяющие элементы
vlans1 & vlans2 #{100} # Выводит повторяющие элементы
Методы
.difference() # разница между множествами
.discard() # Удаляет множества
.copy() # Удаляет множества
.symmetric_difference() # Выдаст элементы отсутствующих в другом множестве и пересечении
Предупреждение
Нельзя создать пустое множество с помощью {} (так как в таком случае это будет не множество, а словарь):
set1 = {} # создается пустой словарь type(set1) # dict
set2 = set() # создается пустое множество type(set2) # set
Методы для работы с множествами
add()
добавляет элемент во множество:
set1 = {10,20,30,40}
set1.add(50)
set1 #{10, 20, 30, 40, 50}
discard()
позволяет удалять элементы, не выдавая ошибку, если элемента в множестве нет
set1 #{10, 20, 30, 40, 50}
set1.discard(55)
set1 #{10, 20, 30, 40, 50}
set1.discard(50)
set1 #{10, 20, 30, 40}
clear()
очищает множество
set1 = {10,20,30,40}
set1.clear()
set1 #set()
Булевы значения
Булевы значения это две константы True - истина и False - лож.
Истинное значение:
1 # True - Короткая запись истины 1
print(bool(10)) # True - любое ненулевое число
print(bool('abc')) # True - любая непустая строка
print(bool([1, 2])) # True - любой непустой объект
print([] == [])
# Выражение
print(100>10) # True первое число больше второго
print('long string'>'Long') # True первая сторока больше второй
Ложное значение:
1 # False - Короткая запись лож 0
print(bool(None)) # False None - без значения
print(bool("")) # False Пустая строка, список, кортедж и т.д.
Остальные истинные и ложные значения, как правило, логически следуют из условия.
Для проверки булевого значения объекта, можно воспользоваться bool:
items = [1, 2, 3]
empty_list = []
bool(empty_list) #False
bool(items) #True
bool(0) #False
bool(1) #True
Лексикографическое сравнение строк в Python
Строки сравниваются посимвольно, по Unicode-кодам. Если первые символы одинаковы, Python сравнивает следующие, пока не найдёт различие
print('long string' > 'Long') # True
print('long string' > 'Short') #True Первый символ 'l' (код 108) и 'S' (код 83). Поскольку 108 > 83,
# Python сразу решает, что строка 'long string' больше, чем 'Short', и не продолжает сравнение дальше.
print('long' > 'long') # False
print('a' > 'at') # False Сначала сравнивается первый символ обеих строк — 'a' и 'a' Строка 'a' не имеет второго символа, а строка 'at' имеет 't' на второй позиции.
# поскольку строка 'a' короче, чем 'at', Python считает её меньшей, и результат сравнения будет False
print('long string' > 'Short string') # True Строки сравниваются на основе их символов, используя их числовые коды (Unicode).
# 'l' (номер в Unicode 108) и 'S' (номер 83). 108 > 83
print('long' == 'long') # True
print('long string' == 'Long string') # False учитывает регистр
print('Long string' == 'Short string') # False учитывает значение
print('Long string' == 'Long string') # False учитывает пробел
Анатация типов
Аннотации типов просто считываются интерпретатором Python и никак более не обрабатываются, но доступны для использования из стороннего кода и в первую очередь рассчитаны для использования статическими анализаторами.
Аннотации типов поддерживаются многими IDE для Python, которые выделяют некорректный код или выдают подсказки в процессе набора текста.
cnt: int # Указыет, переменая должна быть int
cnt: str # Трезаписывает, тип анатации переменой на str
cnt: int = 0 # при наведении курсора на переменую, IDE(VS-Code) показывает тип переменой
def mul2(x: int, y: int = 2 ) -> float: # x: int, y: int = 2 - по умолчанию -> float - вывод типа
ter: str = 'a'
return x * y
res = mul2(1)
print(res)
print(mul2.__annotations__) # {'x': <class 'int'>} - проверка типа анатации
from typung import Unio, Optional, Any, Final
sev: Union[int, float] = 1
# Unio - это int или float
sev: int | float = 1 # Тоже самое с Python 3.10
Digit = Union[int, float] # Псевдоним типа (type alias), поэтому имя пишется с большой буквы по принятому соглашению
sev: Digit = 1
Str = Optional[str] # Тоже самое что и StrTyp = Union[str, None]
sev: Any = 1 # Any - любой тип данных
MAX_VALUE: Final = 1000 # Final - Присвоение константы
from typung import List, Tuple, Dict, Set, Callable
lst: list = [1, 2, '3', True] # Анатация списка
lst: list[int] = [1, 2, '3', True] # Анатация списка с типом в списке, модуль mypy отлавливает ошибку
addr: tuple[int, str] = (1, 'ds', 3) # Указывается тип у каждого элемента
elems: tuple[float, ...] = [1.2, 2.3] # Все элементы должны быть float
# словари, str -ключи, int - значения
words: dict[str, int] = {'one': 1}
# колекция
pers: set[str] = {'dds', 'dfs'}
# Callable описывает контракт функции: какие аргументы она принимает и что возвращает.
# Callable[[int, int], int] — функция, которая принимает два int и возвращает int
def apply_op(a: int, b: int, op: Callable[[int, int], int]) -> int:
# [int, int] - список аргументов функции
# , int - тип возвращаемого значения функции
return op(a, b)
# Обычная функция, подходящая под Callable[[int, int], int]
def add(x: int, y: int) -> int:
return x + y
# Передаём функцию как аргумент
result: int = apply_op(2, 3, add)
print(result) # 5
Преобразование типов
В Python есть несколько полезных встроенных функций, которые позволяют преобразовать данные из одного типа в другой.
Конвертация строки в двоичную, десятичную, шестнадцатеричную систему.
# Преобразует строку как двоичное число в десятичное:
int("11111111", 2) # 255 С помощью функции int можно преобразовать и число в двоичной записи в десятичную (двоичная запись должна быть в виде строки)
# Преобразовать десятичное число в двоичный формат можно с помощью:
bin(10) #'0b1010'
# Преобразовать десятичное число в шестнадцатеричный формат:
hex(10) #'0xa'
Преобразование типов
# Преобразует в список:
list("string") #['s', 't', 'r', 'i', 'n', 'g']
list({1,2,3}) #[1, 2, 3]
list((1,2,3,4)) #[1, 2, 3, 4
# Преобразует в множество:
set([1,2,3,3,4,4,4,4]) #{1, 2, 3, 4}
set((1,2,3,3,4,4,4,4)) #{1, 2, 3, 4}
set("string string") #{' ', 'g', 'i', 'n', 'r', 's', 't'}
# Преобразует в кортеж:
tuple([1,2,3,4]) #(1, 2, 3, 4)
tuple({1,2,3,4}) #(1, 2, 3, 4)
tuple("string") #('s', 't', 'r', 'i', 'n', 'g')
# Преобразует число в строку:
str(10) #'10'
# Преобразует строку в цифру:
int("10") #10
# Преобразует в число с плавающей точкой:
a = float("3.14") # строка '3.14' преобразуется в число 3.14
b = float(10) # целое число 10 преобразуется в 10.0
Проверка типов
# Проверяет, сосоит ли строка из одних только цифр
"a".isdigit() #False
"a10".isdigit() #False
"10".isdigit() #True
# Проверяет, состоит ли строка из одних букв:
"a".isalpha() #True
"a100".isalpha() #False
"a-- ".isalpha() #False
"a ".isalpha() #False
# Позволяет проверить, состоит ли строка из букв или цифр:
"a".isalnum() #True
"a10".isalnum() #True
type()
Иногда, в зависимости от результата, библиотека или функция может выводить разные типы объектов. Например, если объект один, возвращается строка, если несколько, то возвращается кортеж.
Нам же надо построить ход программы по-разному, в зависимости от того, была ли возвращена строка или кортеж.
type("string") #str
type("string") is str #True
#Аналогично с кортежем (и другими типами данных):
type((1,2,3)) #tuple
type((1,2,3)) is tuple #True
type((1,2,3)) is list #False
Файлы
Файлы — это основной способ хранения данных на компьютере. В Python объекты файлов предоставляют интерфейс для чтения и записи данных: текстов, документов, аудио, JSON, CSV и т. д. Работа с файлами включает открытие, чтение/запись и закрытие файлов, а также управление путями и обработку ошибок.
Используйте конструкцию with open(…) as f: для автоматического закрытия файлов. Закрывайте файлы после ручного открытия с open(). Используйте абсолютные пути, если файл всегда в одном месте, и относительные, если код должен работать независимо от структуры каталогов. Для больших файлов лучше читать построчно (for line in file) или с использованием readline(), чтобы не загружать весь файл в память. Для создания и удаления папок применяйте Path.mkdir() и Path.rmdir() (или shutil.rmtree() для непустых).
Создание и открытие файлов
Для создания объекта файла используется встроенная функция open():
f = open('data.txt', 'w') # Создать новый файл в режиме записи ('w')
f.write('Hello\n') # Записать строку в файл
f.write('world\n') # Еще одна строка
f.close() # Закрыть файл и сбросить буфер на диск
Основные режимы: „w“ — режим записи (write). Создает файл, если его нет, или очищает существующий. „r“ — режим чтения (read), используется по умолчанию. „a“ — режим дозаписи (append), добавляет данные в конец файла. Дополнительные режимы: „x“ — создает новый файл и открывает его для записи. Если файл существует, будет ошибка. Бинарные и текстовые режимы: „b“ — бинарный режим (для чтения/записи байтов). „t“ — текстовый режим (по умолчанию). Комбинации: „r+“ – открыть для чтения и записи (ошибка, если файл не существует). „w+“ – открыть для чтения и записи, но предварительно очищает файл или создает новый. „a+“ – открыть для чтения и дозаписи (добавляет данные в конец файла, если файл есть; если нет — создается новый). „x+“ – создать новый файл и открыть для чтения и записи (ошибка, если файл уже есть).
Чтение файлов
Полное чтение
f = open('data.txt', 'r') # Открытие файла для чтения
text = f.read() # Прочитать все содержимое в строку
f.close()
print(text)
Чтение построчно
with open('data.txt', 'r') as f: # Автоматическое открытие и закрытие файла
for line in f:
print(line, end='') # end='' убирает двойной перенос
Чтение с помощью readlines() и readline()
with open('data.txt', 'r') as f:
lines = f.readlines() # Список строк файла
print(lines)
line = f.readline() # Считывает одну строку
Чтение полностью до пустой строки.
with open('test/test.txt') as f:
while True:
line = f.readline()
print(line)
if not line:
break
Запись в файлы
with open('data.txt', 'w', encoding='utf-8') as f: # 'w' перезаписывает файл
f.write("Первая строка\n") # 'a' добавляет строки в конец файла.
f.write("Вторая строка\n") # encoding='utf-8' обеспечивает корректное сохранение текста на русском и других языках.
Обработка текста перед записью/анализом
with open('data.txt', encoding='utf-8') as f:
text = f.read()
text = text.replace("\n", " ") # заменяем переносы на пробелы
text = text.replace(",", "").replace(".", "") # убираем пунктуацию
text = text.lower() # переводим в нижний регистр
words = text.split() # создаем список слов
words.sort() # сортируем слова
Работа с путями к файлам
Функциональный подход (модуль os.path)
from os import path
print(path.abspath('.')) # Абсолютный путь к текущей папке
print(path.exists('data.txt')) # Проверка существования файла
print(path.('C:/local/bin').exists()) # Проверка наличия папки
# Абсолютный путь жестко привязан к конкретной системе: C:/Users/Vasya/Documents/file.txt.
# Относительный путь указывает путь относительно текущей рабочей папки: data/file.txt.
# В относительных путях используется специальный элемент (работае так же и в Path ):
# . — текущая папка
# .. — на одну папку вверх
# ../.. — на две папки вверх
# ../../.. — на три папки вверх
Объектно-ориентированный подход (модуль pathlib)
from pathlib import Path
file_path = Path('test.txt') # Файл в текущей папке
print(file_path.exists()) # Проверка существования
print(file_path.is_file()) # Проверка, является ли файлом
print(file_path.is_dir()) # Проверка, является ли папкой
print(file_path.absolute()) # Абсолютный путь
# Примеры операций с Path:
cwd = Path('.') # текущая папка
for f in cwd.iterdir(): # список файлов и папок
print(f)
new_folder = Path('example')
if not new_folder.exists():
new_folder.mkdir() # создание папки
new_folder.rmdir() # удаление папки (если пустая)
# Для удаления папки с содержимым используйте shutil.rmtree().
# Объектно-ориентированный подход удобен для построения и объединения путей:
# Path('C:/') / 'local' / 'bin' # 'C:/local/bin'
# Создание папки
cwd = Path('C:/Users') / 'ERRoR79' / 'Desktop' / 'krutaten' # Путь к папке
if not cwd.exists(): # проверка если папка отсутствует
cwd.mkdir() # создание папки
if cwd.exists(): # если папка есть
cwd.rmdir() # удаление папки
# import shutil
# shutil.rmtree(cwl) # Удаление папки если в ней есть файлы
cwd = Path('failes')
cmd.mkdir(exist_ok=True) # если такая папка есть то ошибки не будет
Path — не файл и не папка, а объект, который описывает путь.
1. Методы работы с путями Позволяют создавать и преобразовывать пути: absolute() — абсолютный путь resolve() — абсолютный путь с разрешением .. и симлинков joinpath() — соединение путей / — оператор, альтернатива joinpath parent, parents — родительские директории parts — путь как кортеж частей
2. Проверки типа объекта Определяют, что это за путь: exists() — существует ли путь is_file() — это файл is_dir() — это папка is_absolute() — абсолютный путь is_symlink() — символическая ссылка
3. Навигация и поиск Работа с содержимым каталогов: iterdir() — перебор файлов и папок glob() — поиск по шаблону rglob() — рекурсивный поиск
4. Работа с файлами Чтение и запись без open(): read_text() / write_text() read_bytes() / write_bytes() open() — открыть файл
Управление файлами и папками
Операции с файловой системой: mkdir() — создать папку rmdir() — удалить пустую папку unlink() — удалить файл rename() / replace() — переименование touch() — создать пустой файл
6. Информация о пути Свойства и метаданные: name — имя файла stem — имя без расширения suffix / suffixes — расширение(я) root, drive, anchor — части пути stat() — информация из ОС
Удаление файлов
from pathlib import Path
file = Path('test_file.txt') # Создаёт объект Path, представляющий путь
# к файлу 'test_file.txt' в текущей рабочей директории
# (файл может как существовать, так и отсутствовать)
if file.exists(): # проверка наличие файла
file.unlink() # удаление файла
JSON и другие форматы
import json
from pathlib import Path
DATA_FILE = 'data.json'
# Загрузка данных
def load(): # Функция загрузки данных из файла DATA_FILE
if not Path(DATA_FILE).exists(): # Проверяем, существует ли файл по указанному пути
return {} # Если файла нет, возвращаем пустой словарь, чтобы избежать ошибки открытия
with open(DATA_FILE, 'r', encoding='utf-8') as f: # Открываем файл в режиме чтения с кодировкой UTF-8
return json.load(f) # Читаем содержимое файла и преобразуем JSON в объект Python (обычно dict)
# Сохранение данных в файл DATA_FILE
def save(data): # Функция принимает объект Python (обычно словарь или список) для сохранения
with open(DATA_FILE, 'w', encoding='utf-8') as f: # Открываем файл в режиме записи; если файл существует — он будет перезаписан
json.dump( # Сериализуем объект Python в формат JSON
data, # Данные, которые нужно сохранить
f, # Файловый объект, в который производится запись
ensure_ascii=False, # Разрешает сохранение русских и других не-ASCII символов
indent=2 # Делает JSON человекочитаемым за счёт отступов
)
Операторы языка Python
Большинство предложений (логических строк) в программах содержат выражения. Простой пример выражения: 2 + 3. Выражение можно разделить на операторы и операнды.
Операторы – это некий функционал, производящий какие-либо действия, который может быть представлен в виде символов, как например +, или специальных зарезервированных слов. Операторы могут производить некоторые действия над данными, и эти данные называются операндами. В нашем случае 2 и 3 – это операнды.
Базовые операторы
Оператор |
Название |
Объяснение |
Примеры |
„+“ |
Сложение |
Суммирует два объекта |
3 + 5 даст 8; „a“ + „b“ даст „ab“ |
„-“ |
Вычитание |
Даёт разность двух чисел; если первый операнд отсутствует, он считается равным нулю |
-5.2 даст отрицательное число, а 50 - 24 даст 26. |
„*“ |
Умножение |
Даёт произведение двух чисел или возвращает строку, повторённую заданное число раз. |
2 * 3 даст 6. „la“ * 3 даст „lalala“. |
„**“ |
Возведение в степень |
Возвращает число х, возведённое в степень y |
3** 4 даст 81 (т.е. 3 * 3 * 3 * 3) |
/ |
Деление |
Возвращает частное от деления x на y |
4 / 3 даст 1.3333333333333333. |
// |
Целочисленное деление |
Возвращает неполное частное от деления |
4 // 3 даст 1. -4 // 3 даст -2. |
% |
Деление по модулю |
Возвращает остаток от деления |
8 % 3 даст 2. -25.5 % 2.25 даст 1.5. |
<< |
Сдвиг влево |
Сдвигает биты числа влево на заданное количество позиций. (Любое число в памяти компьютера представлено в виде битов - или двоичных чисел, т.е. 0 и 1) |
2 << 2 даст 8. В двоичном виде 2 представляет собой 10. Сдвиг влево на 2 бита даёт 1000, что в десятичном виде означает 8. |
>> |
Сдвиг вправо |
Сдвигает биты числа вправо на заданное число позиций. |
11 >> 1 даст 5. В двоичном виде 11 представляется как 1011, что будучи смещённым на 1 бит вправо, даёт 101, а это, в свою очередь, не что иное как десятичное 5 |
& |
Побитовое И |
Побитовая операция И над числами |
5 & 3 даёт 1. |
„|“ |
Побитовое ИЛИ |
Побитовая операция ИЛИ над числами |
5 | 3 даёт 7 |
^ |
Побитовое ИСКЛЮЧИТЕЛЬНО ИЛИ |
Побитовая операция ИСКЛЮЧИТЕЛЬНО ИЛИ |
5 ^ 3 даёт 6 |
~ |
Побитовое НЕ |
|
~5 даёт -6. |
< |
Меньше |
Определяет, верно ли, что x меньше y. Все операторы сравнения возвращают True или False [1]. Обратите внимание на заглавные буквы в этих словах. |
5 < 3 даст False, а 3 < 5 даст True. Можно составлять произвольные цепочки сравнений: 3 < 5 < 7 даёт True. |
> |
Больше |
Определяет, верно ли, что x больше y |
5 > 3 даёт True. Если оба операнда - числа, то перед сравнением они оба преобразуются к одинаковому типу. В противном случае всегда возвращается False. |
<= |
Меньше или равно |
Определяет, верно ли, что x меньше или равно y |
x = 3; y = 6; x <= y даёт True. |
>= |
Больше или равно |
Определяет, верно ли, что x больше или равно y |
x = 4; y = 3; x >= 3 даёт True. |
== |
Равно |
Проверяет, одинаковы ли объекты |
x = 2; y = 2; x == y даёт True. x = „str“; y = „stR“; x == y даёт False. x = „str“; y = „str“; x == y даёт True. |
!= |
Не равно |
Проверяет, верно ли, что объекты не равны |
x = 2; y = 3; x != y даёт True. |
not |
Логическое НЕ |
Если x равно True, оператор вернёт False. Если же x равно False, получим True. |
x = True; not x даёт False. |
and |
Логическое И |
x and y даёт False, если x равно False , в противном случае возвращает значение y |
x = False; y = True; x and y возвращает False, поскольку x равно False. В этом случае Python не станет проверять значение y, так как уже знает, что левая часть выражения „and“ равняется False, что подразумевает, что и всё выражение в целом будет равно False, независимо от значений всех остальных операндов. Это называется укороченной оценкой булевых (логических) выражений. |
or |
Логическое ИЛИ |
Если x равно True, в результате получим True, в противном случае получим значение y |
x = True; y = False; x or y даёт True. Здесь также может производиться укороченная оценка выражений. |
:= |
Присваивает значение |
Присваивает значение переменной в выражении (оператор присвоения внутри выражения). |
if (n := len(mylist)) > 5: |
is |
Сравнение идентичности (один объект в памяти) |
a is b |
|
is not |
Не идентичны |
a is not b |
|
in |
Проверка, содержится ли элемент |
x in list |
|
not in |
Проверка отсутствия элемента |
x not in list |
Управляющие операторы
Условные операторы (if/else)
Оператор if используется для проверки условий: если условие верно, выполняется блок выражений (называемый “if-блок”), иначе выполняется другой блок выражений (называемый “else-блок”). Блок “else” является необязательным.
Предупреждение
В языке Python блоки разедяются табами(4 пробела) или пробелами
Запомните эмпирическое правило: хотя вы можете использовать для отступов пробелы или табуляции (4 пробела), их смешивание внутри блока обычно не будет удачной идеей применяйте либо то, либо другое. Формально табуляция считается достаточным количеством пробелов, чтобы сместить текущую строку на расстояние, кратное 8, и код будет работать в случае согласованного смешивания табуляций и пробелов. Тем не менее, такой код может быть сложнее изменять. Хуже того, смешивание табуляций и пробелов затрудняет чтение кода целиком, не говоря уже о правилах синтаксиса Python — табуляции в редакторе сменившего вас программиста могут выглядеть сов сем не так, как в вашем редакторе.
Пример использования оператора if
number = 23
guess = int(input('Введите целое число : '))
if guess == number:
print('Поздравляю, вы угадали,') # Здесь начинается новый блок
print('(хотя и не выиграли никакого приза!)') # Здесь заканчивается новый блок
elif guess < number:
print('Нет, загаданное число немного больше этого.') # Ещё один блок
# Внутри блока вы можете выполнять всё, что угодно ...
else:
print('Нет, загаданное число немного меньше этого.')
# чтобы попасть сюда, guess должно быть больше, чем number
print('Завершено')
# Это последнее выражение выполняется всегда после выполнения оператора if
# Выполняет все сравнения
if guess == number
print(1)
if guess < number
print(2)
if guess > number
print(3)
Выражения:
# Проверка наличия значения или ключа
if not per.get('name'): # True, если ключ 'name' отсутствует или значение пустое
if name: # True, если переменная непустая (не None, не '', не 0 и т.д.)
# Сравнения
if name > 1: # True, если значение больше 1
if name and name > 1: # True, если оба условия истинны (логическое И)
# Проверка типа
if isinstance(a, (int, float)): # True, если a принадлежит хотя бы одному типу из кортежа
if type(my) is int: # True, если тип переменной точно int
# Специальные случаи
if 0: # False
if 1: # True
# Проверка исключений типов
if isinstance(i, tip) and not (tip == int and isinstance(i, bool)):
# True, если i принадлежит типу tip, кроме случая, когда tip=int, а i bool
# Логические операторы
a and b (если одно из выражений ложное)
a or b (если оба выражения ложных)
Тернарный оператор (условное выражение)
Используется для выбора значения или функции на месте. Подходит, когда есть одно условие, и нужно сразу что-то выполнить или вернуть.
n = 5
print('ff') if type(n) is int else print('dd')
# Проверяет тип переменной n
# Если n — int, выведет 'ff', иначе 'dd'
result = "Число положительное" if n > 0 else "Число неположительное"
print(result)
# Позволяет записать условие и действия в одну строку вместо полноценного if-else блока.
# Часто используют для краткой и наглядной логики присваивания или вывода.
img = 4
def fr():
print('good')
def tg():
print('not')
ret = fr() if True else tg() # Если условие True → вызывается fr(), иначе tg()
Сопоставление с образцом (match-case)
Когда применять: Много if-elif-else Работа со структурированными данными (списки, словари, объекты) Чтобы сделать код чище и читаемее
Примеры использования: CLI, меню, команды бота, Парсинг JSON/API, Обработка HTTP-статусов
fruit = "Банан"
match fruit: # проверяемая переменная
case "apple": # если "apple"
print("Яблоко")
case "banana": # если "banana"
print("Банан")
case _: # любой другой вариант
print("Неизвестный фрукт")
case "apple" | "banana": # несколько вариантов
pass
case ["user", name]: # проверка структуры списка/кортежа
pass
case x if x < 10: # условие внутри case
pass
case User(name="Alice"): # сопоставление с классом
pass
Оператор while
Оператор while — самая универсальная конструкция для итераций в языке Python. Выражаясь простыми терминами, он многократно выполняет блок операторов (обыч но с отступом) до тех пор, пока проверка в заголовочной части оценивается как истин ное значение. Это называется “циклом”, потому что управление продолжает возвра щаться к началу оператора, пока проверка не даст ложное значение. Когда результат проверки становится ложным, управление переходит на оператор, следующий после блока while. Совокупный эффект в том, что тело цикла выполняется многократно, пока проверка в заголовочной части дает истинное значение. Если проверка оцени вается в ложное значение с самого начала, тогда тело цикла никогда не выполнится и оператор while пропускается.
В своей самой сложной форме оператор while состоит из строки заголовка с вы ражением проверки, тела с одним или большим количеством оператором с отступами и необязательной части else, которая выполняется, если управление покидает цикл, а оператор break не встретился. Python продолжает оценивать выражение проверки в строке заголовка и выполняет операторы, вложенные в тело цикла, пока проверка не возвратит ложное значение:
number = 23
running = True
while running:
guess = int(input('Введите целое число : '))
if guess == number:
print('Поздравляю, вы угадали.')
running = False # это останавливает цикл while
elif guess < number:
print('Нет, загаданное число немного больше этого.')
else:
print('Нет, загаданное число немного меньше этого.')
else:
print('Цикл while закончен.')
# Здесь можете выполнить всё что вам ещё нужно
print('Завершение.')
Цикл for
Циклы перебирают последовательности: diсt, set, list, str, range, tuple Оператор осуществляет итерацию по последовательности объектов, последовательность – это упорядоченный набор элементов.
for х in ["spam", "eggs", "ham"]:
print(x, end=' ') # spam
# eggs
# ham
# end=' ' меняет поведение print: по умолчанию print() ставит перенос строки \n,
# но тут вместо него ставится пробел. Поэтому все значения выводятся в одну строку через пробел:
for i in range(1, 5):
print(i)
else:
print('Цикл for закончен')
Вложенные циклы for
Давайте теперь взглянем на цикл for, который сложнее тех, что мы видели до сих пор. В приведенном ниже примере иллюстрируется вложение операторов и конструк ция else цикла for. Имея список объектов (items) и список ключей (tests), код ищет каждый ключ в списке объектов и сообщает о результате поиска:
items = ["ааа", 111, (4, 5), 2.01]
tests = [(4, 5) , 3.14]
for key in tests:
for item in items:
if item - key:
print (key, "was found")
break
else:
print(key, "not found!")
Оператор break
Оператор break служит для прерывания[7] цикла, т.е. остановки выполнения команд даже если условие выполнения цикла ещё не приняло значения False или последовательность элементов не закончилась.
Важно отметить, что если циклы for или while прервать оператором break, соответствующие им блоки else выполняться не будут.
# Бесконечный цикл
while True: # Неизменяемое условие
print('1')
while True:
s = input('Введите что-нибудь : ')
if s == 'выход':
break # Выход из цикла
print('Длина строки:', len(s))
print('Завершение')
Оператор continue
Оператор continue используется для указания Python, что необходимо пропустить все оставшиеся команды в текущем блоке цикла и продолжить[9] со следующей итерации цикла.
# Прерывание с помощью ввода
while True:
s = input('Введите что-нибудь : ')
if s == 'выход':
break # Выход из цикла
if len(s) < 3:
print('Слишком мало')
continue # Пропуск операции
print('Введённая строка достаточной длины')
# Разные другие действия здесь...
Ну и в качестве маленького примера давайте нарисуем в консоли Ёлочку :)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''программа рисует в консоли елочку'''
''' *
***
*****
*******
*********
***********
'''
#Пример - 1
for i in range(1, 20, 2): #функция range() указывает начальное значение, конечное значение и шаг.
print('{:^20}'.format('*' * i)) # Печатаем символ выравнивая его по центру
#Пример -2
SPACE = ' '
STRAR = '*'
rows = int(input('Укажите размер ёлочки: '))
spaces = rows-1
stars = 1
for i in range(rows):
print(
(SPACE*spaces) +
(STRAR*stars) +
(SPACE*spaces)
)
stars += 2
spaces -= 1
Цикл по словарю (через items())
l = {'1': 'зн1', '2': 'зн2', '3': 'зн3'}
for item in l.items(): # items() - возвращает последовательность кортеж ключ, пара
key, value = item # распаковывает кортеж в две переменные:
print(key, value)
# Сразу распаковка в цикле
for key, value in l.items(): # items() - возвращает последовательность кортежа ключ, пара
print(key, value)
Генераторы
Преимущество генераторов, в малом объеме памяти у объекта
# Список — генератор списка
absol = [3, 4, 7, -2, 6, -1] # список чисел.
absol_1 = [abs(num) for num in absol if num % 2 == 0] # for num in absol — перебрать каждый элемент
# if num % 2 == 0 — оставить только чётные числа
# abs(num) — взять модуль числа (убрать минус)
print(absol_1)
# Генератор множества (set comprehension)
myset = [3, 4, 7, -2, 6, -1]
new_myset = {val * val for val in myset} # Перебираем каждый элемент val, Возводим его в квадрат val * val, Результаты собираются в {...} — это множество
print(new_myset)
# не хранит дубликаты, не гарантирует порядок
# Генератор словаря (dict comprehension)
my_dict = {'1': 10, 'res': 7, 'wed': 14}
new_tunec = {key: value * 10 for key, value in my_dict.items()} # my_dict.items() даёт пары (ключ, значение)
print(new_tunec)
#
print(new_myset) # <generator object <genexpr> at 0x000001BDA7046180>
print(type(new_myset)) # <class 'generator'>
Функции языка Python
Функции – это многократно используемые фрагменты программы. Они позволяют дать имя определённому блоку команд с тем, чтобы впоследствии запускать этот блок по указанному имени в любом месте программы и сколь угодно много раз. Это называется вызовом функции.
Принципы написания функций
Одна функция — одна задача: Функция должна делать только одно логически завершённое действие. Если внутри появляются слова «и», «или», «а ещё» — скорее всего, функцию стоит разбить.
Название функции начинается с глагола Имя должно описывать действие.
Название отражает суть задачи По имени должно быть понятно: что делает функция без просмотра её реализации
Функции не должны изменять внешние объекты (без необходимости) Желательно, чтобы функция: не меняла глобальные переменные не изменяла переданные объекты напрямую возвращала результат, а не имела побочные эффекты
def sayHello(): # def - определение функции, sayHello - имя функции
print('Привет, Мир!') # блок, принадлежащий функции
# Конец функции
sayHello() # вызов функции
sayHello() # ещё один вызов функции
Параметры функций
Функции могут принимать параметры(значения), передаваемые функции для того, чтобы она что-либо сделала с ними. Эти параметры похожи на переменные, за исключением того, что значение этих переменных указывается при вызове функции, и во время работы функции им уже присвоены их значения.
Параметры указываются в скобках при объявлении функции и разделяются запятыми. Аналогично мы передаём значения, когда вызываем функцию. Обратите внимание на терминологию: имена, указанные в объявлении функции, называются параметрами, тогда как значения, которые вы передаёте в функцию при её вызове, – аргументами.
def printMax(a, b): # a, b - параметры функции
if a > b:
print(a, 'максимально')
elif a == b:
print(a, 'равно', b)
else:
print(b, 'максимально')
# прямая передача значений
printMax(3, 4) # 3, 4 - аргументы функции
# передача переменных в качестве аргументов
x = 5
y = 7
printMax(x, y)
Локальные переменные
При объявлении переменных внутри определения функции, они никоим образом не связаны с другими переменными с таким же именем за пределами функции – т.е. имена переменных являются локальными в функции. Это называется областью видимости переменной. Область видимости всех переменных ограничена блоком, в котором они объявлены, начиная с точки объявления имени.
x= 50
def func(x):
print('x равен', x)
x = 2
print('Замена локального x на', x)
func(x)
print('x по-прежнему', x)
Зарезервированное слово “global”
Чтобы присвоить некоторое значение переменной, определённой на высшем уровне программы (т.е. не в какой-либо области видимости, как то функции или классы), необходимо указать Python, что её имя не локально, а глобально (global). Сделаем это при помощи зарезервированного слова global. Без применения зарезервированного слова global невозможно присвоить значение переменной, определённой за пределами функции.
Можно использовать уже существующие значения переменных, определённых за пределами функции (при условии, что внутри функции не было объявлено переменной с таким же именем). Однако, это не приветствуется, и его следует избегать, поскольку человеку, читающему текст программы, будет непонятно, где находится объявление переменной. Использование зарезервированного слова global достаточно ясно показывает, что переменная объявлена в самом внешнем блоке.
x = 50
def func():
global x
print('x равно', x)
x = 2
print('Заменяем глобальное значение x на', x)
func()
print('Значение x составляет', x)
Зарезервированное слово “nonlocal”
Мы увидели, как получать доступ к переменным в локальной и глобальной области видимости. Есть ещё один тип области видимости, называемый “нелокальной” (nonlocal) областью видимости, который представляет собой нечто среднее между первыми двумя. Нелокальные области видимости встречаются, когда вы определяете функции внутри функций.
Поскольку в Python всё является выполнимым кодом, вы можете определять функции где угодно.
def func_outer():
x = 2
print('x равно', x)
def func_inner():
nonlocal x
x = 5
func_inner()
print('Локальное x сменилось на', x)
func_outer()
Значения аргументов по умолчанию
Зачастую часть параметров функций могут быть необязательными, и для них будут использоваться некоторые заданные значения по умолчанию, если пользователь не укажет собственных. Этого можно достичь с помощью значений аргументов по умолчанию. Их можно указать, добавив к имени параметра в определении функции оператор присваивания (=) с последующим значением.
Обратите внимание, что значение по умолчанию должно быть константой. Или точнее говоря, оно должно быть неизменным[1] – это объясняется подробнее в последующих главах. А пока запомните это.
def say(message, times = 1):
print(message * times)
say('Привет')
say('Мир', 5)
Предупреждение
Важно Значениями по умолчанию могут быть снабжены только параметры, находящиеся в конце списка параметров. Таким образом, в списке параметров функции параметр со значением по умолчанию не может предшествовать параметру без значения по умолчанию. Это связано с тем, что значения присваиваются параметрам в соответствии с их положением. Например, def func(a, b=5) допустимо, а def func(a=5, b) – не допустимо.
Ключевые аргументы
Если имеется некоторая функция с большим числом параметров, и при её вызове требуется указать только некоторые из них, значения этих параметров могут задаваться по их имени – это называется ключевые параметры. В этом случае для передачи аргументов функции используется имя (ключ) вместо позиции (как было до сих пор).
Есть два преимущества такого подхода: во-первых, использование функции становится легче, поскольку нет необходимости отслеживать порядок аргументов; во-вторых, можно задавать значения только некоторым избранным аргументам, при условии, что остальные параметры имеют значения аргумента по умолчанию.
def func(a, b=5, c=10):
print('a равно', a, ', b равно', b, ', а c равно', c)
func(3, 7)
func(25, c=24)
func(c=50, a=100)
Переменное число параметров
Иногда бывает нужно определить функцию, способную принимать любое число параметров. Этого можно достичь при помощи звёздочек (сохраните как function_varargs.py):
def total(a=5, *numbers, **phonebook):
print('a', a)
#проход по всем элементам кортежа
for single_item in numbers:
print('single_item', single_item)
#проход по всем элементам словаря
for first_part, second_part in phonebook.items():
print(first_part,second_part)
print(total(10,1,2,3,Jack=1123,John=2231,Inge=1560))
Только ключевые параметры
Если некоторые ключевые параметры должны быть доступны только по ключу, а не как позиционные аргументы, их можно объявить после параметра со звёздочкой (сохраните как keyword_only.py):
def total(initial=5, *numbers, extra_number):
count = initial
for number in numbers:
count += number
count += extra_number
print(count)
total(10, 1, 2, 3, extra_number=50)
total(10, 1, 2, 3)
# Вызовет ошибку, поскольку мы не указали значение
# аргумента по умолчанию для 'extra_number'.
Оператор “return”
Оператор return используется для возврата из функции, т.е. для прекращения её работы и выхода из неё. При этом можно также вернуть некоторое значение из функции.
# Просто выводит на экран
def print(str):
print("Выведит текст в консоль")
# return возвращает значение для дальнейшего использования
def add(a, b):
return a + b # Возвращает результат выражения
result = add(3, 5)
print(result) # 8 тут может быть любой код.
# return - возвращает значение в зависимости от условия
def maximum(x, y):
if x > y:
return x
elif x == y:
return 'Числа равны.'
else:
return y
print(maximum(2, 3))
return - заавершает действие фунции
Стандартные Функции:
1. Функции ввода / вывода print() — вывод данных
Используется для: вывода информации пользователю отладки
print("Hello, world")
print(10, 20, 30)
input() — ввод строки от пользователя
Используется для: получения данных с клавиатуры интерактивных программ
name = input("Введите имя: ")
print(name)
Работа с типами и преобразования
Используется, когда: ввод получен строкой дробная часть не нужна работа с индексами, счётчиками
int() - Преобразование строки или числа в целое число.
Используется, когда: ввод получен строкой дробная часть не нужна работа с индексами, счётчиками
x = int("123") # строка → int
y = int(3.9) # float → int (отбрасывает дробную часть)
float() - Преобразование в вещественное число (с плавающей точкой).
Используется, когда: нужны дробные значения расчёты, измерения, проценты
x = float("3.14") # строка → float
y = float(10) # int → float
complex() - Работа с комплексными числами (математика, физика, сигналы).
Используется, когда: математика физика обработка сигналов
z = complex(2, 3) # 2 + 3j
# z.real → 2.0
# z.imag → 3.0
str() - Преобразование данных в строку (вывод, логирование, JSON).
Используется, когда: нужно вывести данные логирование сериализация (JSON, файлы)
s = str(100) # int → str
t = str(3.14) # float → str
bool() - Логические проверки (if, while).
Используется, когда: условия в if / while проверки наличия данных
bool(0) # False
bool(1) # True
bool("") # False
bool("text") # True
bytes() - Работа с сырыми бинарными данными (файлы, сеть, шифрование).
Используется, когда: работа с файлами сеть шифрование данные «как есть», без изменения
b = bytes("hi", "utf-8") # строка → bytes
# b'hi'
bytearray() - Изменяемые бинарные данные (буферы, протоколы).
Используется, когда: нужно менять байты буферы сетевые протоколы
ba = bytearray(b"abc") # bytes → bytearray
ba[0] = 100 # изменяем байт
# bytearray(b'dbc')
memoryview() - Работа с большими данными без копирования (производительность).
Используется, когда: большие данные важна производительность нельзя копировать массивы
data = bytearray(b"abcd")
mv = memoryview(data) # представление в памяти
mv[1] = 120 # меняет исходные данные
# bytearray(b'axcd')
Коллекции и структуры данных
list() — список
Используется, когда: порядок важен элементы нужно менять допускаются дубликаты
lst = list([1, 2, 3]) # создание списка
lst.append(4) # добавление элемента
lst[0] = 10 # изменение элемента
print(lst) # [10, 2, 3, 4]
tuple() — кортеж
Используется, когда: данные не должны изменяться нужен фиксированный набор значений можно использовать как ключ словаря
tpl = tuple([1, 2, 3]) # создание кортежа
print(tpl[0]) # доступ по индексу
# tpl[0] = 10 ошибка (неизменяем)
set() — множество
Используется, когда: важна уникальность не важен порядок нужны операции: объединение, пересечение
s = set([1, 2, 2, 3]) # дубликаты удаляются
s.add(4) # добавление элемента
print(s) # {1, 2, 3, 4}
frozenset() — неизменяемое множество
Используется, когда: нужно множество как ключ словаря требуется гарантия неизменности
fs = frozenset([1, 2, 3])
# fs.add(4) ошибка
print(fs)
dict() — словарь
Используется, когда: нужен быстрый доступ по ключу данные имеют структуру «имя → значение»
d = dict(one=1, two=2) # создание словаря
d["three"] = 3 # добавление пары
print(d["one"]) # 1
range() — диапазон чисел
Используется, когда: нужен диапазон чисел важна производительность и память часто применяется в циклах
r = range(1, 5) # 1, 2, 3, 4
print(list(r)) # [1, 2, 3, 4]
r2 = range(0, 10, 2) # шаг 2
print(list(r2)) # [0, 2, 4, 6, 8]
Математика и числа
abs() — модуль числа, Возвращает абсолютное значение (без знака).
Используется, когда: нужна величина без знака расчёт расстояний сравнение отклонений
abs(-10) # 10
abs(3.5) # 3.5
round() — Округляет число до заданного количества знаков.
Используется, когда: вывод чисел пользователю финансовые расчёты форматирование результатов
round(3.14159, 2) # 3.14
round(2.5) # 2 (банковское округление)
pow() — возведение в степень
Используется, когда: математические вычисления алгоритмы нужна поддержка 3 аргументов (модуль)
pow(2, 3) # 8
pow(2, 3, 5) # 3 → (2³) % 5
divmod() — частное и остаток
Используется, когда: нужно одновременно получить деление и остаток работа с разрядами, временем, координатами
divmod(17, 5) # (3, 2)
sum() — сумма
Используется, когда: подсчёт итогов агрегация данных работа с числами
sum([1, 2, 3, 4]) # 10
sum([1, 2, 3], 10) # 16 (начальное значение)
min(), max() — минимум и максимум
Используются, когда: поиск предельных значений ограничения анализ данных
min(3, 1, 5) # 1
max([3, 1, 5]) # 5
min("apple", "banana") # 'apple' (лексикографически)
Проверки и сравнения
len() — длина
Используется, когда: нужно узнать размер коллекции проверка на пустоту контроль границ
len("hello") # 5
len([1, 2, 3]) # 3
len({1, 2, 3}) # 3
type() — тип объекта
Используется, когда: отладка изучение объектов интроспекция
type(10) # <class 'int'>
type("abc") # <class 'str'>
isinstance() — проверка типа
Используется, когда: безопасная проверка типов поддержка наследования
isinstance(10, int) # True
isinstance("hi", (str, bytes)) # True
issubclass() — проверка наследования
Используется, когда: работа с иерархией классов проверка интерфейсов
class A: pass
class B(A): pass
issubclass(B, A) # True
issubclass(A, B) # False
id() — идентификатор объекта
Используется, когда: отладка понимание ссылок проверка, один ли это объект
a = [1, 2]
b = a
id(a) == id(b) # True
hash() — хеш-значение
Используется, когда: объект используется как ключ словаря работа с set сравнение неизменяемых объектов
hash("hello")
hash(10)
# hash([1, 2, 3]) ошибка (изменяемый тип)
Логика и булевы операции
all() — Возвращает True, если все элементы в итерируемом объекте истинны
Используется, когда: нужно проверить выполнение всех условий валидация данных
all([True, True, True]) # True
all([True, False, True]) # False
all([1, 2, 3]) # True
all([1, 0, 3]) # False
all([]) # True (пустой набор)
any() — хотя бы один истинный
Используется, когда: достаточно выполнения одного условия поиск совпадений проверки флагов
any([False, False, True]) # True
any([False, False, False]) # False
any([0, "", None, 5]) # True
any([]) # False (пустой набор)
Работа с последовательностями
sorted() — сортировка
Используется, когда: нужен отсортированный результат исходные данные нельзя менять требуется сортировка по ключу
sorted([3, 1, 2]) # [1, 2, 3]
sorted("cba") # ['a', 'b', 'c']
sorted([("a", 3), ("b", 1)], key=lambda x: x[1])
# [('b', 1), ('a', 3)]
reversed() — обратный порядок
Используется, когда: нужно пройти коллекцию с конца не хочется создавать копию списка
list(reversed([1, 2, 3])) # [3, 2, 1]
list(reversed("abc")) # ['c', 'b', 'a']
enumerate() — индекс + значение
Используется, когда: нужен индекс в цикле нумерация элементов
for i, val in enumerate(["a", "b", "c"]):
print(i, val)
# 0 a
# 1 b
# 2 c
zip() — объединение последовательностей
Используется, когда: нужно обрабатывать данные параллельно склеивание структур данных
a = [1, 2, 3]
b = ["a", "b", "c"]
list(zip(a, b))
# [(1, 'a'), (2, 'b'), (3, 'c')]
map() — применение функции
Используется, когда: нужно преобразовать данные функциональный стиль
nums = [1, 2, 3]
list(map(lambda x: x * 2, nums))
# [2, 4, 6]
filter() — фильтрация
Используется, когда: нужно отфильтровать данные убрать лишние элементы
nums = [1, 2, 3]
list(map(lambda x: x * 2, nums))
# [2, 4, 6]
Функциональное программирование
lambda — анонимная функция (ключевое слово)
Используется, когда: нужно передать функцию как аргумент не хочется создавать отдельную функцию с def удобно в map, filter, sorted, key
f = lambda x: x * 2 # создаём функцию x → x*2
print(f(5)) # 10
# Прямое использование в map
nums = [1, 2, 3]
list(map(lambda x: x**2, nums)) # [1, 4, 9]
# В sorted с ключом
words = ["apple", "banana", "kiwi"]
sorted(words, key=lambda x: len(x)) # ['kiwi', 'apple', 'banana']
callable() — это встроенная функция, которая проверяет, можно ли объект вызвать как функцию
Вызываемые объекты: функции методы классы (потому что вызывается конструктор) объекты с методом __call__()
def f():
pass
class A:
def __call__(self):
print("called")
print(callable(f)) # True
print(callable(A)) # True
print(callable(A())) # True
print(callable(123)) # False
functools.reduce() — последовательно сворачивает коллекцию в одно значение
from functools import reduce # 1 + 2 = 3
nums = [1, 2, 3, 4] # 3 + 3 = 6
result = reduce(lambda a, b: a + b, nums) # 6 + 4 = 10
print(result) # 10
Атрибуты и рефлексия
getattr() - получить атрибут объекта Возвращает значение атрибута по имени.
Используется, когда: нужно получить атрибут динамически имя атрибута хранится в строке
class A:
x = 10
a = A()
getattr(a, "x") # 10
getattr(a, "y", 0) # 0 (значение по умолчанию)
setattr() - установить атрибут объекта Присваивает значение атрибуту по имени.
Используется, когда: нужно динамически изменить объект создание атрибутов на лет
class A:
pass
a = A()
setattr(a, "x", 5)
print(a.x) # 5
delattr() — удалить атрибут объекта Удаляет атрибут по имени.
Используется, когда: нужно удалить свойство объекта динамическая очистка
class A:
x = 10
a = A()
delattr(a, "x")
# print(a.x) ошибка, атрибут удалён
hasattr() — проверка существования атрибута Возвращает True, если объект имеет атрибут с указанным именем.
Используется, когда: безопасная работа с динамическими атрибутами проверка перед доступом или удалением
class A:
x = 10
a = A()
hasattr(a, "x") # True
hasattr(a, "y") # False
vars() - словарь атрибутов объекта Возвращает __dict__ объекта (имена → значения).
Используется, когда: нужно получить все атрибуты объекта интроспекция, сериализация
class A:
x = 10
y = 20
a = A()
vars(a) # {'x': 10, 'y': 20}
dir() - Возвращает список всех доступных атрибутов и методов объекта.
Используется, когда: изучение объекта отладка и интроспекция
class A:
x = 10
a = A()
dir(a) # ['__class__', '__delattr__', ..., 'x']
Работа с кодом и выполнением
eval() — вычисляет выражение, возвращает результат.
Используется, когда: нужно динамически вычислить строковое выражение как Python‑код полезно для калькуляторов, парсеров простых выражений
Важно: небезопасно использовать с ненадёжными данными (можно выполнить произвольный код).
expr = "2 + 3 * 4"
result = eval(expr) # 14
print(result)
exec() — выполняет код из строки или объекта кода.
Используется, когда: нужно выполнить несколько строк кода динамически например, скрипт формируется на лету
Отличие от eval(): exec() не возвращает результат, выполняет код целиком подходит для нескольких выражений и блоков кода
code = """ a = 10
b = 5
c = a + b """"
exec(code)
print(c) # 15
compile() — компилирует строку кода в объект кода для последующего выполнения
Используется, когда: нужно подготовить код для eval() или exec() заранее можно оптимизировать многократное выполнение одного и того же кода
code_str = "x + y"
code_obj = compile(code_str, "<string>", "eval")
x, y = 2, 3
result = eval(code_obj) # 5
print(result)
# Аргументы:
# source — строка кода
# filename — имя файла или источник (для сообщений об ошибках)
# mode — "eval" (выражение), "exec" (блок кода), "single" (одна команда)
Использовать осторожно.
Контекст и область видимости
globals() — возвращает словарь глобальных имён текущего модуля.
Используется, когда: нужно получить доступ к глобальным переменным по имени применяется в отладке, метапрограммировании, динамическом доступе к объектам
x = 10
def show_globals():
print(globals()['x']) # доступ к глобальной переменной по имени
show_globals() # 10
globals()['y'] = 20
print(y) # 20
locals() — возвращает словарь локальных имён текущей области видимости.
Используется, когда: нужно посмотреть локальные переменные функции удобно для отладки и логирования
def test():
a = 5
b = 7
print(locals()) # {'a': 5, 'b': 7}
test()
Работа с файлами и системными объектами
open() — — открывает файл для чтения или записи.
Используется, когда: нужно работать с файлами на диске (текстовыми или бинарными) читать данные, записывать результаты, создавать новые файлы
open(file, mode='r', encoding=None)
Ошибки и отладка
help() — выводит справку о объекте (функции, классе, модуле).
Используется, когда: нужно быстро узнать, как работает функция или метод изучаете новый модуль или библиотеку
help(print) # справка о встроенной функции print
help(str) # справка о типе str
help("modules") # список доступных модулей
breakpoint() — точка останова для отладки.
Используется, когда: нужно остановить выполнение программы и войти в интерактивный режим отладки удобно для анализа состояния переменных в конкретной точке
x = 10
y = 5
breakpoint() # здесь выполнение остановится, откроется pdb
z = x + y
print(z)
Специальные / служебные
repr() — возвращает строковое представление объекта для разработчика.
x = "Привет"
print(repr(x)) # "'Привет'" — с кавычками, пригодно для eval()
ascii() — возвращает строку с экранированием не-ASCII символов.
s = "Привет"
print(ascii(s)) # '\u041f\u0440\u0438\u0432\u0435\u0442'
format() — форматирование строк.
name = "Михаил"
age = 42
print("Имя: {}, возраст: {}".format(name, age))
# Имя: Михаил, возраст: 42
slice() объект среза, используется для индексирования последовательностей.
lst = [0,1,2,3,4,5]
s = slice(1,5,2) # start=1, stop=5, step=2
print(lst[s]) # [1,3]
object() — базовый объект Python, родитель всех классов.
obj = object()
print(type(obj)) # <class 'object'>
classmethod() — метод класса, получает класс как первый аргумент.
class MyClass:
@classmethod
def hello(cls):
print("Hello from", cls.__name__)
MyClass.hello() # Hello from MyClass
staticmethod() — статический метод, не принимает ни self, ни cls.
class MyClass:
@staticmethod
def greet():
print("Привет!")
MyClass.greet() # Привет!
property() — создаёт управляемый атрибут (getter/setter).
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
p = Person("Михаил")
print(p.name) # Михаил
super() — доступ к родительскому классу.
class A:
def hello(self):
print("Hello from A")
class B(A):
def hello(self):
super().hello()
print("Hello from B")
b = B() # Hello from A
b.hello() # Hello from B
Проверка итераций
iter() — возвращает итератор из итерируемого объекта.
Используется, когда: нужно пройтись по объекту шаг за шагом вручную работать с объектами, которые поддерживают итерацию (списки, строки, словари)
lst = [1, 2, 3]
it = iter(lst) # создаём итератор
print(it) # <list_iterator object at 0x...>
next() — возвращает следующий элемент итератора.
Используется, когда: нужно получать элементы итератора по одному можно задать значение по умолчанию, если элементы закончились
lst = [1, 2, 3]
it = iter(lst)
print(next(it)) # 1
print(next(it)) # 2
print(next(it)) # 3
# print(next(it)) # StopIteration
print(next(it, "Конец")) # Конец — вместо ошибки
Строки документации
Python имеет строки документации, обычно обозначаемую сокращённо docstrings. Важный инструмент, помогает лучше документировать программу и облегчает её понимание. Строку документации можно получить, из функции, даже во время выполнения программы!
def print_max(x, y):
# Args: Выводит текст в подсказках при наведение на функцию
"""
Выводит наибольшее из двух чисел.
Args:
x (int): первое число
y (int): второе число
Returns:
None
"""
x = int(x) # конвертируем в целые, если возможно
y = int(y)
if x > y:
print(x, 'наибольшее')
else:
print(y, 'наибольшее')
print_max(3, 5)
print(print_max.__doc__)
Изменяемые объекты в функции
При передаче изменяемых объектов в функцию, в случаи изменения объекта в функции объект в не функции тоже изменится.
def add_item(items): # параметр — список (изменяемый объект)
items.append("яблоко") # изменяем объект внутри функции
basket = ["хлеб", "молоко"] # исходный список
add_item(basket) # передаём список в функцию
print(basket) # объект изменился и вне функции
# Как избежать изменения внешнего объекта
def add_item_copy(items):
new_items = items.copy() # создаём копию
new_items.append("яблоко")
return new_items
basket = ["хлеб", "молоко"]
new_basket = add_item_copy(basket)
print(basket) # исходный список не изменился
print(new_basket) # изменённая копия
Рекурсивная функция
Рекурсивная функция — это функция, которая вызывает саму себя. Она должна иметь условие выхода, иначе вызовы будут бесконечными, и программа завершится с ошибкой.
def calc_f(num):
if type(num) is not int:
raise TypeError('integer')
if num <= 0:
raise ValueError('positive')
if num == 1:
return 1
return calc_f(num -1) * num # В рекурсивных вызовах сначала идёт углубление (убывание), а потом разворачивание (увеличение).
calc_f('10') # Факториал 10! == 10*9*8*7*6*5*4*3*2*1
Присвоение переменой функции
В Python функции можно присваивать переменным, потому что функции — это объекты.
def hello(): # (применяется для хранения в структуре данных (списки, словари) когда нужно выполнить несколько операций по очереди
print("Привет!")
greet = hello # Присваиваем функцию переменной
# Теперь greet — это тоже hello
greet() # Выведет: Привет!
def outer(): # Возврат функции как переменную. (применяется для замыкания, фабрики функций)
def inner():
print("Я внутри!")
return inner # Без скобок!
func = outer() # Теперь func = inner
func() # Выведет: Я внутри!
def double_call(func): # Передаем функцию как аргумент (применяется для сортировка, фильтрация)
func()
func()
double_call(hello)
Колбэк-функция
Колбэк-функция (callback function) — это функция, которую передают в другую функцию как аргумент, чтобы она была вызвана позже или при наступлении события.
def greet(name):
print("Привет,", name)
def process_user(name, callback): # callback — функция
callback(name) # вызываем её внутри
process_user("Анна", greet)
Классы
Классы: Создание экземпляров на основе шаблонов Экземпляры наследуют атрибуты класса
class Car: # имя класса
net = 15 # Атрибут класса, обычно добавляют так константы для использования в других методах
# тело класса Методы move() и stop() просто выполняют действия, но не изменяют состояние объекта.
def move(self): # метод класса, self - указание на экземпляр
Car.net +=1 # Обращение к атрибуту класса
print('одно')
def stop(self): # метод класса
print('другое')
my_car = Car() # Вызов
my_car.move() # одно - Вызов метода
my_car.stop() # другое - Вызов метода
Car.net = 10 # изменение атрибута класса
print(Car.net) #
print(my_car) # <__main__.Car object at 0x000002727DEFBA90>
print(dir(my_car)) # Видно атрибуты move, stop
print(type(my_car)) # <class '__main__.Car'>
print(isinstance(my_car, Car)) # True
print(my_car.__dict__) # {} Собственных атрибутов у my_car нет, move, stop наследуются от класса
class Comment: # Comment хранит данные внутри объекта (self.text, self.votes_qty)
def __init__(self, text): # магический метод для создания нового экземпляра
# В этом классе у каждого комментария есть свои уникальные данные: текст и количество голосов.
# __init__() создаёт эти данные (self.text и self.votes_qty) при создании объекта.
# Без __init__() объект не смог бы хранить текст комментария.
self.text = text # Собственные атрибуты
self.votes_qty = 0
def upvote(self):
self.votes_qty += 1
def upvote2(self, qty):
self.votes_qty += qty # first_comment.upvote(5) передача аргумента 5
# first_comment предыдущее значение 1 сохраняется поэтому выдаст 6
print(first_comment) # <__main__.Image object at 0x0000023EF2D5A110>
# необходимо вести ниже метод __str__ для того чтоб в консоль вывело текст
# def __str__(self):
# return f" {self.text}.{self.votes_qty}"
first_comment = Comment("Первый комментарий") # Создание экземпляра
print(first_comment.text) # Первый комментарий - чтение атрибута класса
print(first_comment.votes_qty) # 0 - чтение атрибута класса (метод upvote() нигде не вызывается!)
# first_comment.upvote() # Теперь вызываем метод votes_qty стал равен 1
# print(first_comment.votes_qty)
Методы экземпляров и классов: Методы экземпляров - всегда получают self (ссылку на объект) Методы класса - привязаны не к объекту а к всему классу cls Статические методы - не привязаны ни к экземпляру, ни к классу. Они работают как обычные функции, но принадлежат классу.
p1 = Player("Алекс")
print(p1.greet)
#Привязанные методы (bound) - Когда метод вызывается через объект (p1.greet()),
# он привязывается к этому объекту.
print(Player.greet)
# Непривязанный метод (unbound) - Если метод вызывается напрямую через класс, он не привязан к объекту. потому что он вызывается через класс без объекта.
Тип метода Привязанность Передаёт self или cls? Можно вызывать без объекта? Метод экземпляра Привязан к объекту self (экземпляр) Нет Метод класса Привязан к классу cls (класс) Да Статический метод Не привязан Нет self или cls Да
class Car:
@staticmethod # декоратор статического метода, не привязывается к экземпляру
def move(net_parametra_self, two)
return f"Просто действие"
# Вызывать можно как науровне класса так и на уровне экземпляра
Магические методы: В собственных классах надо реализовывать методы, чтоб можно было в не классе реализовать функционал
print(ter + ret) # выдаст ошибку так как нету реализации магического метода __add__ в классе
# реализация метода
def __add__(self.text, other):
return (f'{self.text} {other.text}', self.votes_qty + other.votes_qty)
Наследие:
class New_class(Roditelski_class): # наследуется из класса Roditelski_class
def print(self): # Метод __init__ родительского класса вызывается автоматически
print('blood')
class User:
def __init__(self, username, email):
self.username = username
self.email = email
class AdminUser(User):
def __init__(self, username, email, role):
super().__init__(username, email) # super() создает объект который представляет User __init__ - доступ к методу
self.role = role
self.is_admin = True
may_admin = dminUser('admin123', 'admin@ru.com', 'AdminIm')
print(may_admin)
Декоратры
Декоратор. — это функция, которая принимает другую функцию (или метод), изменяет её поведение и возвращает её обратно. Это мощный инструмент, который позволяет добавлять функциональность к функциям без изменения их кода. Используются для логирования, проверки прав, кэширования и других задач
Можно применять к любым callable (функции, методы) Можно вкладывать декораторы друг в друга (цепочки) Декоратор может менять: аргументы функции поведение до/после вызова результат функции
def decorator_function(original_fn):
def wrapper_function(*args, **kwargs): # Функция для перехвата всех аргументов. *args, **kwargs - любые аргументы
print("Код до оригинальной функции") # модифицирующий код до оригинальной функции
result = original_fn(*args, **kwargs) # Вызов функции
print("Function result:", result) # доступ к оригинальной функции
print("Код после оригинальной функции") # модифицирующий код после оригинальной функции
return result # ВАЖНО: Возвращаем результат оригинальной функции , если не возвращать выдаст None
return wrapper_function # ВАЖНО: Возвращаем обернутую функцию (модифицированную с кодом до и после оригинальной функции)
@decorator_function # передача функции ниже в декоратор на верху
def my_function(a, b): # оригинальная функция
print("This is my function!")
return (a, b)
result = my_function(100, 50) # вызов функции
print(result)
Декораторы:
# @staticmethod — делает метод независимым от self экземпляра класса.
# @classmethod — делает метод общим для всех объектов класса.
# @property — превращает метод в атрибут геттер.
# @<property>.setter - Сеттер для свойства
# @<property>.deleter -Делетер для свойства
# @abstractmethod — делает метод абстрактным, заставляя наследников реализовывать его.
# @lru_cache Кэширует результаты функции
# @wraps Сохраняет метаданные оригинальной функции
# @singledispatch Перегрузка функции по типу аргумента
# @contextmanager Упрощает создание менеджеров контекста
# @dataclass Упрощает создание классов
# @asyncio.coroutine / async def Асинхронное программирование
# @functools.wraps — Сохраняет метаданные функции при декорировании (имя, docstring, аннотации)
# @functools.lru_cache - Кэширует результаты вызовов функции
# @functools.cache - Упрощённая версия lru_cache (без ограничения размера)
# @functools.total_ordering - Достаточно определить __eq__ и один оператор сравнения
# @functools.singledispatch - Функция с разной реализацией в зависимости от типа аргумента
# @functools.singledispatchmethod - То же самое, но для методов класса
# @abc.abstractmethod - Обязательный метод для наследников
# @enum.unique - Запрещает одинаковые значения в Enum
# @dataclasses.dataclass - Автоматически генерирует __init__, __repr__, __eq__ и др.
# @contextlib.contextmanager - Позволяет писать контекстный менеджер через yield
# @typing.final - Позволяет проверять Protocol через isinstance
# @coroutine - Старый способ работы с корутинами (устаревающий)
# @warnings.deprecated - Помечает функцию как устаревшую (новые версии Python)
Порядок выполнения нескольких декораторов
@A
@B
@C
def func():
pass
# Эквивалентно: func = A(B(C(func)))
Декораторы применяются снизу вверх, выполняются (при вызове функции) сверху вниз.
def deco_a(func):
print("A: декорируем")
def wrapper():
print("A: до вызова")
func()
print("A: после вызова")
return wrapper
def deco_b(func):
print("B: декорируем")
def wrapper():
print("B: до вызова")
func()
print("B: после вызова")
return wrapper
@deco_a
@deco_b
def hello():
print("HELLO")
Логирование
def log_function_call(fn):
def wrapper(*args, **kwargs):
print(f"Function name: {fn.__name__}") # Логирование {fn.__name__} - магический атрибут дающий доступ к названию функции
print(f"Function arguments: {args}, {kwargs}") # Логирование аргументов
result = fn(*args, **kwargs)
print(f"Function result: {result}") # Логирование результата
return result
return wrapper
@log_function_call
def mult(a, b):
return a * b
print(mult(5, 2))
# валидатор аргументов
def validate_args(fn):
def wrapper(*args, **kwargs):
for arg in [*args, *kwargs.values()]: # values() - доступ к всем значениям
if not isinstance(arg, int) and not isinstance(arg, float):
raise ValueError(f"Type of the {arg} is {type(arg)}",
"All arguments must be int or float!")
return fn(*args, **kwargs)
return wrapper
@validate_args
def sum_nums(a, b):
return a + b
try:
print(sum_nums(7, 2))
print(sum_nums(10.5, 2.3))
print(sum_nums([1, 2, 3], '2.0'))
print(sum_nums(a=10.5, b='2.0'))
except ValueError as e:
print(e)
Инспекция и dunder-атрибуты
Инспекция объектов (Introspection)
print(dir(obj)) # Показывает список всех доступных атрибутов и методов объекта
print(id(obj)) # Показывает уникальный идентификатор (адрес в памяти)
print(type(obj)) # Показывает тип (класс) объекта
print(help(obj)) # Показывает встроенную справку по объекту
print(obj.__doc__) # Показывает строку документации (docstring)
print(obj.__dict__) # Словарь атрибутов объекта
print(obj.__class__) # Класс, к которому принадлежит объект
print(obj.__module__) # Модуль, в котором определён объект
print(obj.__annotations__) # Аннотации типов (если есть)
print(obj.__sizeof__()) # Размер объекта в байтах
from sys import getsizeof
print(getsizeof(obj)) # Альтернатива — учитывает служебную информацию
Информация о классах и наследовании
print(MyClass.__subclasses__()) # Список всех подклассов данного класса
print(MyClass.__bases__) # Кортеж базовых (родительских) классов
print(MyClass.__mro__) # Порядок разрешения методов (Method Resolution Order)
print(MyClass.__name__) # Имя класса
Магические методы (Dunder methods)
Строковые представления
obj.__repr__() # “Официальное” строковое представление (для разработчиков)
obj.__str__() # “Человеческое” строковое представление (для вывода)
Хэш и сравнения
obj.__hash__() # Возвращает хэш-значение объекта
obj.__eq__(x) # Равно ==
obj.__ne__(x) # Не равно !=
obj.__lt__(x) # Меньше <
obj.__le__(x) # Меньше или равно <=
obj.__gt__(x) # Больше >
obj.__ge__(x) # Больше или равно >=
Прочие специальные атрибуты
obj.__slots__ # Определяет допустимые атрибуты (ограничивает __dict__)
Обработка ошибок
try:
pass # блок кода который выполняется
except ErrorType: # тип ошибки, если словил этот тип то
pass
# в случаи ошибки в try выполнится блок кода except
# Если корректно обработали ошибку, то Python не останавливает выполнение кода
except ErrorType as e: # присваивает ошибке имя , можно в try несколько except
print(type(e)) # выведет текст ошибки
else: # если не сработало не одно исключение
finally: # выполняется в любом случаи
try:
pass # блок кода который выполняется
except Exception as e: # если не знаешь какая ошибка
print(e)
# Почему не стоит использовать Exception
# Ловля конкретных ошибок делает код более читаемым и предсказуемым
# Ловля только нужных ошибок помогает избежать нежелательного подавления других исключений
# Обработка Exception может замаскировать баги
# Более точная обработка ошибок позволяет лучше реагировать на ситуацию
# Исключения выше Exception (например, SystemExit, KeyboardInterrupt) не обрабатываются явно
# Когда использовать Exception:
# Когда вы точно не знаете, какие ошибки могут возникнуть (например, в тестовой среде или временном коде).
# Для логирования всех ошибок, если ваш код затем завершает работу или пересылает ошибку.
raise # используется для генерации исключений. Оно позволяет "поднять" ошибку вручную, когда в коде возникает нежелательная ситуация, или передать исключение выше по стеку вызовов.
def set_age(age): # Пример
if age < 0:
raise ValueError("Возраст не может быть отрицательным")
print(f"Возраст установлен: {age}")
set_age(-5)
# Пример подключение к БД - подключение в try, другие действия в else так как ошибок не возникло , отключение finally
Хорошая практика перенаправлять ошибки на отдельный сервис логирования Хорошая практика обрабатывать ошибки в функции
Типы ошибок стандартной библиотеке Python:
ArithmeticError Базовый класс для всех ошибок, связанных с математическими операциями.
AssertionError Возникает при неудачном выполнении инструкции assert.
AttributeError Обращение к несуществующему атрибуту объекта.
BaseException Базовый класс для всех исключений (включая SystemExit, KeyboardInterrupt, и GeneratorExit).
BufferError Ошибка, связанная с операциями буфера.
BytesWarning Предупреждение о проблемах с байтовыми строками (только для режима -b).
DeprecationWarning Предупреждение об использовании устаревших функций.
EOFError Ошибка при достижении конца файла или потока, где это не ожидается.
Exception Базовый класс для большинства исключений (не включая SystemExit, KeyboardInterrupt и GeneratorExit).
FileExistsError Возникает при попытке создания файла, который уже существует.
FileNotFoundError Указанный файл или директория не найдены.
FloatingPointError Ошибка, связанная с операциями с плавающей точкой (редко возникает).
FutureWarning Предупреждение о предстоящих изменениях в функциональности.
GeneratorExit Вызывается при закрытии генератора.
ImportError Ошибка при импорте модуля.
ModuleNotFoundError: Подкласс, вызывается, если модуль не найден.
IndentationError Ошибка синтаксиса, вызванная неверными отступами.
TabError: Подтип, возникающий при смешении пробелов и табуляции.
IndexError Индекс выходит за границы последовательности.
KeyError Обращение к несуществующему ключу в словаре.
KeyboardInterrupt Прерывание программы пользователем (например, Ctrl+C).
LookupError Базовый класс для ошибок поиска (например, IndexError или KeyError).
MemoryError Превышение доступной памяти.
NameError Использование имени, которое не определено.
UnboundLocalError: Подтип, если локальная переменная используется до её определения.
NotADirectoryError Попытка обратиться к объекту, который не является директорией.
NotImplementedError Метод или функция не реализованы.
OSError Ошибка, связанная с операционной системой (например, работа с файлами).
Подклассы:
BlockingIOError Операция ввода-вывода заблокирована в неблокирующем режиме.
ChildProcessError Ошибка при работе с дочерними процессами (например, ожидание несуществующего процесса).
ConnectionError Базовый класс для ошибок соединения. и его подклассы:
BrokenPipeError Соединение или канал разорваны.
ConnectionAbortedError Соединение было прервано другой стороной.
ConnectionRefusedError Соединение отклонено (например, сервер не отвечает).
ConnectionResetError Соединение сброшено другой стороной.
FileExistsError Попытка создать файл или директорию, которая уже существует.
FileNotFoundError Указанный файл или директория не найдены.
IsADirectoryError Операция ожидала файл, но путь указывает на директорию.
NotADirectoryError Операция ожидала директорию, но путь указывает на файл.
PermissionError Недостаточно прав для выполнения операции.
ProcessLookupError Указанный процесс не найден.
TimeoutError Время ожидания операции истекло.
OverflowError Результат вычислений слишком велик для представления.
PendingDeprecationWarning Предупреждение о функциональности, которая будет устаревать в будущем.
PermissionError Недостаточно прав для выполнения операции.
ProcessLookupError Указанный процесс не найден.
RecursionError Превышен лимит рекурсии.
ReferenceError Попытка доступа к объекту через слабую ссылку, когда объект уже удалён.
ResourceWarning Предупреждение о неправильном использовании ресурсов (например, не закрытый файл).
RuntimeError Общая ошибка выполнения, не подпадающая под другие категории.
SyntaxError Ошибка синтаксиса.
IndentationError: Подтип, связанный с неверными отступами.
TabError: Смесь пробелов и табуляций.
SystemError Внутренняя ошибка интерпретатора.
SystemExit Исключение для выхода из программы (например, вызов sys.exit()).
TabError Смесь пробелов и табуляции в отступах.
TimeoutError Истечение времени выполнения операции.
TypeError Некорректная операция с объектами неподходящего типа.
UnboundLocalError Локальная переменная используется до её определения (подтип NameError).
UnicodeDecodeError Ошибка декодирования строки Unicode.
UnicodeEncodeError Ошибка кодирования строки Unicode.
UnicodeError Базовый класс для ошибок Unicode.
UnicodeTranslateError Ошибка преобразования строки Unicode.
UserWarning Пользовательское предупреждение.
ValueError Некорректное значение передано функции или методу.
Warning Базовый класс для предупреждений.
ZeroDivisionError Деление на ноль.
Изменяемость, идентичность, копирование
Тип данных и их свойства
list |
Изменяемый |
упорядоченный |
одинаковые элементы |
tuple |
нет |
упорядоченный |
одинаковые элементы |
set |
Изменяемый |
нет |
нет |
range |
нет |
упорядоченный |
нет |
dict |
Изменяемый |
нет |
нет |
str |
нет |
упорядоченный |
одинаковые элементы |
Адреса объектов в памяти
m_n = 10
print(id(m_n)) # 2798471414288
o_n = 10
print(id(o_n)) # 2798471414288
c_n = m_n
print(id(m_n)) # 2798471414288
print(id(c_n)) # 2798471414288
c_n += 5 # создаётся новый объект
print(id(m_n)) # 2798471414288
print(id(c_n)) # другой адрес
Примечание: неизменяемые объекты (int, str, tuple) при изменении создают новую копию в памяти, а изменяемые (list, dict, set) — работают по ссылке.
Поверхностное и глубокое копирование
from copy import deepcopy
info_deepcopy = deepcopy(словарь)
# Возвращает новый объект с копиями всех вложенных структур.
def copy_fn(person):
person_copy = person.copy() # поверхностная копия
person_copy["age"] += 2
return person_copy
Разница: copy() создаёт копию только верхнего уровня (не вложеные объекты). deepcopy() — рекурсивно копирует все вложенные объекты. = просто создаёт новую ссылку на тот же объект в памяти.
Принципы ООП
Инкапсуляция, Наследование, Полиморфизм, Абстракция.
Инкапсуляция — это когда мы скрываем детали реализации внутри класса и предоставляем только нужные методы для работы с объектом.
class Email:
def __init__(self, sender, recipient, subject, body):
self.sender = sender # Закрытая переменная (инкапсуляция)
self.recipient = recipient
self.subject = subject
self.body = body
def send_email(self):
# Логика отправка писем
pass
def deposit(self, amount):
if amount > 0:
self.__balance += amount # Доступ к данным через метод
else:
print("Сумма должна быть положительной!")
def get_balance(self):
return self.__balance # Доступ только через метод
def read_email(self):
# Логика чтения писем
pass
# print(account.__balance) # Ошибка! Прямой доступ запрещён
# Инкапсуляция защищает данные и скрывает детали, позволяя работать
# только с нужными частями объекта.
Наследование - позволяет одному классу (наследнику) наследовать свойства и методы другого класса (родителя). Это позволяет переиспользовать код и создавать более специфичные классы на основе более общих.
class Animal: # Родительский класс
def __init__(self, name):
self.name = name
def speak(self):
return "Some sound"
class Dog(Animal): # Дочерний класс, наследует от Animal
def __init__(self, name, breed): # Конструктор для Dog
super().__init__(name) # Вызов конструктора родителя (Animal)
self.breed = breed # Дополнительный атрибут breed для собаки
# Когда мы хотим расширить функциональность конструктора родительского класса.
# Это позволяет инициализировать атрибуты родительского класса и добавить новые
# атрибуты в дочернем классе.
def speak(self): # Переопределение метода speak
parent_sound = super().speak() # Вызов метода родительского класса
# Сохраняем функциональность родителя и добавляем свою.
# Это важно, когда нужно не просто заменить поведение родительского метода, но
# и добавить новое поведение без потери того, что уже реализовано в родителе.
return parent_sound + " and Woof!" # Дополняем вывод дополнительным звуком
class Cat(Animal): # Другой дочерний класс, также наследует от Animal
def speak(self): # Переопределение метода speak
return "Meow!"
# Создаём объекты
dog = Dog("Buddy")
cat = Cat("Whiskers")
print(dog.name) # Buddy
print(dog.speak()) # Woof!
print(cat.name) # Whiskers
print(cat.speak()) # Meow!
# Наследование — это способ переиспользовать и расширять функциональность
# классов, создавая более сложные и специализированные объекты,
# базируясь на общих классах.
Полиморфизм - способность методов (функций) работать по-разному в зависимости от объекта, который их вызывает.
Когда один и тот же метод (или оператор) делает разное в зависимости от объекта. Это делает код гибким, удобным и читаемым!
# Родительский класс
class Animal:
def make_sound(self):
return "Какой-то звук" # Базовое поведение
# Дочерний класс, переопределяющий метод
class Dog(Animal):
def make_sound(self): # Переопределение метода родителя
return "Гав-гав!"
# Дочерний класс, переопределяющий метод
class Cat(Animal):
def make_sound(self): # Переопределение метода родителя
return "Мяу!"
# Дочерний класс, который вызывает метод родителя через super()
class Fox(Animal):
def make_sound(self):
return super().make_sound() + " но конкретно я говорю Фррр!" # Расширение метода родителя
# Функция, которая работает с разными объектами (полиморфизм)
def animal_sound(animal):
print(animal.make_sound())
# Создаём объекты разных классов
dog = Dog()
cat = Cat()
fox = Fox()
# Вызываем одну и ту же функцию с разными объектами (полиморфизм)
animal_sound(dog) # Выведет: "Гав-гав!"
animal_sound(cat) # Выведет: "Мяу!"
animal_sound(fox) # Выведет: "Какой-то звук но конкретно я говорю Фррр!"
def add(a, b): # полиморфизм через функцию
return a + b
print(add(1, 2)) # Выведет: 3
print(add("Hello, ", "world!")) # Выведет: Hello, world!
# Сначала ищет метод в самом объекте (его классе) поиска методов идёт снизу вверх.
# Если не находит, поднимается выше по иерархии классов (ищет в родительском классе).
# Если находит, вызывает его.
# Если метод не найден AttributeError
Полиморфизм без наследования
class Dog:
def sound(self):
return "Woof"
class Cat:
def sound(self):
return "Meow"
animals = [Dog(), Cat()]
for animal in animals:
print(animal.sound())
# Полиморфизм работает через одинаково названные методы в разных классах.
Абстракция — это процесс выделения только ключевых характеристик объекта, игнорируя все лишнее. Мы создаем упрощенную модель или интерфейс, оставляя детали реализации скрытыми.
from abc import ABC, abstractmethod
class Transport(ABC): # Делаем класс абстрактным
@abstractmethod # декоратор обязывает все дочернии классы прописывать этот метод иначе ошибка
# Класс Bicycle не реализует абстрактный метод travel()
def travel(self):
pass
class Car(Transport):
def travel(self):
return "Поехал на машине"
class Bus(Transport):
def travel(self):
return "Поехал на автобусе"
class Train(Transport):
def travel(self):
return "Поехал на поезде"
# Реальная жизнь: у нас есть несколько видов транспорта
vehicles = [Car(), Bus(), Train()]
for vehicle in vehicles:
print(vehicle.travel()) # Вызывает нужный метод в зависимости от типа объекта
Преимущества абстракции: Упрощение работы с системой. Мы не погружаемся в детали реализации, а используем высокоуровневые интерфейсы. Гибкость и масштабируемость. Можно добавлять новые классы, не меняя код, который использует абстракцию. Снижение сложности. Мы скрываем сложные детали, оставляя только то, что важно для пользователя. Когда используется абстракция: При проектировании интерфейсов. Когда нужно скрыть реализацию, оставив только важные для пользователя части. В крупных системах, где взаимодействие происходит через интерфейсы, а не через детали реализации.
Модули
Основы синтаксиса
Импорт модуля – относительно дорогостоящее мероприятие, поэтому Python предпри- нимает некоторые трюки для ускорения этого процесса. Один из способов – создать байт-компилированные файлы (или байткод) с расширением .pyc, которые являются некой промежуточной формой, в которую Python переводит программу (помните раздел “Введение” о том, как работает Python?). Такой файл .pyc полезен при импорте модуля в следующий раз в другую программу – это произойдёт намного быстрее, поскольку зна- чительная часть обработки, требуемой при импорте модуля, будет уже проделана. Этот байткод также является платформо-независимым.
Примечание
Обычно файлы .pyc создаются в том же каталоге, где расположены и соот- ветствующие им файлы .py. Если Python не может получить доступ для записи файлов в этот каталог, файлы .pyc созданы не будут.
Оператор from … import …
Чтобы импортировать переменную argv прямо в программу и не писать всякий раз sys. при обращении к ней, можно воспользоваться выражением «from sys import argv». Для импорта всех имён, использующихся в модуле sys, можно выполнить команду «from sys import «»»*»»»». Это работает для любых модулей. В общем случае вам следует избегать использования этого оператора и использовать вместо этого оператор import, чтобы предотвратить конфликты имён и не затруднять чтение программы.
from math import *
n = input("Введите диапазон:- ") p = [2, 3]
count = 2
a=5
while (count < n):
b=0
for i in range(2,a):
if ( i <= sqrt(a)): if (a % i == 0):
print("a neprost",a)
b=1
else:
pass
if (b != 1):
print("a prost",a) p = p + [a]
count = count + 1
a=a+2
print p
Имя модуля – __name__
У каждого модуля есть имя, и команды в модуле могут узнать имя их модуля. Это полез- но, когда нужно знать, запущен ли модуль как самостоятельная программа или импорти- рован. Как уже упоминалось выше, когда модуль импортируется впервые, содержащийся в нём код исполняется. Мы можем воспользоваться этим для того, чтобы заставить мо- дуль вести себя по-разному в зависимости от того, используется ли он сам по себе или импортируется в другую программа. Этого можно достичь с применением атрибута мо- дуля под названием __name__.
if __name__ == '__main__':
print('Эта программа запущена сама по себе.')
else:
print('Меня импортировали в другой модуль.')
- Как это работает:
В каждом модуле Python определено его имя – __name__ . Если оно равно „__main__“, это означает, что модуль запущен самостоятельно пользователем, и мы можем выполнить соответствующие действия.
Импорт модулей и функций в Python
Python позволяет импортировать модули и отдельные функции разными способами, переменные. Каждый способ имеет свои плюсы и минусы.
Импорт всего модуля
Если нужно использовать несколько функций из модуля.
import math # импорт всего модуля
print(math.sqrt(16)) # вызов функции через имя модуля
print(dir(math)) # список всех функций и переменных модуля
Плюсы: - Ясно, откуда функция (math.sqrt) - Избегает конфликтов имён
Минусы: - Нужно писать имя модуля каждый раз
Переименование модуля (alias)
import math as m
print(m.sqrt(16)) # сокращённый вызов
Когда использовать: - Модуль имеет длинное имя (например, matplotlib.pyplot → plt) - Часто используешь функции модуля, хочется сократить код
Импорт конкретной функции
from math import sqrt
print(sqrt(16)) # вызов напрямую
Плюсы: - Не нужно писать имя модуля - Быстрее доступ к функциям
Минусы: - Может быть неясно, из какого модуля функция - Возможны конфликты имён, если функция с таким именем уже есть
Импорт всех функций модуля
from math import *
⚠ Минусы: - Неясно, откуда взялись функции - Возможны конфликты имён - Сложнее читать и отлаживать код
Вывод: - import module — безопасно и читаемо - import module as alias — удобно для длинных имён - from module import func — удобно, когда нужны только конкретные функции - from module import * — использовать не рекомендуется
Создание собственных модулей
Создать собственный модуль очень легко. Да вы всё время делали это! Ведь каждая про- грамма на Python также является и модулем. Необходимо лишь убедиться, что у неё уста- новлено расширение .py. Следующий пример объяснит это.
# mymodule.py
def sayhi():
print('Привет! Это говорит мой модуль.')
__version__ = '0.1'
Выше приведён простой модуль. Как видно, в нём нет ничего особенного по сравнению с обычной программой на Python. Далее посмотрим, как использовать этот модуль в дру- гих наших программах. Помните, что модуль должен находиться либо в том же каталоге, что и программа, в ко- торую мы импортируем его, либо в одном из каталогов, указанных в sys.path.
# mymodule_demo.py
import mymodule
mymodule.sayhi()
print ('Версия', mymodule.__version__)
Примечание
Обратите внимание, что мы используем всё то же обозначение точкой для до- ступа к элементам модуля. Python повсеместно использует одно и то же обо- значение точкой, придавая ему таким образом характерный «Python-овый» вид и не вынуждая нас изучать всё новые и новые способы делать что-либо.
Вот версия, использующая синтаксис from..import
# mymodule_demo2.py
from mymodule import sayhi, __version__
sayhi()
print('Версия', __version__)
Примечание
Обратите внимание, что если в модуле, импортирующем данный модуль, уже было объ- явлено имя __version__, возникнет конфликт. Это весьма вероятно, так как объявлять версию любого модуля при помощи этого имени – общепринятая практика. Поэтому всегда рекомендуется отдавать предпочтение оператору import, хотя это и сделает вашу программу немного длиннее.
Вы могли бы также использовать from mymodule import *
Это импортирует все публичные имена, такие как sayhi, но не импортирует __version__, потому что оно начинается с двойного подчёркивания
Модули поставляемые с Python и Встроенные модули
Модули с _ в начале (например, _abc, _collections) — это внутренние низкоуровневые модули, которые Python использует сам, но их можно импортировать. Остальные (например, math, sys, json, os) — обычные стандартные модули, доступные сразу без установки. Публичный модуль (без _) — это “обёртка” над _модулем, которая делает интерфейс удобным, безопасным и переносимым между платформами.
Правило: Используй публичные модули в своём коде. _модули — только если знаешь точно, что делаешь, и нужен низкоуровневый доступ.
Модули, поставляемые с Python (stdlib .py modules)
Это пакеты и файлы Python, которые идут вместе с установкой Python. Реализованы на Python (.py) и тоже доступны сразу после установки. Примеры: os, json, re, collections, http. Эти модули входят в sys.stdlib_module_names, вместе с встроенными.
# Просмотр всех модулей стандартной библиотеки
import sys
print(sorted(sys.stdlib_module_names))
_модули
__future__
_aix_support
_android_support
_apple_support
_ast_unparse
_asyncio
_bz2
_collections_abc
_colorize
_compat_pickle
_ctypes
_curses
_curses_panel
_dbm
_decimal
_elementtree
_frozen_importlib
_frozen_importlib_external
_gdbm
_hashlib
_ios_support
_lzma
_markupbase
_multiprocessing
_opcode_metadata
_osx_support
_overlapped
_posixshmem
_posixsubprocess
_py_abc
_py_warnings
_pydatetime
_pydecimal
_pyio
_pylong
_pyrepl
_queue
_remote_debugging
_scproxy
_sitebuiltins
_socket
_sqlite3
_ssl
_strptime
_threading_local
_tkinter
_uuid
_weakrefset
_wmi
_zoneinfo
_zstd
abc
annotationlib
antigravity
argparse
ast
asyncio
base64
bdb
bisect
bz2
cProfile
calendar
cmd
code
codecs
codeop
collections
colorsys
compileall
compression
concurrent
configparser
contextlib
contextvars
copy
copyreg
csv
Модуль csv позволяет легко:
читать CSV-файлы; записывать данные построчно; настраивать разделители, кавычки, кодировки; работать с таблицами как со списками.
CSV = текстовый файл, где данные разделены символом (обычно , или ;).
Основные объекты:
csv.writer — запись строк; csv.reader — чтение строк; DictWriter / DictReader — запись/чтение как словарей.
import csv
# --- Запись CSV ---
with open('test.csv', 'w', encoding='utf-8') as csv_file:
writer = csv.writer(csv_file, delimiter=';')
# writer — объект для записи; delimiter=';' задаёт разделитель колонок
writer.writerow(['user_id', 'user_name', 'comments_qty'])
# writerow — записать одну строку (список → строка CSV)
writer.writerow([5235, 'Mikhail', 1352])
writer.writerow([1567, 'Olga', 246])
writer.writerow([1990, 'Lina', 79])
# Три строки с данными → попадут в test.csv
# --- Чтение CSV ---
with open('test.csv', encoding='utf-8') as csv_file:
reader = csv.reader(csv_file)
# reader — объект, который читает строки файла и превращает в списки
for line in reader:
print(line)
# Каждая строка CSV возвращается как список (все значения — строки)
# Пример с DictReader
# Запись
data = [
{"user_id": 5235, "user_name": "Mikhail", "comments_qty": 1352},
{"user_id": 1567, "user_name": "Olga", "comments_qty": 246},
]
with open('dict.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=["user_id", "user_name", "comments_qty"])
writer.writeheader() # записывает заголовки
writer.writerows(data) # записывает список словарей
# Чтение
with open('dict.csv', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
print(row)
# row — словарь
По умолчанию csv.writer использует: , как разделитель → мы переопределили на ; « как кавычки
Важные параметры:
delimiter Разделитель (;, ,, t) quotechar Кавычки для текстовых значений (обычно «) quoting Когда ставить кавычки (csv.QUOTE_MINIMAL, ALL, NONE) newline=““ Обязательно на Windows, чтобы не было пустых строк
Когда CSV — идеальный выбор: таблицы небольшого размера, обмен данными между программами, импорт/экспорт в Excel, логи, статистика, выгрузки.
Когда CSV плохо подходит: вложенные структуры (JSON лучше), большие объёмы данных (>100MB), бинарные данные, сложные форматы.
ctypes
curses
dataclasses
DateTime
from datetime import data
my_date = date(2100, 4, 15)
print(my_date) # 2100-04-15
print(my_date.day) # 15
print(my_date.isocalendar()) # datetime.IsoCalendarDate(year=2100, week=15, weekday=4)
from datetime import time
my_time = time(18, 10, 45) # 18:10:45 час, минута, секунда
print(my_time.hour) # 18
from datetime import datetime
my_datetime = datetime(2025, 12, 10, 18, 10, 45) # 2100-04-15 18:10:45
Форматирование дат
from datetime import datetime, timedelta
my_datetime = datetime(2025, 12, 10, 18, 10, 45) # 2100-04-15 18:10:45
my_datetime.strftime('%d-%b/%Y %H:%M:%S') # 10-Dec/2025 18:10:45
a = '10/12/225'
converted = datetime.strftime(a,'%d-%b/%Y %H:%M:%S') # 10-Dec/2025 18:10:45
my_datetime + timedelta(days=100, hours=2) # прибавит к дате 100 дней
import time
time.time() # вывод секунд с Юникс эпохи с 01.01.1970
time.ctime(24553453) # Mon Oct 12 15:24:13 1970
time.sleep(2.5) # Остановит исполнение следующего кода на 2,5 секунд
start_time = time.time()
# выполняемый код
end_time = time.time()
print(end_time - start_time) # Время выполнения кода
dbm
decimal
difflib
dis
doctest
email
encodings
ensurepip
enum
fcntl
filecmp
fileinput
fnmatch
fractions
ftplib
functools
genericpath
getopt
getpass
gettext
glob
graphlib
grp
gzip
hashlib
heapq
hmac
html
http
Протокол http – это простой текстовый протокол передачи данных.
Модуль http - это пакет, собирающий несколько модулей для работы с протоколом передачи гипертекста:
*http.client* - низкоуровневый клиент протокола HTTP. Клиент высокого уровня urllib.request
*http.server* - содержит базовые классы HTTP-серверов на основе socketserver
*http.cookies* - имеет утилиты для реализации управления состоянием с помощью cookies
*http.cookiejar* - обеспечивает сохраняемость cookies
Применяется модуль:
Обучение сетевому программированию (Отличный инструмент для понимания, как работает HTTP «под капотом».)
Создание простых REST-API (Без Flask/Django — идеально для экспериментов.)
Локальная разработка статических сайтов (http.server → просмотр HTML/CSS/JS как на сервере.)
Прототипирование (Можно быстро накидать мини-сервер для тестов.)
Системные утилиты (Обмен файлами в сети, просмотр каталогов, лёгкие админ-панели.)
http.client
http.client — HTTP-клиент (аналог requests, но встроенный). Позволяет отправлять HTTP-запросы без сторонних библиотек.
Позволяет отправлять HTTP-запросы: GET, POST, PUT, DELETE, OPTIONS, …; Работа по HTTP и HTTPS; Управление заголовками; Чтение тела ответа. Не предназначен для использования в продакшн-среде. Его минимальные функции безопасности делают его легкой добычей для хакеров!
import http.client
# Устанавливаем соединение с сервером
conn = http.client.HTTPSConnection("www.python.org") # Можно использовать HTTPConnection для HTTP
# Отправляем GET-запрос
conn.request("GET", "/")
# Получаем ответ
response = conn.getresponse()
print(f"Статус ответа: {response.status} {response.reason}") # Выведет 200 OK
# Читаем тело ответа (декодируем байты в строку)
data = response.read().decode('utf-8')
# print(data) # Раскомментируйте, чтобы увидеть HTML-код страницы
# Закрываем соединение
conn.close()
http.server
HTTPServer - Базовый класс сервера, принимает обработчик запросов.
python3 -m http.server 8000 # запустить HTTP-сервер. 8000 - порт
python3 -m http.server --bind 127.0.0.1 8000 # Запуск локального сервера
python3 -m http.server --directory /path/to/directory 8000 # доступ к файлам конкретной директории
python3 -m http.server --bind ::1 # указывает, к какому IP-адресу сервер привязывается.
# Запись ::1 сокращает длинный адрес: 0000:0000:0000:0000:0000:0000:0000:0001
# http://[::1]:8000/
BaseHTTPRequestHandler - Базовый обработчик. Можно вручную описать методы: do_GET() do_POST() do_HEAD(). Позволяет строить свои API, обработчики форм, прокси и т.д.
SimpleHTTPRequestHandler - Готовый сервер статических файлов: отдаёт HTML, CSS, JS, изображения; поддерживает directory listing; опционально позволяет указать корневую директорию.
http.HTTPStatus
http.HTTPStatus — перечисление HTTP-кодов
idlelib
imaplib
importlib
inspect
io
ipaddress
json
JSON (JavaScript Object Notation) — это текстовый формат обмена данными и формат файлов, используемый для передачи данных между программами и сервисами.
JSON используется в:
API (REST) конфигурационные файлы базы данных веб игры микросервисы
JSON не является Python-форматом, но Python умеет с ним работать через встроенный модуль json.
Основные особенности JSON: JSON — строгий формат Используются только двойные кавычки « » Данные передаются в виде строки Типы данных отличаются от Python Логические значения: true, false — в нижнем регистре Значение отсутствия данных — null
Типы данных в JSON: string — строка number — число (целое или дробное) object — объект (аналог словаря) array — массив boolean — логическое значение null — отсутствие значения
Для работы используется встроенный модуль json.
import json
# JSON-строка (обязательно двойные кавычки)
json_str = '{"id": 235, "brand": "Nike", "qty": 84, "status": {"isForSale": true}}'
# loads() — преобразует JSON-строку в Python-словарь
sneakers = json.loads(json_str)
print(sneakers['brand']) # Nike
print(sneakers['status']['isForSale']) # True
Преобразование Python → JSON
import json
# dumps() — преобразует Python-объект в JSON-строку
json_text = json.dumps(sneakers)
# indent — форматированный вывод (отступы)
json_text = json.dumps(sneakers, indent=2)
Соответствие типов Python ↔ JSON
Python |
JSON |
|---|---|
dict |
object {} |
list |
array [] |
tuple |
array [] |
set |
array [] |
str |
string |
int |
number |
float |
number |
bool (True / False) |
true / false |
None |
null |
Важно помнить при чтении JSON: array → list object → dict JSON не поддерживает: комментарии множества (set) пользовательские типы JSON — это данные, а не код
Чтение и запись JSON-файлов
loads / dumps — работают со строками load / dump — работают с файлами Буква s = string (строка) — это ключ к запоминанию.
import json
# Запись в файл
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
# Чтение из файла
with open("data.json", "r", encoding="utf-8") as f:
data = json.load(f)
Отлавивание ошибкок
JSONDecodeError возникает, когда: JSON невалидный строка не JSON пустая строка HTML / текст вместо JSON ошибка синтаксиса (кавычки, запятые, true/false)
import json
try:
data = json.loads(response_text)
except json.JSONDecodeError as e:
print("Ошибка разбора JSON")
print(e)
keyword
linecache
locale
logging
lzma
mailbox
mimetypes
modulefinder
multiprocessing
netrc
ntpath
nturl2path
numbers
opcode
operator
optparse
os
pathlib
pdb
pickle
pickletools
pkgutil
platform
plistlib
poplib
posix
posixpath
pprint
profile
pstats
pty
pwd
py_compile
pyclbr
pydoc
pydoc_data
pyexpat
queue
quopri
random
random в Python предназначен для статистического моделирования, а не для криптографической безопасности.
Генератор случайных чисел модуля random псевдослучайный. Когда ты задаёшь random.seed(42), ты устанавливаешь начальное состояние генератора. Все последующие вызовы random будут вычислять числа по одному и тому же алгоритму, начиная с этого состояния. Поэтому последовательность чисел всегда одинаковая для одного и того же seed.
Инициализация и управление состоянием генератора
Зачем нужно: Для повторяемых экспериментов (Если хочешь повторно сгенерировать те же числа в будущем) Для отладки игр (Для отладки — можно вернуться к определённому месту генератора) Для воспроизводимости результатов (В играх или симуляциях, чтобы «сохранить состояние случайностей»)
import random
# Инициализация генератора случайных чисел
random.seed(42) # Всегда одно и то же число.
# Если нет аргумента — используется системное время.
# Сейчас: 12:01:32 → одно число
# Через секунду: 12:01:33 → другое число
# Системное время нужно, чтобы автоматически дать генератору новое стартовое число, когда ты его сам не указал.
# Получение внутреннего состояния генератора
state = random.getstate()
# Представь генератор случайных чисел как длинную ленту с числами, которые заранее «записаны» (хоть мы их не видим).
# Внутреннее состояние — это точка на этой ленте, где ты сейчас находишься.
# С этого места генератор берёт следующее число.
# Состояние включает: текущее место в последовательности псевдослучайных чисел, внутренние параметры Mersenne Twister,
# Возвращает генератор случайных чисел в то же самое место, где ты его сохранил через getstate().
random.setstate(state)
Работа с битами
Используется в: Криптографии (небезопасной) Генерации масок Низкоуровневых задачах
import random
# Возвращает N случайных бит
bits = random.getrandbits(8) # 8 бит = число от 0 до 255
# 8 бит = 1 байт - 1 байт может хранить числа от 0 до 255
print(bits)
# Для работы на уровне битов (шифрование, маски, флаги)
#Эта строка даёт тебе 8 случайных флагов сразу. bits = 173 В двоичном виде это: 173 = 10101101
#Бит Значение Смысл флага
#1 1 включён
#0 0 выключен
#1 1 включён
#0 0 выключен
#1 1 включён
#1 1 включён
#0 0 выключен
#1 1 включён
Целые случайные числа
Примеры: Бросок кубика Генерация ID Случайные координаты
import random
# Случайное число из диапазона [A, B]
num1 = random.randint(10, 20)
print(num1)
# Случайное число из последовательности с шагом
num2 = random.randrange(0, 100, 5)
print(num2)
Работа с последовательностями (списки, строки и т.д.)
shuffle() не работает со строками и кортежами, потому что они неизменяемы.
import random
items = ["меч", "щит", "лук", "зелье"]
# Случайный элемент из последовательности (список не меняется)
item = random.choice(items)
print(item)
# Перемешивание списка (изменяет сам список!)
random.shuffle(items)
print(items)
# Случайная выборка k элементов без повторений
selected = random.sample(items, 2)
print(selected)
Случайные вещественные числа (базовые)
Используется:
Физические симуляции Разброс значений Игровая механика
import random
# Случайное число от 0.0 до 1.0
r1 = random.random()
print(r1)
# Случайное число от A до B
r2 = random.uniform(5.5, 9.9)
print(r2)
# Треугольное распределение
r3 = random.triangular(0, 10, 3) # 0 — минимальное значение, 10 — максимальное значение, 3 — самое вероятное значение
print(r3)
Нормальные и логнормальные распределения
Применяется: Физика Экономика Ошибки измерений Статистика
import random
# Нормальное (Гауссово) распределение
n1 = random.gauss(100, 10)
print(n1)
# 100 — среднее значение
# 10 — разброс
# Большинство чисел будет около 100
# Иногда будут 90, 110
# Очень редко — 70 или 130
# Альтернатива нормальному распределению
n2 = random.normalvariate(0, 1)
print(n2)
# То же самое распределение, что и gauss, только другая реализация внутри
# 0 — центр
# 1 — небольшой разброс
# Логнормальное распределение
ln = random.lognormvariate(0, 1)
print(ln)
# Значения всегда ТОЛЬКО больше 0
# Много маленьких чисел
# Редко появляются очень большие
Экспоненциальное и гамма-распределения
Применяется:
Моделирование времени ожидания Очереди Надёжность систем
import random
# Экспоненциальное распределение
exp = random.expovariate(1.5)
print(exp)
# Создаёт случайное число, которое показывает время до следующего события.
# 1.5 — как часто событие происходит (чем больше число, тем меньше случайное число).
# Гамма-распределение
gamma = random.gammavariate(2.0, 1.0)
print(gamma)
# Создаёт случайное число, которое суммирует несколько случайных событий.
# 2.0 — сколько событий складываем, 1.0 — масштаб (размер чисел).
Бета-распределение
Используется: Вероятности успеха Байесовская статистика Машинное обучение
import random
# Бета-распределение (0..1)
beta = random.betavariate(2.0, 5.0)
print(beta)
# Оно всегда даёт число от 0 до 1.
# Параметры (2.0, 5.0) решают, где числа чаще будут выпадать:
# 2.0 (первый параметр) — «слева» (числа ближе к 0).
# 5.0 (второй параметр) — «справа» (числа ближе к 1).
Угловые распределения (Von Mises)
Используется: Физика вращения Направление движения 2D/3D-игры
import random
# Угловое распределение (радианы)
angle = random.vonmisesvariate(math.pi, 2.0)
print(angle)
# Генерирует случайный угол в радианах random.vonmisesvariate(mu, kappa)
# Используется для круговых данных (например, направление ветра, положение стрелки на круге).
# Параметры:
# mu — центр распределения (куда «тяготеют» углы).
# kappa — концентрация вокруг центра:
# Большое kappa → углы близко к mu.
# Малое kappa → углы более разбросаны по кругу.
Распределение Парето
Используется: Экономика Распределение богатства «20% дают 80%»
import random
# Распределение Парето
p = random.paretovariate(2.5)
print(p)
# Парето — распределение, где маленькие числа встречаются часто, а большие — редко, но иногда попадаются очень большие.
# 2.5 — параметр, который влияет на «редкость больших чисел»: чем больше число, тем реже оно появляется.
Распределение Вейбулла
Используется: Надёжность оборудования Анализ отказов Инженерные расчёты
import random
# Распределение Вейбулла
w = random.weibullvariate(1.5, 1.0)
print(w)
# random.weibullvariate(alpha, beta) — функция, которая возвращает случайное число по распределению Вейбулла.
# alpha — форма (shape). Определяет, как «круто» распределение растёт или падает.
# beta — масштаб (scale). Определяет, примерно какие числа будут чаще встречаться.
# Суть распределения Вейбулла:
# Используется для моделирования времени до поломки, надёжности и других процессов, где что-то может «выжить» некоторое время.
# Например, лампочки: большинство сгорит примерно через beta часов, но некоторые раньше, некоторые позже.
re
readline
reprlib
resource
rlcompleter
runpy
sched
secrets
secrets — это стандартная библиотека Python, предназначенная для генерации криптографически стойких случайных данных, таких как пароли, токены и секретные ключи. Он более безопасен, чем модуль random.
secrets:
Использует системный источник энтропии, предоставляемый операционной системой (например, /dev/urandom на Linux или CryptGenRandom на Windows). Генерация случайных чисел почти невозможна для предсказания. Подходит для паролей, токенов, ключей API, одноразовых кодов.
Наглядный пример разницы между random и secrets:
import random
import secrets
# 1. Случайность с random
random.seed(42) # фиксируем seed для воспроизводимости
pwd1 = ''.join(random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for _ in range(8))
pwd2 = ''.join(random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for _ in range(8))
print("random:", pwd1, pwd2)
# Если кто-то узнает seed (42), он сможет предсказать все "случайные" пароли
# 2. Случайность с secrets
pwd3 = ''.join(secrets.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for _ in range(8))
pwd4 = ''.join(secrets.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for _ in range(8))
print("secrets:", pwd3, pwd4)
# Никто не сможет предсказать эти пароли, даже зная предыдущие
# Вызов 1
# random: HBRPOIG8 F1CBFNO6
# secrets: 7HVV96ZK Z5IS62JO
# Вызов 2
# random: HBRPOIG8 F1CBFNO6
# secrets: L58C2L5J 088LZQOT
# Вызов 3
# random: HBRPOIG8 F1CBFNO6
# secrets: V0YSP6IT 337DXNXZ
random.seed(42) - задаёт начальное состояние генератора. После этого все вызовы random будут выдавать одинаковую последовательность чисел на любом компьютере с тем же seed. То есть, если кто-то узнает, что seed = 42, он может точно предсказать все будущие «случайные» числа. Пример вывода (будет всегда одинаковым при seed=42): 81 14 3 94 35
Если заменить seed на другой или не задавать его, последовательность будет другой. В отличие от этого, secrets не использует seed и берёт случайность из системного источника, поэтому предсказать значения невозможно.
import secrets
import string
# 1. secrets.choice(sequence)
letters = string.ascii_letters # Берём все латинские буквы (a-zA-Z)
ch = secrets.choice(letters) # Выбираем случайный символ из letters
print(ch) # Выводим выбранный символ
# 2. secrets.randbelow(n)
num = secrets.randbelow(10) # Случайное целое число от 0 до 9 (не включая 10)
print(num) # Выводим число
# 3. secrets.randbits(k)
bits = secrets.randbits(8) # Случайное число из 8 бит (0..255). 0 - 00000000 255 - 11111111
print(bits) # Выводим число
# 4. secrets.token_bytes([nbytes])
tb = secrets.token_bytes(4) # Генерируем 4 случайных байта. bytes — это последовательность байт (каждый байт = 8 бит).
print(tb) # Выводим байты (например: b'\x9f\x12\xab\x00')
# 5. secrets.token_hex([nbytes])
th = secrets.token_hex(4) # Генерируем 4 случайных байта и конвертируем в hex
print(th) # Выводим hex-строку (8 символов, т.к. 1 байт = 2 hex)
# 6. secrets.token_urlsafe([nbytes])
tu = secrets.token_urlsafe(4) # Генерируем 4 случайных байта и делаем безопасную для URL строку
print(tu) # Выводим строку (например: 'q3R0aA')
# Генерирует 30 символов, переводит в строку
all_chars = string.ascii_letters + string.digits + string.punctuation
# string.ascii_letters – все латинские буквы (верхний и нижний регистр):abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
# string.digits – все цифры: 0123456789
# string.punctuation – все знаки пунктуации: !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`
print( ''.join(secrets.choice(all_chars) for _ in range(30)))
# Создаётся генератор на 30 итераций → на каждой итерации выбирается случайный символ
# из all_chars с помощью secrets.choice → все 30 символов объединяются в строку через ''.join
select
selectors
shelve
shlex
shutil
signal
site
smtplib
socket
socket — низкоуровневый модуль
Сокет (socket) - конечная точка соединения: «IP + порт».
Использовать socket нужно, когда: хочешь понять, как работают сети на низком уровне; нужно создать свой протокол; пишешь игры (UDP); создаёшь чат, стриминг, перенос файлов (TCP); работаешь с IoT, микроконтроллерами.
Не использовать socket напрямую если нужно: веб-приложение → Flask / Django / FastAPI запросы к API → requests / httpx WebSocket → websockets / asyncio готовый сервер → http.server
Протаколы: TCP - Надёжный, гарантированная доставка, поток байтов (как телеграм в WhatsApp). UDP - Быстрый, без гарантий (как бросать записки через окно).
socket — это базовый модуль Python для работы с сетевыми соединениями.
Он позволяет: создавать сети клиент–сервер, отправлять и принимать данные, работать с TCP, UDP, использовать IPv4 / IPv6, строить свои протоколы поверх TCP/UDP.
Как работать с модулем socket (основные шаги) Клиент (TCP): Создать сокет Подключиться к серверу Отправить данные Получить ответ Закрыть сокет
# Простой клиент TCP
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # создание экземпляра класса сокет
# AF_INET — IPv4
# SOCK_STREAM — TCP
client.connect(("localhost", 5000)) # Подключение к серверу
client.send(b"Hi server!") # Отправляем bytes
response = client.recv(1024) # Получаем ответ
print("Server:", response.decode())
client.close()
Сервер (TCP): Создать сокет Привязать к IP/порту Перевести в режим ожидания Принять клиента Получать/отправлять данные Закрыть клиента
# Простой сервер TCP (пример)
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# AF_INET — IPv4
# SOCK_STREAM — TCP
server.bind(("localhost", 5000)) # Привязываем IP + порт (резервирование порта)
server.listen() # Начинаем слушать порт
print("Server started...")
conn, addr = server.accept() # Ждём подключения
print("Connected:", addr)
data = conn.recv(1024) # Получаем 1024 байта (ждем сообщения с сети)
print("Client:", data.decode())
conn.send(b"Hello from server") # Отправляем ответ
conn.close() # Закрыть соединение
UDP пример (быстрый, без соединения)
# UDP сервер
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("localhost", 5001))
while True:
data, addr = sock.recvfrom(1024)
print("Received:", data, "from", addr)
sock.sendto(b"pong", addr)
# UDP клиент
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(b"ping", ("localhost", 5001))
data, _ = sock.recvfrom(1024)
print(data)
Пример «Чат»:
Сервер
Запуск сервера python server.py
import socket
# Подключаем модуль socket: предоставляет низкоуровневые примитивы для сетевого ввода-вывода (создание сокетов, привязка к IP/порту, прослушка и т.д.). Модуль реализует API ОС для работы с сетью.
import threading
# Подключаем модуль threading: позволяет запускать отдельные потоки исполнения внутри одного процесса — используется, чтобы обслуживать каждого клиента параллельно, не блокируя основной цикл приёмов.
clients = []
# Создаём пустой список clients: в него будут храниться объекты сокетов подключённых клиентов. Используется для рассылки сообщений всем клиентам и для управления активными соединениями.
def handle_client(conn, addr):
# Определяем функцию handle_client, принимающую два аргумента: conn — объект сокета, представляющий соединение с клиентом; addr — кортеж (IP, порт) клиента. Эта функция будет выполняться в отдельном потоке для каждого клиента.
print(f"[+] Клиент подключён: {addr}")
# Печатаем в консоль информацию о подключении: адрес клиента. Это полезно для логирования и отладки.
while True:
# Запускаем бесконечный цикл обработки сообщений от данного клиента. Цикл будет прерываться только при явном выходе (ошибка, закрытие соединения или пустой приём).
try:
msg = conn.recv(1024)
# Вызываем метод recv на объекте сокета conn: блокирующий вызов, который ждёт входящих данных от клиента и читает до 1024 байт. Возвращаемый объект — байты (bytes). Если клиент корректно закрыл соединение, recv вернёт b''.
if not msg:
# Проверяем: если msg пустой (b''), это означает, что клиент закрыл соединение со своей стороны (EOF).
break
# Если клиент отключился, выходим из цикла обработки этого клиента, чтобы дальше корректно закрыть сокет и убрать его из списка.
except Exception as e:
# Ловим исключения при чтении (например, соединение сброшено, тайм-аут или другая сетевая ошибка).
# Здесь мы явно перехватываем любые исключения, чтобы не падал поток; можно логировать e при необходимости.
break
# При ошибке читаемого/сетевого характера также выходим из цикла — завершаем обслуживание данного клиента.
broadcast(msg, conn)
# Если получили сообщение (msg не пустой), вызываем функцию broadcast, передавая сообщение и сокет отправителя. broadcast разошлёт полученные байты всем остальным подключённым клиентам.
conn.close()
# После выхода из цикла закрываем сокет клиента: освобождаем системный ресурс и уведомляем ОС, что соединение закончено.
clients.remove(conn)
# Удаляем объект сокета клиента из списка clients — больше не будем рассылать этому сокету сообщения и не будем пытаться с ним работать.
print(f"[-] Клиент отключён: {addr}")
# Печатаем в лог информацию об отключении клиента — полезно для мониторинга и отладки.
def broadcast(message, sender):
# Определяем функцию broadcast, которая принимает message (байты) и sender — сокет отправителя. Её цель: отправить message всем подключённым клиентам, кроме отправителя.
for client in clients:
# Проходим по списку всех активных клиентских сокетов clients.
if client != sender:
# Пропускаем сокет отправителя, чтобы не отсылать сообщение обратно тому, кто его отправил (если нужно — можно убрать эту проверку).
try:
client.send(message)
# Вызываем send на каждом клиентском сокете: отправляем те же байты message. send может отправить все байты или часть их; здесь используем простую модель (для небольших сообщений обычно отправляется полностью).
except Exception:
# Если отправка не удалась (клиент разорвал соединение, сетевые ошибки), перехватываем исключение.
# В реальном приложении здесь желательно корректно обработать ошибку: закрыть сокет и удалить клиента из списка.
pass
# Для простоты пропускаем ошибку; в production это нужно фиксировать.
def main():
# Определяем главную функцию main, которая запускает сервер, принимает подключения и создаёт потоки для каждого клиента.
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Создаём новый сокет: AF_INET — адресная семья IPv4; SOCK_STREAM — потоковый сокет (TCP). Это объект низкоуровневого сокета ОС.
server.bind(("localhost", 5000))
# Привязываем (bind) сокет к локальному IP и порту: "localhost" обычно резолвится в 127.0.0.1; порт 5000 — порт, на котором сервер будет принимать соединения. bind сообщает ОС, что этот процесс будет слушать указанный адрес/порт.
server.listen()
# Переводим сокет в режим прослушивания входящих подключений. listen сообщает ОС, что сокет готов принимать подключающихся клиентов; приём очереди подключений по умолчанию (обычно system backlog).
print("[*] Сервер запущен на порту 5000...")
# Выводим в консоль сообщение о старте сервера — чтобы пользователь видел, что сервер запущен и готов принимать соединения.
while True:
# Главный цикл сервера — непрерывно ждём и принимаем новые подключения.
conn, addr = server.accept()
# Метод accept блокирует выполнение до появления нового подключения. При подключении он возвращает кортеж: conn — новый сокет для общения с конкретным клиентом; addr — адрес клиента (IP, порт). Каждый клиент получает свой conn.
clients.append(conn)
# Добавляем новый сокет клиента в список clients — чтобы иметь возможность рассылать ему сообщения друг от друга.
threading.Thread(target=handle_client, args=(conn, addr)).start()
# Создаём и запускаем новый поток исполнения: target — функция handle_client, args — её аргументы (conn, addr). .start() сразу запускает поток. Таким образом главный цикл остаётся неблокирующим и может принимать следующие подключения.
if __name__ == "__main__":
# Проверяем, что модуль запускается как основная программа (не импортируется как модуль другим скриптом). Эта конструкция предотвращает автоматический запуск main() при импорте.
main()
# Вызываем main(): стартуем сервер.
Клиент
Запуск клиента (для каждого клиента требуется новый терминал) python client.py
import socket
# Модуль для работы с сетевыми соединениями (TCP/UDP)
import threading
# Модуль для работы с потоками, чтобы выполнять несколько задач одновременно
def receive(sock):
# Функция для потока, который будет принимать сообщения от сервера
"""Поток для приёма сообщений от сервера"""
while True:
# Бесконечный цикл, чтобы постоянно слушать сервер
try:
msg = sock.recv(1024).decode()
# Получаем до 1024 байт от сервера и декодируем в строку
print(msg)
# Выводим полученное сообщение в консоль
except:
# Если возникла ошибка при получении (например, сервер закрыл соединение)
print("[!] Соединение потеряно")
# Сообщаем пользователю о потере соединения
break
# Прерываем цикл, завершая поток
def main():
# Основная функция программы
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Создаём TCP сокет с IPv4
client.connect(("localhost", 5000))
# Подключаемся к серверу на локальной машине, порт 5000
print("Подключено к чату!")
# Сообщаем, что подключение успешно установлено
# Создаём отдельный поток для функции receive, чтобы одновременно получать сообщения и писать свои
threading.Thread(target=receive, args=(client,), daemon=True).start()
# target=receive — функция, которая будет выполняться в потоке
# args=(client,) — передаём сокет в поток как аргумент
# daemon=True — поток автоматически завершится при закрытии основной программы
# start() — запускаем поток
while True:
# Бесконечный цикл для отправки сообщений пользователем
msg = input()
# Ждём ввода сообщения от пользователя
client.send(msg.encode())
# Кодируем сообщение в байты и отправляем серверу
if __name__ == "__main__":
# Проверка: если файл запускается напрямую, а не импортируется
main()
# Запускаем основную функцию программы
Основные методы сокета: bind((host, port)) Привязывает сокет к адресу (сервер) listen(backlog) Начинает слушать входящие соединения (сервер) accept() Принимает новое соединение (сервер) connect((host, port)) Подключается к серверу (клиент) send(data) Отправляет байты recv(bufsize) Получает до bufsize байт close() Закрывает сокет settimeout(seconds) Устанавливает таймаут на операции с сокетом
всегда закрывай сокеты после использования (close()), иначе соединение может зависнуть.
Таймауты и блокирующий режим: По умолчанию сокеты блокирующие, т.е. программа ждёт, пока операция завершится. sock.settimeout(5) — задаёт таймаут 5 секунд. Если данные не придут — будет исключение socket.timeout. Это важно, чтобы программа не «зависала» на recv() при обрыве соединения.
Работа с адресами: gethostbyname(„example.com“) — переводит доменное имя в IP. gethostname() — имя локальной машины. Можно проверять адреса перед подключением.
Опции сокета (socket options): setsockopt(level, optname, value) — управляет поведением сокета. Примеры: SO_REUSEADDR (разрешает повторное использование порта), TCP_NODELAY (отключает Nagle для TCP). На больших проектах важно для настройки производительности.
Работа с мультикастом, неблокирующим вводом, select/poll Для более сложных сетевых приложений используют: select.select() — проверяет готовность сокетов к чтению/записи socket.setblocking(False) — делает сокет неблокирующим Мультикаст/броадкаст через UDP Эти вещи важны, если чат или сервер должны обслуживать десятки или сотни клиентов.
Ошибки и исключения socket.error — базовое исключение для всех сетевых ошибок. ConnectionResetError, TimeoutError — для обработки обрывов и таймаутов. Важно: всегда оборачивать recv() и send() в try/except, чтобы программа не падала.
Создание локального UNIX-сокет через файл. Межпроцессное взаимодействие внутри одной операционной системы.
# Сервер
import os
import socket
unix_sock_name = 'unix.sock'
# Имя файла сокета в файловой системе (UNIX-сокет — это файл)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
# socket.AF_UNIX — указывает, что используется локальный UNIX-сокет (не через IP-сеть)
# socket.SOCK_DGRAM — тип сокета UDP (без установления соединения, пакетная передача)
# В итоге создаётся локальный датаграммный сокет, работающий через файл
if os.path.exists(unix_sock_name):
# Проверяем, существует ли уже файл сокета
os.remove(unix_sock_name)
# Если существует — удаляем его, иначе bind вызовет ошибку
sock.bind(unix_sock_name)
# Привязываем сокет к файлу unix.sock в файловой системе
# После этого другие процессы смогут отправлять данные в этот сокет через этот файл
while True:
# Бесконечный цикл для постоянного ожидания сообщений
try:
result = sock.recv(1024)
# Ожидаем входящее сообщение
# recv(1024) — принимает до 1024 байт данных
# Программа будет "висеть" на этой строке, пока не придёт сообщение
except KeyboardInterrupt:
# Срабатывает, если пользователь нажал Ctrl + C
sock.close()
# Закрываем сокет, освобождаем системный ресурс
break
else:
print('Message', result.decode('utf-8'))
# result.decode('utf-8') — преобразуем полученные байты в строку
# print — выводим сообщение в консоль
# Клиент
import socket
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.sendto(b'Test Message', 'unix.sock')
socketserver
sqlite3
sre_compile
sre_constants
sre_parse
ssl
stat
statistics
string
string — — это вспомогательный модуль для работы со строками, в котором собраны готовые наборы символов и константы. Он не заменяет методы строк, а дополняет их.
Когда тебе требуется: Готовый алфавит Все цифры Все знаки пунктуации Все печатаемые символы Генерация случайных строк Фильтрация символов
Где реально применяется: Генерации логинов и паролей Валидации вводимых данных Фильтрации текста Парсинге файлов Криптографии (в связке с secrets)
import string
print(string.ascii_letters)
# хранит все маленькие и большие буквы английского языка таблицы ASCII
print(string.ascii_lowercase)
# эта константа хранит в себе маленькие буквы английского языка, с той же таблицы
print(string.ascii_uppercase)
# аналогично предыдущему методу, но хранит большие буквы английского языка, т.е. в верхнем регистре
print(string.digits)
# хранит цифры от 0 до 9
print(string.hexdigits)
#хранит '0123456789abcdefABCDEF', т.е цифры от 0 до 9, и маленькие и большие буквы английского языка от «a» до «F»
print(string.octdigits)
#хранит цифры от 0 до 7, т.е. строка ‘01234567’
print(string.punctuation)
# хранит знаки пунктуации и специальные символы, т.е. строку «!»#$%&'()*+,-./:<=>?@[\]^_{|}~»
print(string.printable)
# хранит символы ASCII, которые считаются печатными. Это сочетание digits, ascii_letters, punctuation, и whitespace
print(string.whitespace)
#хранит набор символов, которые считаются пробельными символами, а именно: табуляция, перевод строки, возврат, подача формы и вертикальная табуляция
# Пример разделение
letters_joined_by_commas = ",".join(string.ascii_letters)
print(string.ascii_letters)
#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
print(letters_joined_by_commas)
# a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
# Пример Проверка: только ли цифры в строке
import string
text = "12345"
if all(ch in string.digits for ch in text):
print("Только цифры")
# Пример Генерация случайного пароля
import string
import random
symbols = string.ascii_letters + string.digits
password = "".join(random.choice(symbols) for _ in range(10))
print(password)
# Пример Очистка строки от знаков препинания
import string
text = "Привет, мир!!!"
clean = "".join(ch for ch in text if ch not in string.punctuation)
print(clean)
stringprep
struct
subprocess
symtable
sysconfig
syslog
tabnanny
tarfile
tempfile
termios
textwrap
this
threading
timeit
tkinter
token
tokenize
tomllib
trace
traceback
tracemalloc
tty
turtle
turtledemo
types
typing
unicodedata
unittest
urllib
uuid
venv
warnings
wave
weakref
webbrowser
winsound
wsgiref
xml
xmlrpc
zipapp
ZipFile
Zip
from zipfile import ZipFile
from pathlib import Path
Path('my-files').mkdir()
with open('my-files/first.txt', 'w', encoding='utf-8') as my_file:
my_file.write('Это первый файл')
with open('my-files/second.txt', 'w', encoding='utf-8') as my_file:
my_file.write('Это второй файл')
with ZipFile('my-files/my-files.zip', mode='w') as my_zip_file:
# print(my_zip_file) # <zipfile.ZipFile filename='my-files.zip' mode='w'>
for file in Path('my-files').iterdir(): # iterdir() - метод итерация по директории
print(file) # my-files\first.txt # my-files\second.txt
my_zip_file.write(file)
with ZipFile('my-files/my-files.zip') as my_zip_file:
my_zip_file.extractall('my-files-unzipped') # распаковка архива в новую папку my-files-unzipped
print(my_zip_file.infolist()) # информация о каждом файле
zipimport
zoneinfo
Встроенные модули (built-in)
Они встроены в интерпретатор на этапе компиляции. Реализованы на C (или другом низкоуровневом языке). Не имеют .py файлов, работают сразу после запуска Python. Примеры: sys, time, math, _thread, marshal. Эти модули показываются в sys.builtin_module_names.
# Просмотр всех встроенных модулей
import sys
print(sorted(sys.builtin_module_names))
_модули
_abc
_ast“
_bisect
_blake2
_codecs
_codecs_cn
_codecs_hk
_codecs_iso2022
_codecs_jp
_codecs_kr
_codecs_tw
_collections
_contextvars
_csv
_datetime
_functools
_heapq
_hmac
_imp
_interpchannels
_interpqueues
_interpreters
_io
_json
_locale
_lsprof
_md5
_multibytecodec
_opcode
_operator
_pickle
_random
_sha1
_sha2
_sha3
_signal
_sre
_stat
_statistics
_string
_struct
_suggestions
_symtable
_sysconfig
_thread
_tokenize
_tracemalloc
_types
_typing
_warnings
_weakref
_winapi
array
atexit
binascii
builtins
cmath
errno
faulthandler
gc
itertools
marshal
math
math — это стандартный модуль Python, который предоставляет математические функции, такие как тригонометрия, логарифмы, факториалы и округление.
mmap
msvcrt
nt
sys
time
winreg
xxsubtype
zlib
Файлы байткода .pyc
Библиотеки
Фреймворки
Практика
Генераторы Память Диапазоны Биты и байты