uk
Feedback
Библиотека Python разработчика | Книги по питону

Библиотека Python разработчика | Книги по питону

Відкрити в Telegram

Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq

Показати більше
18 330
Підписники
-824 години
-357 днів
-8530 день
Архів дописів
Функция round округляет число до заданной точности в десятичных знаках.

>>> round(1.2)
1
>>> round(1.8)
2
>>> round(1.228, 1)
1.2
Также можно задать отрицательную точность:

>>> round(413.77, -1)
410.0
>>> round(413.77, -2)
400.0
round возвращает значение того же типа, что и входное число:

>>> type(round(2, 1))
<class 'int'>

>>> type(round(2.0, 1))
<class 'float'>

>>> type(round(Decimal(2), 1))
<class 'decimal.Decimal'>

>>> type(round(Fraction(2), 1))
<class 'fractions.Fraction'>
Для собственных классов можно определить поведение округления с помощью метода __round__:

>>> class Number(int):
...   def __round__(self, p=-1000):
...     return p
...
>>> round(Number(2))
-1000
>>> round(Number(2), -2)
-2
Значения округляются до ближайшего кратного 10 ** (-precision). Например, при precision=1, значение округляется до кратного 0.1: round(0.63, 1) возвращает 0.6. Если два значения одинаково близки, округление происходит в сторону чётного числа:

>>> round(0.5)
0
>>> round(1.5)
2
Иногда округление чисел с плавающей точкой может казаться неожиданным:

>>> round(2.85, 1)
2.9
Это связано с тем, что большинство десятичных дробей не могут быть точно представлены в формате float:

>>> format(2.85, '.64f')
'2.8500000000000000888178419700125232338905334472656250000000000000'
Если нужно округление "в большую сторону при 0.5" (round half up), можно использовать decimal.Decimal:

>>> from decimal import Decimal, ROUND_HALF_UP
>>> Decimal(1.5).quantize(0, ROUND_HALF_UP)
Decimal('2')
>>> Decimal(2.85).quantize(Decimal('1.0'), ROUND_HALF_UP)
Decimal('2.9')
>>> Decimal(2.84).quantize(Decimal('1.0'), ROUND_HALF_UP)
Decimal('2.8')
📲 Мы в MAX 👉@BookPython

Стандартный модуль json имеет интерфейс командной строки, который может быть полезен для форматирования JSON только с помощью Python. Модуль для этого называется json.tool и предназначен для вызова следующим образом:

$ echo '{"a": [], "b": "c"}' | python -m json.tool
{
    "a": [],
    "b": "c"
}
📲 Мы в MAX 👉@BookPython

Чтобы немедленно остановить выполнение программы на Python, следует использовать sys.exit(). Альтернативой является функция exit(), однако она предназначена для использования в интерактивном режиме. Благодаря строковому представлению, она может помочь пользователям, которые пытаются завершить сессию, используя exit (что поддерживается многими оболочками):

>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit
>>> str(exit)
'Use exit() or Ctrl-D (i.e. EOF) to exit'
И exit(), и sys.exit() на самом деле не завершают программу, а просто выбрасывают исключение SystemExit. SystemExit — это прямой подкласс BaseException, а значит, он не может быть перехвачен через except Exception, но может быть перехвачен через except BaseException или через голый except:.

>>> try:
...     exit()
... except:
...     'Nothing'
...
'Nothing'
Поскольку это может быть проблемой, можно использовать функцию os._exit. Она не выбрасывает никаких исключений — просто завершает текущий процесс. Однако это означает, что блоки finally, а также завершающие действия менеджеров контекста не будут выполнены.

