Сегодня покажу вам удобный способ следить за производительностью Python-кода прямо в терминале — с помощью
🔍 Что такое
🛠 Установка:
Или, если хочется поставить бинарник напрямую:
🚀 Примеры использования:
1. Снять снимок с работающего процесса:
Альтернатива
2. Записать flamegraph:
Откроется красивая SVG-шечка, где видно, куда утекает время выполнения.
3. Запустить скрипт с профилированием:
🧠 Зачем это нужно?
- Падает производительность? Посмотри, какие функции грузят процессор.
- Программа зависла? Снимок покажет, где именно.
- Хотите оптимизировать горячие участки? Flamegraph быстро выведет подозреваемых.
🔥 Совет от меня:
👉@BookPython
py-spy
.🔍 Что такое
py-spy
?py-spy
— это sampling-профайлер для Python, который не требует модификации кода и может подключаться к уже работающим процессам. Он написан на Rust, работает очень быстро и почти не влияет на производительность.🛠 Установка:
pip install py-spy
Или, если хочется поставить бинарник напрямую:
curl -sSL https://install.python-poetry.org | python3 -
🚀 Примеры использования:
1. Снять снимок с работающего процесса:
py-spy top --pid 12345
Альтернатива
htop
, но показывает, какие функции Python жрут CPU.2. Записать flamegraph:
py-spy record -o profile.svg --pid 12345
Откроется красивая SVG-шечка, где видно, куда утекает время выполнения.
3. Запустить скрипт с профилированием:
py-spy top -- python my_script.py
🧠 Зачем это нужно?
- Падает производительность? Посмотри, какие функции грузят процессор.
- Программа зависла? Снимок покажет, где именно.
- Хотите оптимизировать горячие участки? Flamegraph быстро выведет подозреваемых.
🔥 Совет от меня:
py-spy
умеет работать с контейнерами и виртуальными окружениями, просто указывайте --pid
правильного процесса. Идеален для DevOps'а и продакшн-серверов.👉@BookPython
В Python вы можете легко изменять все стандартные переменные, доступные в глобальном пространстве имён:
Это может быть полезно, если ваш модуль определяет какие-то функции с теми же именами, что и встроенные. Такое также случается при метапрограммировании, когда вы принимаете произвольную строку в качестве идентификатора.
Тем не менее, даже если вы затеняете (shadow) некоторые встроенные имена, вам всё ещё может понадобиться доступ к оригинальным объектам, на которые они изначально ссылались. Для этого существует модуль
Также переменная
👉@BookPython
>>> print = 42
>>> print(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
Это может быть полезно, если ваш модуль определяет какие-то функции с теми же именами, что и встроенные. Такое также случается при метапрограммировании, когда вы принимаете произвольную строку в качестве идентификатора.
Тем не менее, даже если вы затеняете (shadow) некоторые встроенные имена, вам всё ещё может понадобиться доступ к оригинальным объектам, на которые они изначально ссылались. Для этого существует модуль
builtins
:
>>> import builtins
>>> print = 42
>>> builtins.print(1)
1
Также переменная
__builtins__
доступна в большинстве модулей. Однако здесь есть нюанс. Во-первых, это деталь реализации CPython, и обычно её вообще не стоит использовать. Во-вторых, __builtins__
может ссылаться либо на builtins
, либо на builtins.__dict__
, в зависимости от того, как именно был загружен текущий модуль.👉@BookPython
Подборка Telegram каналов для программистов
https://t.me/bash_srv Bash Советы
https://t.me/win_sysadmin Системный Администратор Windows
https://t.me/lifeproger Жизнь программиста. Авторский канал.
https://t.me/devopslib Библиотека девопса | DevOps, SRE, Sysadmin
https://t.me/rabota1C_rus Вакансии для программистов 1С
Системное администрирование 📌
https://t.me/sysadmin_girl Девочка Сисадмин
https://t.me/srv_admin_linux Админские угодья
https://t.me/linux_srv Типичный Сисадмин
https://t.me/linux_odmin Linux: Системный администратор
https://t.me/devops_star DevOps Star (Звезда Девопса)
https://t.me/i_linux Системный администратор
https://t.me/linuxchmod Linux
https://t.me/sys_adminos Системный Администратор
https://t.me/tipsysdmin Типичный Сисадмин (фото железа, было/стало)
https://t.me/sysadminof Книги для админов, полезные материалы
https://t.me/i_odmin Все для системного администратора
https://t.me/i_odmin_book Библиотека Системного Администратора
https://t.me/i_odmin_chat Чат системных администраторов
https://t.me/i_DevOps DevOps: Пишем о Docker, Kubernetes и др.
https://t.me/sysadminoff Новости Линукс Linux
1C разработка 📌
https://t.me/odin1C_rus Cтатьи, курсы, советы, шаблоны кода 1С
https://t.me/DevLab1C 1С:Предприятие 8
Программирование C++📌
https://t.me/cpp_lib Библиотека C/C++ разработчика
https://t.me/cpp_knigi Книги для программистов C/C++
https://t.me/cpp_geek Учим C/C++ на примерах
Программирование Python 📌
https://t.me/pythonofff Python академия. Учи Python быстро и легко🐍
https://t.me/BookPython Библиотека Python разработчика
https://t.me/python_real Python подборки на русском и английском
https://t.me/python_360 Книги по Python Rus
Java разработка 📌
https://t.me/BookJava Библиотека Java разработчика
https://t.me/java_360 Книги по Java Rus
https://t.me/java_geek Учим Java на примерах
GitHub Сообщество 📌
https://t.me/Githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://t.me/database_info Все про базы данных
Мобильная разработка: iOS, Android 📌
https://t.me/developer_mobila Мобильная разработка
https://t.me/kotlin_lib Подборки полезного материала по Kotlin
Фронтенд разработка 📌
https://t.me/frontend_1 Подборки для frontend разработчиков
https://t.me/frontend_sovet Frontend советы, примеры и практика!
https://t.me/React_lib Подборки по React js и все что с ним связано
Разработка игр 📌
https://t.me/game_devv Все о разработке игр
Библиотеки 📌
https://t.me/book_for_dev Книги для программистов Rus
https://t.me/programmist_of Книги по программированию
https://t.me/proglb Библиотека программиста
https://t.me/bfbook Книги для программистов
https://t.me/books_reserv Книги для программистов
БигДата, машинное обучение 📌
https://t.me/bigdata_1 Data Science, Big Data, Machine Learning, Deep Learning
Программирование 📌
https://t.me/bookflow Лекции, видеоуроки, доклады с IT конференций
https://t.me/coddy_academy Полезные советы по программированию
https://t.me/rust_lib Полезный контент по программированию на Rust
https://t.me/golang_lib Библиотека Go (Golang) разработчика
https://t.me/itmozg Программисты, дизайнеры, новости из мира IT
https://t.me/php_lib Библиотека PHP программиста 👨🏼💻👩💻
https://t.me/nodejs_lib Подборки по Node js и все что с ним связано
https://t.me/ruby_lib Библиотека Ruby программиста
QA, тестирование 📌
https://t.me/testlab_qa Библиотека тестировщика
Шутки программистов 📌
https://t.me/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://t.me/thehaking Канал о кибербезопасности
https://t.me/xakep_2 Хакер Free
Книги, статьи для дизайнеров 📌
https://t.me/ux_web Статьи, книги для дизайнеров
Математика 📌
https://t.me/Pomatematike Канал по математике
https://t.me/phis_mat Обучающие видео, книги по Физике и Математике
Excel лайфхак📌
https://t.me/Excel_lifehack
https://t.me/tikon_1 Новости высоких технологий, науки и техники💡
https://t.me/mir_teh Мир технологий (Technology World)
Вакансии 📌
https://t.me/sysadmin_rabota Системный Администратор
https://t.me/progjob Вакансии в IT
https://t.me/bash_srv Bash Советы
https://t.me/win_sysadmin Системный Администратор Windows
https://t.me/lifeproger Жизнь программиста. Авторский канал.
https://t.me/devopslib Библиотека девопса | DevOps, SRE, Sysadmin
https://t.me/rabota1C_rus Вакансии для программистов 1С
Системное администрирование 📌
https://t.me/sysadmin_girl Девочка Сисадмин
https://t.me/srv_admin_linux Админские угодья
https://t.me/linux_srv Типичный Сисадмин
https://t.me/linux_odmin Linux: Системный администратор
https://t.me/devops_star DevOps Star (Звезда Девопса)
https://t.me/i_linux Системный администратор
https://t.me/linuxchmod Linux
https://t.me/sys_adminos Системный Администратор
https://t.me/tipsysdmin Типичный Сисадмин (фото железа, было/стало)
https://t.me/sysadminof Книги для админов, полезные материалы
https://t.me/i_odmin Все для системного администратора
https://t.me/i_odmin_book Библиотека Системного Администратора
https://t.me/i_odmin_chat Чат системных администраторов
https://t.me/i_DevOps DevOps: Пишем о Docker, Kubernetes и др.
https://t.me/sysadminoff Новости Линукс Linux
1C разработка 📌
https://t.me/odin1C_rus Cтатьи, курсы, советы, шаблоны кода 1С
https://t.me/DevLab1C 1С:Предприятие 8
Программирование C++📌
https://t.me/cpp_lib Библиотека C/C++ разработчика
https://t.me/cpp_knigi Книги для программистов C/C++
https://t.me/cpp_geek Учим C/C++ на примерах
Программирование Python 📌
https://t.me/pythonofff Python академия. Учи Python быстро и легко🐍
https://t.me/BookPython Библиотека Python разработчика
https://t.me/python_real Python подборки на русском и английском
https://t.me/python_360 Книги по Python Rus
Java разработка 📌
https://t.me/BookJava Библиотека Java разработчика
https://t.me/java_360 Книги по Java Rus
https://t.me/java_geek Учим Java на примерах
GitHub Сообщество 📌
https://t.me/Githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://t.me/database_info Все про базы данных
Мобильная разработка: iOS, Android 📌
https://t.me/developer_mobila Мобильная разработка
https://t.me/kotlin_lib Подборки полезного материала по Kotlin
Фронтенд разработка 📌
https://t.me/frontend_1 Подборки для frontend разработчиков
https://t.me/frontend_sovet Frontend советы, примеры и практика!
https://t.me/React_lib Подборки по React js и все что с ним связано
Разработка игр 📌
https://t.me/game_devv Все о разработке игр
Библиотеки 📌
https://t.me/book_for_dev Книги для программистов Rus
https://t.me/programmist_of Книги по программированию
https://t.me/proglb Библиотека программиста
https://t.me/bfbook Книги для программистов
https://t.me/books_reserv Книги для программистов
БигДата, машинное обучение 📌
https://t.me/bigdata_1 Data Science, Big Data, Machine Learning, Deep Learning
Программирование 📌
https://t.me/bookflow Лекции, видеоуроки, доклады с IT конференций
https://t.me/coddy_academy Полезные советы по программированию
https://t.me/rust_lib Полезный контент по программированию на Rust
https://t.me/golang_lib Библиотека Go (Golang) разработчика
https://t.me/itmozg Программисты, дизайнеры, новости из мира IT
https://t.me/php_lib Библиотека PHP программиста 👨🏼💻👩💻
https://t.me/nodejs_lib Подборки по Node js и все что с ним связано
https://t.me/ruby_lib Библиотека Ruby программиста
QA, тестирование 📌
https://t.me/testlab_qa Библиотека тестировщика
Шутки программистов 📌
https://t.me/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://t.me/thehaking Канал о кибербезопасности
https://t.me/xakep_2 Хакер Free
Книги, статьи для дизайнеров 📌
https://t.me/ux_web Статьи, книги для дизайнеров
Математика 📌
https://t.me/Pomatematike Канал по математике
https://t.me/phis_mat Обучающие видео, книги по Физике и Математике
Excel лайфхак📌
https://t.me/Excel_lifehack
https://t.me/tikon_1 Новости высоких технологий, науки и техники💡
https://t.me/mir_teh Мир технологий (Technology World)
Вакансии 📌
https://t.me/sysadmin_rabota Системный Администратор
https://t.me/progjob Вакансии в IT
Telegram
Bash Советы
🚀 Секреты и советы по Bash
🔹 Полезные трюки, хитрые однострочники и лайфхаки для работы в терминале.
🔹 Автоматизация, скрипты и оптимизация работы в Linux.
🔹 Стать мастером Bash легко – просто подпишись!
💻 Прокачивай терминал вместе с нами! 👇
🔹 Полезные трюки, хитрые однострочники и лайфхаки для работы в терминале.
🔹 Автоматизация, скрипты и оптимизация работы в Linux.
🔹 Стать мастером Bash легко – просто подпишись!
💻 Прокачивай терминал вместе с нами! 👇
Обработка исключений в асинхронных программах может быть непростой задачей.
В
Если исключение выброшено, но задача (
Когда вы используете
Вы можете использовать
👉@BookPython
В
asyncio
, если корутина выбрасывает исключение, оно передаётся в тот код, который ожидает соответствующий future
. Если await
вызывается в нескольких местах, то каждое из них получит это исключение (так как оно сохраняется внутри объекта исключения). Следующий код напечатает сообщение об ошибке пять раз:
import asyncio
async def error():
await asyncio.sleep(1)
raise ValueError()
async def waiter(task):
try:
await task
except ValueError:
print('error')
else:
print('OK')
async def main():
task = asyncio.get_event_loop().create_task(error())
for _ in range(5):
asyncio.get_event_loop().create_task(waiter(task))
await asyncio.sleep(2)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Если исключение выброшено, но задача (
task
) ни разу не была ожидаема (awaited
), исключение будет потеряно. В таком случае при уничтожении задачи вы получите предупреждение: “Task exception was never retrieved”.Когда вы используете
await asyncio.gather(tasks)
и одна из задач выбрасывает исключение, оно передаётся наружу. Однако если несколько задач выбросят исключения, вы получите только первое, остальные будут проигнорированы:
import asyncio
async def error(i):
await asyncio.sleep(1)
raise ValueError(i)
async def main():
try:
await asyncio.gather(
error(1),
error(2),
error(3),
)
except ValueError as e:
print(e)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Вы можете использовать
gather
с параметром return_exceptions=True
, чтобы получать исключения как обычные значения. Следующий код напечатает: [42, ValueError(2,), ValueError(3,)]
import asyncio
async def error(i):
await asyncio.sleep(1)
if i > 1:
raise ValueError(i)
return 42
async def main():
results = await asyncio.gather(
error(1),
error(2),
error(3),
return_exceptions=True,
)
print(results)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
👉@BookPython
В Python очень короткий список встроенных констант. Одна из них —
Библиотека NumPy поддерживает
PEP 484 придаёт
Наконец,
👉@BookPython
Ellipsis
, которую также можно записать как ...
. Эта константа не имеет особого значения для интерпретатора, но используется в местах, где такой синтаксис выглядит уместно.Библиотека NumPy поддерживает
Ellipsis
в качестве аргумента __getitem__
, например: x[...]
возвращает все элементы массива x
.PEP 484 придаёт
Ellipsis
дополнительное значение: Callable[..., type]
— это способ определить тип вызываемых объектов без указания типов аргументов.Наконец,
...
можно использовать, чтобы обозначить, что функция ещё не реализована. Это абсолютно валидный код на Python:
def x():
...
👉@BookPython
Когда вы пишете
В этом примере
Если всё же нужно напрямую изменить значение
👉@BookPython
obj.x = y
, нельзя быть уверенным, что атрибут x
объекта obj
действительно станет равным y
. Протокол дескрипторов в Python позволяет определить, как будет обрабатываться присваивание атрибутов.
class Descriptor:
def __set__(self, obj, value):
obj.test = value
class A:
x = Descriptor()
В этом примере
x
напрямую никогда не присваивается значение — вместо этого устанавливается атрибут test
:
>>> a = A()
>>> a.x = 42
>>> a.test
42
>>> a.x
<__main__.Descriptor at 0x7ff7baef51d0>
Если всё же нужно напрямую изменить значение
x
, например, в тестах или при использовании метапрограммирования, придётся обращаться напрямую к __dict__
:
>>> a.__dict__['x'] = 42
>>> a.x
42
👉@BookPython
itertools.tee()
создаёт несколько итераторов из одного. Это может быть полезно, если несколько потребителей должны читать один и тот же поток данных.
In : a, b, c = tee(iter(input, ''), 3)
In : next(a), next(c)
FIRST
Out: ('FIRST', 'FIRST')
In : next(a), next(b)
SECOND
Out: ('SECOND', 'FIRST')
In : next(a), next(b), next(c)
THIRD
Out: ('THIRD', 'SECOND', 'SECOND')
Данные, которые ещё не были использованы всеми итераторами, сохраняются в памяти. Если какие-то из созданных итераторов ещё не начали чтение к моменту, когда другие уже завершили, это означает, что все сгенерированные элементы будут сохранены в памяти для последующего использования. В таком случае проще и эффективнее использовать
list(iter(input, ''))
вместо tee
.👉@BookPython
Чтобы сохранить любую информацию в памяти или на устройстве хранения, её необходимо представить в виде байтов. Python, как правило, предоставляет уровень абстракции, при котором вы оперируете непосредственно данными, а не их байтовым представлением.
Тем не менее, когда вы, скажем, записываете строку в файл, вы работаете с физической структурой данных. Чтобы поместить символы в файл, их нужно преобразовать в байты — это называется кодированием. Когда вы получаете байты из файла, скорее всего, вы захотите превратить их в осмысленные символы — это называется декодированием.
Существует сотни методов кодирования. Самый популярный — вероятно, Unicode, но он сам по себе не может преобразовывать данные в байты. В смысле байтового представления Unicode вообще не является кодировкой. Unicode определяет соответствие между символами и их числовыми кодами. Например, 🐍 имеет код 128013.
Но чтобы записать числа в файл, нужна настоящая кодировка. Unicode обычно используется вместе с utf-8, которая (в большинстве случаев) является стандартной в Python. При чтении из файла Python автоматически декодирует utf-8. Вы можете выбрать любую другую кодировку с помощью параметра
👉@BookPython
Тем не менее, когда вы, скажем, записываете строку в файл, вы работаете с физической структурой данных. Чтобы поместить символы в файл, их нужно преобразовать в байты — это называется кодированием. Когда вы получаете байты из файла, скорее всего, вы захотите превратить их в осмысленные символы — это называется декодированием.
Существует сотни методов кодирования. Самый популярный — вероятно, Unicode, но он сам по себе не может преобразовывать данные в байты. В смысле байтового представления Unicode вообще не является кодировкой. Unicode определяет соответствие между символами и их числовыми кодами. Например, 🐍 имеет код 128013.
Но чтобы записать числа в файл, нужна настоящая кодировка. Unicode обычно используется вместе с utf-8, которая (в большинстве случаев) является стандартной в Python. При чтении из файла Python автоматически декодирует utf-8. Вы можете выбрать любую другую кодировку с помощью параметра
encoding=
функции open
, либо читать «сырые» байты, добавив b
к режиму открытия файла.👉@BookPython
Если вы создаёте новые объекты внутри метода
В этом примере
Возможный рефакторинг:
Такой подход имеет как минимум следующие преимущества:
• Упрощает внедрение зависимостей. В тестах можно использовать
• Класс может иметь столько фабричных методов, сколько нужно; подключение может создаваться не только по
• Такие фабричные методы можно сделать асинхронными; это невозможно для
👉@BookPython
__init__
, возможно, будет лучше передавать их как аргументы и использовать фабричный метод. Это позволяет разделить бизнес-логику и технические детали создания объектов.В этом примере
__init__
принимает host
и port
для создания подключения к базе данных:
class Query:
def __init__(self, host, port):
self._connection = Connection(host, port)
Возможный рефакторинг:
class Query:
def __init__(self, connection):
self._connection = connection
@classmethod
def create(cls, host, port):
return cls(Connection(host, port))
Такой подход имеет как минимум следующие преимущества:
• Упрощает внедрение зависимостей. В тестах можно использовать
Query(FakeConnection())
.• Класс может иметь столько фабричных методов, сколько нужно; подключение может создаваться не только по
host
и port
, но и путём клонирования другого подключения, чтения конфигурационного файла или объекта, использования значения по умолчанию и т.д.• Такие фабричные методы можно сделать асинхронными; это невозможно для
__init__
.👉@BookPython
Сегодня я покажу вам простой, но очень полезный приём, который часто выручает при работе с Python-скриптами — автоматическое логирование вызовов функций с помощью декоратора.
Иногда, особенно в отладке, хочется видеть, какие функции вызываются, с какими аргументами и что они возвращают. Не писать же в каждую вручную
Пример использования:
📌 Вывод:
Такой декоратор можно подключить временно на любую функцию — и сразу видеть, что происходит у вас в коде. Это особенно удобно при работе со сторонними библиотеками или когда вы разбираетесь в чужом проекте.
Кстати, с небольшими изменениями можно направить вывод не в
Пользуетесь такими декораторами? Или у вас свой лайфхак?
👉@BookPython
Иногда, особенно в отладке, хочется видеть, какие функции вызываются, с какими аргументами и что они возвращают. Не писать же в каждую вручную
print()
? Вот тут и приходит на помощь наш герой — универсальный логгер-декоратор:
import functools
def log_calls(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"[CALL] {func.__name__} args={args} kwargs={kwargs}")
result = func(*args, **kwargs)
print(f"[RETURN] {func.__name__} -> {result}")
return result
return wrapper
Пример использования:
@log_calls
def multiply(a, b):
return a * b
multiply(3, 5)
📌 Вывод:
[CALL] multiply args=(3, 5) kwargs={}
[RETURN] multiply -> 15
Такой декоратор можно подключить временно на любую функцию — и сразу видеть, что происходит у вас в коде. Это особенно удобно при работе со сторонними библиотеками или когда вы разбираетесь в чужом проекте.
Кстати, с небольшими изменениями можно направить вывод не в
print()
, а в logging
, или даже сохранять в файл — по вкусу.Пользуетесь такими декораторами? Или у вас свой лайфхак?
👉@BookPython
Одна и та же строка может быть представлена по-разному в Unicode, и стандарт это учитывает. Он определяет два типа эквивалентности: последовательности могут быть канонически эквивалентными или совместимыми.
Канонически эквивалентные последовательности выглядят одинаково, но содержат разные кодовые точки. Например, символ ö может быть представлен как LATIN SMALL LETTER O WITH DIAERESIS (U+00F6) или как комбинация из o и диакритического знака: LATIN SMALL LETTER O (U+006F) + COMBINING DIAERESIS (U+0308).
Совместимые последовательности выглядят по-разному, но могут трактоваться одинаково с точки зрения смысла, например, ff и ff.
Для каждого из этих типов эквивалентности можно нормализовать строку в Unicode, сжимая или расширяя последовательности. В Python для этого используется модуль
Результат:
👉@BookPython
Канонически эквивалентные последовательности выглядят одинаково, но содержат разные кодовые точки. Например, символ ö может быть представлен как LATIN SMALL LETTER O WITH DIAERESIS (U+00F6) или как комбинация из o и диакритического знака: LATIN SMALL LETTER O (U+006F) + COMBINING DIAERESIS (U+0308).
Совместимые последовательности выглядят по-разному, но могут трактоваться одинаково с точки зрения смысла, например, ff и ff.
Для каждого из этих типов эквивалентности можно нормализовать строку в Unicode, сжимая или расширяя последовательности. В Python для этого используется модуль
unicodedata
:
import unicodedata
modes = [
# Сжать канонически эквивалентные
'NFC',
# Расширить канонически эквивалентные
'NFD',
# Сжать совместимые
'NFKC',
# Расширить совместимые
'NFKD',
]
s = 'ff + ö'
for mode in modes:
norm = unicodedata.normalize(mode, s)
print('\t'.join([
mode,
norm,
str(len(norm.encode('utf8'))),
]))
Результат:
NFC ff + ö 8
NFD ff + ö 9
NFKC ff + ö 7
NFKD ff + ö 8
👉@BookPython
Обычно вы взаимодействуете с генератором, запрашивая данные с помощью
С помощью
Эта техника позволяет более точно управлять поведением генератора — не только передавать данные внутрь, но и, например, сообщать о проблемах со значениями, полученными через
Тем не менее, декоратор
👉@BookPython
next(gen)
. В Python 3 вы также можете отправлять значения обратно в генератор с помощью g.send(x)
. Но существует техника, которой вы, вероятно, не пользуетесь каждый день, а возможно, и вовсе не знаете: выбрасывание исключений внутри генератора.С помощью
gen.throw(e)
можно выбросить исключение в той точке, где генератор gen
приостановлен — то есть на инструкции yield
. Если генератор обрабатывает это исключение, gen.throw(e)
возвращает следующее значение, полученное через yield
(или выбрасывает StopIteration
, если генератор завершён). Если генератор не перехватывает исключение, оно пробрасывается обратно к вызывающему коду.
def gen():
try:
yield 1
except ValueError:
yield 2
g = gen()
next(g)
# Out: 1
g.throw(ValueError)
# Out: 2
g.throw(RuntimeError('TEST'))
# RuntimeError: TEST
Эта техника позволяет более точно управлять поведением генератора — не только передавать данные внутрь, но и, например, сообщать о проблемах со значениями, полученными через
yield
. Однако такие случаи бывают редко, и встретить g.throw
в дикой природе почти невозможно.Тем не менее, декоратор
@contextmanager
из модуля contextlib
использует именно такую технику, позволяя коду внутри контекста перехватывать исключения.
from contextlib import contextmanager
@contextmanager
def atomic():
print('BEGIN')
try:
yield
except Exception:
print('ROLLBACK')
else:
print('COMMIT')
with atomic():
print('ERROR')
raise RuntimeError()
BEGIN
ERROR
ROLLBACK
👉@BookPython
Стандартный механизм расширения путей в оболочке называется globbing. Шаблоны, которые вы используете для сопоставления путей, называются globs.
Python поддерживает globbing с помощью модуля
👉@BookPython
$ echo /li*
/lib /lib64
Python поддерживает globbing с помощью модуля
glob
. Однако есть важное замечание: оболочка возвращает сам шаблон, если файлы не найдены, а Python — нет:
$ echo /zz**
/zz**
$ python -c 'from glob import glob; print(glob("/zz**"))'
[]
👉@BookPython
Функция
Имя функции
Пример:
Обрати внимание: результат работы
👉@BookPython
super()
позволяет обращаться к родительскому (базовому) классу. Это может быть очень полезно в случаях, когда производный класс хочет добавить что-то к реализации метода, а не полностью переопределять его:
class BaseTestCase(TestCase):
def setUp(self):
self._db = create_db()
class UserTestCase(BaseTestCase):
def setUp(self):
super().setUp()
self._user = create_user()
Имя функции
super
не означает "отличный" или "очень хороший". В данном контексте слово super означает "выше" (как, например, в слове superintendent — заведующий). Несмотря на это, super()
не всегда ссылается на базовый класс — он может вернуть и "соседний" класс. Более точным названием была бы, возможно, функция next()
, так как возвращается следующий класс согласно цепочке разрешения методов (MRO — Method Resolution Order).Пример:
class Top:
def foo(self):
return 'top'
class Left(Top):
def foo(self):
return super().foo()
class Right(Top):
def foo(self):
return 'right'
class Bottom(Left, Right):
pass
# выводит 'right'
print(Bottom().foo())
Обрати внимание: результат работы
super()
может отличаться в зависимости от MRO вызвавшего объекта.
>>> Bottom().foo()
'right'
>>> Left().foo()
'top'
👉@BookPython
🚀 Подпишись и прокачай свои скилы: лучшие каналы для IT-специалистов 👨💻📲
Папка с каналами для DevOps, Linux - Windows СисАдминов👍
Папка с каналами для 1С программистов🧑💻
Папка с каналами для C++ программистов👩💻
Папка с каналами для Python программистов👩💻
Папка с каналами для Java программистов🖥
Папка с книгами для программистов 📚
Папка для программистов (frontend, backend, iOS, Android)💻
GitHub Сообщество🧑💻
https://t.me/Githublib Интересное из GitHub
Базы данных (Data Base)🖥
https://t.me/database_info Все про базы данных
Разработка игр📱
https://t.me/game_devv Все о разработке игр
БигДата, машинное обучение🖥
https://t.me/bigdata_1 Data Science, Big Data, Machine Learning, Deep Learning
QA, тестирование🖥
https://t.me/testlab_qa Библиотека тестировщика
Шутки программистов 📌
https://t.me/itumor Шутки программистов
Защита, взлом, безопасность💻
https://t.me/thehaking Канал о кибербезопасности
https://t.me/xakep_2 Хакер Free
Книги, статьи для дизайнеров🎨
https://t.me/ux_web Статьи, книги для дизайнеров
Математика🧮
https://t.me/Pomatematike Канал по математике
https://t.me/phis_mat Обучающие видео, книги по Физике и Математике
Excel лайфхак🙃
https://t.me/Excel_lifehack
Технологии🖥
https://t.me/tikon_1 Новости высоких технологий, науки и техники💡
https://t.me/mir_teh Мир технологий (Technology World)
Вакансии💰
https://t.me/sysadmin_rabota Системный Администратор
https://t.me/progjob Вакансии в IT
https://t.me/rabota1C_rus Вакансии для программистов 1С
Папка с каналами для DevOps, Linux - Windows СисАдминов
Папка с каналами для 1С программистов
Папка с каналами для C++ программистов
Папка с каналами для Python программистов
Папка с каналами для Java программистов
Папка с книгами для программистов 📚
Папка для программистов (frontend, backend, iOS, Android)
GitHub Сообщество
https://t.me/Githublib Интересное из GitHub
Базы данных (Data Base)
https://t.me/database_info Все про базы данных
Разработка игр
https://t.me/game_devv Все о разработке игр
БигДата, машинное обучение
https://t.me/bigdata_1 Data Science, Big Data, Machine Learning, Deep Learning
QA, тестирование
https://t.me/testlab_qa Библиотека тестировщика
Шутки программистов 📌
https://t.me/itumor Шутки программистов
Защита, взлом, безопасность
https://t.me/thehaking Канал о кибербезопасности
https://t.me/xakep_2 Хакер Free
Книги, статьи для дизайнеров
https://t.me/ux_web Статьи, книги для дизайнеров
Математика
https://t.me/Pomatematike Канал по математике
https://t.me/phis_mat Обучающие видео, книги по Физике и Математике
Excel лайфхак
https://t.me/Excel_lifehack
Технологии
https://t.me/tikon_1 Новости высоких технологий, науки и техники💡
https://t.me/mir_teh Мир технологий (Technology World)
Вакансии
https://t.me/sysadmin_rabota Системный Администратор
https://t.me/progjob Вакансии в IT
https://t.me/rabota1C_rus Вакансии для программистов 1С
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
Админ Devops
You’ve been invited to add the folder “Админ Devops”, which includes 18 chats.
Функция
Однако если каждый элемент итерируемого объекта — это кортеж, было бы удобно передавать каждый элемент кортежа как отдельный аргумент. В Python 2 это было возможно благодаря распаковке параметров кортежа (обратите внимание на скобки):
В Python 3 эта возможность исчезла, но есть другое решение —
👉@BookPython
map
вызывает другую функцию для каждого элемента итерируемого объекта. Это значит, что функция должна принимать одно значение в качестве аргумента:
In : list(map(lambda x: x ** 2, [1, 2, 3]))
Out: [1, 4, 9]
Однако если каждый элемент итерируемого объекта — это кортеж, было бы удобно передавать каждый элемент кортежа как отдельный аргумент. В Python 2 это было возможно благодаря распаковке параметров кортежа (обратите внимание на скобки):
>>> map(lambda (a, b): a + b, [(1, 2), (3, 4)])
[3, 7]
В Python 3 эта возможность исчезла, но есть другое решение —
itertools.starmap
. Она распаковывает кортежи за вас, будто функция вызывается со звёздочкой: f(*arg)
(отсюда и название функции):
from itertools import starmap
In [3]: list(starmap(lambda a, b: a + b, [(1, 2), (3, 4)]))
Out[3]: [3, 7]
👉@BookPython
Лямбды в Python не могут делать многое из того, что умеют обычные функции. В теле лямбда-выражения можно использовать только одно выражение, нельзя писать операторы (такие как
Тем не менее, если очень нужно превратить лямбду в асинхронную функцию, можно использовать декоратор
Разумеется, это всё равно не позволяет использовать
👉@BookPython
a = b
, yield
, await
и т.д.), также нельзя добавлять аннотации типов или объявлять лямбду как async
.Тем не менее, если очень нужно превратить лямбду в асинхронную функцию, можно использовать декоратор
asyncio.coroutine
. Это было полезно до появления ключевого слова async
в Python 3.4, но в современном Python почти не применяется.
>>> f = asyncio.coroutine(lambda x: x ** 2)
>>> asyncio.get_event_loop().run_until_complete(f(12))
144
Разумеется, это всё равно не позволяет использовать
await
внутри лямбды.👉@BookPython
Когда вы используете модуль
Однако сериализация исключений может быть непростой задачей. Исключение создаётся с любым количеством аргументов, которые сохраняются в атрибуте
Но это может не сработать так, как вы ожидаете, особенно если используется наследование. Посмотрите на пример:
Вызов
Обходное решение — либо вообще не вызывать
👉@BookPython
multiprocessing
, и в одном из процессов происходит исключение, оно передаётся в основную программу с помощью механизма сериализации (pickling). Исключение сериализуется, передаётся в другой процесс и там десериализуется обратно.Однако сериализация исключений может быть непростой задачей. Исключение создаётся с любым количеством аргументов, которые сохраняются в атрибуте
args
. Эти же аргументы используются при десериализации для воссоздания объекта исключения.Но это может не сработать так, как вы ожидаете, особенно если используется наследование. Посмотрите на пример:
import pickle
class TooMuchWeightError(Exception):
def __init__(self, weight):
super().__init__()
self._weight = weight
pickled = pickle.dumps(TooMuchWeightError(42))
pickle.loads(pickled)
Вызов
TooMuchWeightError.__init__
приводит к вызову Exception.__init__
, который устанавливает args
как пустой кортеж. Этот пустой кортеж затем используется в качестве аргументов при десериализации, что, очевидно, приводит к ошибке:
TypeError: __init__() missing 1 required positional argument: 'weight'
Обходное решение — либо вообще не вызывать
super().__init__()
(что обычно считается плохой практикой при наследовании), либо передавать все аргументы явно в конструктор родительского класса:
class TooMuchWeightError(Exception):
def __init__(self, weight):
super().__init__(weight)
self._weight = weight
👉@BookPython
Python предоставляет мощную библиотеку для работы с датой и временем —
Самым популярным модулем для этой задачи является
Вы не можете просто передать объект временной зоны
Посмотрите на этот смещение
Кроме того, после любых операций с датой и временем, нужно нормализовать объект
Начиная с Python 3.6, рекомендуется использовать
Если вам интересно, почему
👉@BookPython
datetime
. Интересный момент: объекты datetime
имеют специальный интерфейс для поддержки часовых поясов (атрибут tzinfo), однако сама библиотека `datetime
реализует его лишь частично, оставляя остальную работу сторонним модулям.Самым популярным модулем для этой задачи является
pytz
. Хитрость в том, что pytz
не полностью соответствует интерфейсу tzinfo
. В документации pytz
прямо указано с самого начала: «Эта библиотека отличается от задокументированного API Python для реализаций tzinfo
».Вы не можете просто передать объект временной зоны
pytz
в атрибут tzinfo
. Если попробуете, результат может быть абсолютно безумным:
In : paris = pytz.timezone('Europe/Paris')
In : str(datetime(2017, 1, 1, tzinfo=paris))
Out: '2017-01-01 00:00:00+00:09'
Посмотрите на этот смещение
+00:09
. Правильное использование pytz
выглядит так:
In : str(paris.localize(datetime(2017, 1, 1)))
Out: '2017-01-01 00:00:00+01:00'
Кроме того, после любых операций с датой и временем, нужно нормализовать объект
datetime
, если есть вероятность смены смещения (например, на границе перехода на летнее время):
In : new_time = time + timedelta(days=2)
In : str(new_time)
Out: '2018-03-27 00:00:00+01:00'
In : str(paris.normalize(new_time))
Out: '2018-03-27 01:00:00+02:00'
Начиная с Python 3.6, рекомендуется использовать
dateutil.tz
вместо pytz
. Он полностью совместим с tzinfo
, может использоваться напрямую, не требует normalize
, хотя и работает немного медленнее.Если вам интересно, почему
pytz
не поддерживает API datetime
, или вы хотите увидеть больше примеров, обязательно почитайте хорошую статью на эту тему.👉@BookPython
yield from
— элегантная передача управленияЕсли вы пишете генераторы, которые вызывают другие генераторы — забудьте про
for x in sub(): yield x
. Есть способ проще и мощнее.Оператор
yield from
позволяет передавать элементы из подгенератора напрямую, без лишнего кода. Но фишка не только в лаконичности — он также автоматически пробрасывает исключения и возвращаемые значения из подгенератора.Вот классика:
def gen():
for x in range(3):
yield x
def wrapper():
for x in gen():
yield x
Можно короче и лучше:
def wrapper():
yield from gen()
Но главное —
yield from
пробрасывает return-значение из подгенератора (начиная с Python 3.3):
def sub():
yield 1
yield 2
return 'done'
def main():
result = yield from sub()
print('Sub returned:', result)
for _ in main():
pass
# Выведет: Sub returned: done
А ещё через
yield from
можно проксировать значения внутрь генератора — например, в сопрограммах:
def delegator():
result = yield from coroutine()
print('coroutine done:', result)
def coroutine():
x = yield
y = yield
return x + y
g = delegator()
next(g) # Старт
next(g) # coroutine ждет x
g.send(10) # x = 10
print(g.send(20)) # y = 20 → return 30
# Выведет: coroutine done: 30
Итог: если вы пишете генераторы — освоение
yield from
даст вам лаконичный синтаксис, проброс return-значений, исключений и взаимодействие на новом уровне.👉@BookPython