$ python3
Python 3.4.3 (default, Apr 28 2015, 13:37:07)
[GCC 4.8.3 20140911 (Red Hat 4.8.3-9)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> try:
...     os._exit(42)
... finally:
...     print('Bye!')
...
$ ...
📲 Мы в MAX 👉@BookPython

Иногда программное обеспечение начинает вести себя странно в продакшене. Вместо того чтобы просто перезапустить его, вы, вероятно, захотите понять, что именно происходит, чтобы позже это исправить. Очевидный способ сделать это — проанализировать, что делает программа, и попытаться угадать, какой участок кода выполняется. Безусловно, корректная система логирования облегчает эту задачу, но логи приложения могут быть недостаточно подробными — либо по замыслу, либо из-за настроек, ограничивающих уровень логирования. В таком случае может пригодиться strace. Это утилита Unix, которая отслеживает системные вызовы. Вы можете запустить её заранее — strace python script.py — но чаще бывает удобнее подключиться к уже работающему процессу: strace -p PID.
$ cat test.py
with open('/tmp/test', 'w') as f:
    f.write('test')
$ strace python test.py 2>&1 | grep open | tail -n 1
open("/tmp/test", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 3
Каждая строка в выводе strace содержит имя системного вызова, его аргументы в скобках и возвращаемое значение. Поскольку некоторые аргументы являются выходными параметрами (используются для возврата результата, а не для передачи данных), вывод строки может быть прерван до завершения системного вызова. В следующем примере вывод приостанавливается до тех пор, пока кто-то не введёт данные в STDIN:

$ strace python -c 'input()'
...
read(0,
📲 Мы в MAX 👉@BookPython

🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. https://max.ru/tipsysdmin Типичный Сисадмин 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика Программирование Go📌 https://max.ru/golang_lib Библиотека Go (Golang) разработчика Программирование React📌 https://max.ru/react_lib React Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии 📌 https://max.ru/progjob Вакансии в IT Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Бонус 📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы

У Python очень короткий список встроенных констант. Одна из них — Ellipsis, которую также можно записать как .... Эта константа не имеет особого значения для интерпретатора, но используется в ситуациях, где такой синтаксис уместен. В библиотеке NumPy Ellipsis поддерживается в качестве аргумента для __getitem__, например, x[...] возвращает все элементы массива x. PEP 484 придаёт Ellipsis дополнительный смысл: Callable[..., type] используется для обозначения типа вызываемых объектов без указания типов аргументов. Наконец, ... можно использовать, чтобы показать, что функция ещё не реализована. Это полностью допустимый Python-код:

def x():
    ...
📲 Мы в MAX 👉@BookPython

💡10 функций, для продвинутых Python-разработчиков 1. Разворачиваем вложенных списков любой глубины

flatten = lambda lst: [x for sub in lst for x in (flatten(sub) if isinstance(sub, list) else [sub])]
2. Декоратор для мемоизации результатов функции

memoize = lambda f: (lambda *args, _cache={}, **kwargs: _cache.setdefault((args, tuple(kwargs.items())), f(*args, **kwargs)))
3. Разбиение списка на куски длины n

chunked = lambda lst, n: [lst[i:i+n] for i in range(0, len(lst), n)]
4. Уникализация последовательности с сохранением порядка

uniq = lambda seq: list(dict.fromkeys(seq))
5. Глубокий доступ к вложенным ключам словаря

deep_get = lambda d, *keys: __import__('functools').reduce(lambda a, k: a.get(k) if isinstance(a, dict) else None, keys, d)
6. Преобразование Python-объекта в читаемый JSON

pretty_json = lambda obj: __import__('json').dumps(obj, ensure_ascii=False, indent=2)
7. Чтение последних n строк файла (аналог tail)

tail = lambda f, n=10: list(__import__('collections').deque(open(f), maxlen=n))
8. Выполнение shell-команды и возврат вывода

sh = lambda cmd: __import__('subprocess').run(cmd, shell=True, check=True, capture_output=True).stdout.decode().strip()
9. Быстрое объединение путей

path_join = lambda *p: __import__('os').path.join(*p)
10. Группировка списка словарей по значению ключа

group_by = lambda seq, key: {k: [d for d in seq if d.get(key) == k] for k in set(d.get(key) for d in seq)}
📲 Мы в MAX 👉@BookPython

Если вы хотите итерироваться одновременно по нескольким итерируемым объектам, функция zip может быть хорошим выбором. Она возвращает генератор, который выдаёт кортежи, содержащие по одному элементу из каждого исходного итерируемого объекта:

In : eng = ['one', 'two', 'three']
In : ger = ['eins', 'zwei', 'drei']
In : for e, g in zip(eng, ger):
    ...:     print('{e} = {g}'.format(e=e, g=g))
    ...:
Вывод:
one = eins  
two = zwei  
three = drei
Обратите внимание, что zip принимает итерируемые объекты как отдельные аргументы, а не в виде списка аргументов. Чтобы «развернуть» значения (unzip), можно использовать оператор *:

In : list(zip(*zip(eng, ger)))
Out: [('one', 'two', 'three'), ('eins', 'zwei', 'drei')]
📲 Мы в MAX 👉@BookPython

Иногда в тестах нужно сравнивать сложные структуры, игнорируя некоторые значения. Обычно это делается путем сравнения отдельных значений внутри структуры:

>>> d = dict(a=1, b=2, c=3)
>>> assert d['a'] == 1
>>> assert d['c'] == 3
Однако можно создать специальное значение, которое будет считаться равным любому другому значению:

>>> assert d == dict(a=1, b=ANY, c=3)
Это легко реализовать, определив метод __eq__:

>>> class AnyClass:
...     def __eq__(self, another):
...         return True
... 
>>> ANY = AnyClass()
📲 Мы в MAX 👉@BookPython

🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. https://max.ru/tipsysdmin Типичный Сисадмин 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика Программирование Go📌 https://max.ru/golang_lib Библиотека Go (Golang) разработчика Программирование React📌 https://max.ru/react_lib React Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии 📌 https://max.ru/progjob Вакансии в IT Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Бонус 📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы

Начиная с Python 3.7, модуль contextlib предоставляет декоратор asynccontextmanager, который позволяет определять асинхронные контекстные менеджеры точно так же, как contextmanager:

import asyncio
from contextlib import asynccontextmanager

@asynccontextmanager
async def slow(delay):
    half = delay / 2
    await asyncio.sleep(half)
    yield
    await asyncio.sleep(half)

async def main():
    async with slow(1):
        print('slow')

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Для более старых версий Python можно использовать @asyncio_extras.async_contextmanager. 📲 Мы в MAX 👉@BookPython

Если ты хочешь, чтобы контекстный менеджер при входе или выходе из контекста приостанавливал выполнение корутины, следует использовать асинхронные контекстные менеджеры. Вместо вызова m.__enter__() и m.__exit__() Python в этом случае выполняет await m.__aenter__() и await m.__aexit__() соответственно. Асинхронные контекстные менеджеры нужно использовать с синтаксисом async with:

import asyncio

class Slow:
    def __init__(self, delay):
        self._delay = delay

    async def __aenter__(self):
        await asyncio.sleep(self._delay / 2)

    async def __aexit__(self, *exception):
        await asyncio.sleep(self._delay / 2)

async def main():
    async with Slow(1):
        print('slow')

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
В этом примере класс Slow симулирует задержку при входе и выходе из контекста. 📲 Мы в MAX 👉@BookPython

Начиная с Python 3.5, стало возможно использовать распаковку в литералах словарей и списков. Пример со словарём:

{**{'a': 1}, 'b': 2, **{'c': 3}}
# Результат: {'a': 1, 'b': 2, 'c': 3}
Пример со списком:

[1, 2, *[3, 4]]
# Результат: [1, 2, 3, 4]
Для словарей такая форма даже мощнее, чем функция dict, потому что позволяет переопределять значения:

{**{'a': 1, 'b': 1}, 'a': 2, **{'b': 3}}
# Результат: {'a': 2, 'b': 3}
📲 Мы в MAX 👉@BookPython

Ты можешь создавать словари двумя способами: с помощью литералов или функции dict:

>>> dict(a=1, b=2)
{'a': 1, 'b': 2}
>>> {'a': 1, 'b': 2}
{'a': 1, 'b': 2}
Литералы работают быстрее, чем dict, но у функции есть свои преимущества. Во-первых, не нужно ставить дополнительные кавычки. Однако это работает только в том случае, если все ключи — допустимые идентификаторы Python:

>>> dict(a=1)
{'a': 1}
>>> dict(1='a')
  File "<stdin>", line 1
SyntaxError: keyword can't be an expression
Во-вторых, ты не сможешь случайно указать один и тот же ключ дважды:

>>> {'a': 1, 'a': 1}
{'a': 1}
>>> dict(a=1, a=1)
  File "<stdin>", line 1
SyntaxError: keyword argument repeated
В-третьих, легко создать новый словарь на основе уже существующего:

>>> d = dict(b=2)
>>> dict(a=1, **d)
{'a': 1, 'b': 2}
Но учти, что ключи нельзя переопределять при таком способе:

>>> dict(b=3, **d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: type object got multiple values for keyword argument
📲 Мы в MAX 👉@BookPython

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

from contextlib import contextmanager

QUIT_MESSAGE = 'Bye'

def print_quit_mesage():
    global QUIT_MESSAGE
    print(QUIT_MESSAGE)

@contextmanager
def global_variable_changed(name, value):
    orig_value = globals()[name]
    globals()[name] = value
    yield
    globals()[name] = orig_value

with global_variable_changed(
    'QUIT_MESSAGE',
    'Tschüss'
):
    print_quit_mesage()
📲 Мы в MAX 👉@BookPython

🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика Программирование Go📌 https://max.ru/golang_lib Библиотека Go (Golang) разработчика Программирование React📌 https://max.ru/react_lib React Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии 📌 https://max.ru/progjob Вакансии в IT Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Бонус 📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы

Существует две встроенные функции, которые позволяют анализировать итерируемые объекты без необходимости писать тривиальные и избыточные циклы for. Это all и any. any возвращает True, если хотя бы одно значение истинно; all возвращает True, только если все значения истинны. Для пустого итерируемого объекта all возвращает True, а anyFalse. Обе функции особенно полезны в сочетании со списковыми включениями (list comprehensions):

package_broken = any(
    part.is_broken() for part in package.get_parts()
)
package_ok = all(
    part.ok() for part in package.get_parts()
)
Функции any и all зачастую взаимозаменяемы благодаря законам де Моргана. Используй ту, с которой код будет понятнее. 📲 Мы в MAX 👉@BookPython

Иногда нужно создать функцию на основе более универсальной. Например, у функции int() есть параметр base, который мы хотим зафиксировать, чтобы получить новую функцию base2:

>>> int("10")
10
>>> int("10", 2)
2
>>> def base2(x):
...     return int(x, 2)
...
>>> base2("10")
2
functools.partial позволяет сделать то же самое, но точнее и семантически понятнее:

base2 = partial(int, base=2)
Это полезно, когда нужно передать функцию как аргумент другой, более общей функции, но при этом некоторые аргументы должны быть зафиксированы:

>>> map(partial(int, base=2), ["1", "10", "100"])
[1, 2, 4]
Без partial пришлось бы делать так:

>>> map(lambda x: int(x, base=2), ["1", "10", "100"])
[1, 2, 4]
📲 Мы в MAX 👉@BookPython

В Python нет поддержки асинхронных операций с файлами. Чтобы сделать их неблокирующими, нужно использовать отдельные потоки. Для асинхронного выполнения кода в потоке следует использовать метод loop.run_in_executor. Сторонний модуль aiofiles делает всё это за тебя, предоставляя простой и удобный интерфейс:

async with aiofiles.open('filename', mode='r') as f:
    contents = await f.read()
📲 Мы в MAX 👉@BookPython

>>> bool(datetime(2018, 1, 1).time())
False
>>> bool(datetime(2018, 1, 1, 13, 12, 11).time())
True
До Python 3.5 объекты datetime.time() считались ложными, если они представляли полночь по UTC. Это могло приводить к трудноуловимым ошибкам. В следующих примерах if not может выполниться не потому, что created_time равен None, а потому, что время — полночь.

def create(created_time=None) -> None:
    if not created_time:
        created_time = datetime.now().time()
Можно исправить это, явно проверяя на None:

def create(created_time=None) -> None:
    if created_time is None:
        created_time = datetime.now().time()
📲 Мы в MAX 👉@BookPython