Библиотека Python разработчика | Книги по питону
18.3K subscribers
1.05K photos
403 videos
82 files
1.15K links
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍

По всем вопросам @evgenycarter

РКН clck.ru/3Ko7Hq
Download Telegram
Если декоратор, который вы пишете, становится слишком сложным, имеет смысл преобразовать его из функции в класс с методом __call__.


class SavingOrig:
def __init__(self, another_decorator):
self._another = another_decorator

def __call__(self, f):
decorated = self._another(f)
if hasattr(f, 'orig'):
decorated.orig = f.orig
else:
decorated.orig = f
return decorated

saving_orig = SavingOrig


Последняя строка позволяет одновременно дать классу имя в стиле CamelCase и сохранить имя декоратора в стиле snake_case.

📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
В asyncio распространённая практика для планирования выполнения кода с задержкой — создать задачу, которая делает await asyncio.sleep(x):


import asyncio

async def do(n=0):
print(n)
await asyncio.sleep(1)
loop.create_task(do(n + 1))
loop.create_task(do(n + 1))

loop = asyncio.get_event_loop()
loop.create_task(do())
loop.run_forever()


Однако создание новой задачи может быть затратным и не требуется, если вы не собираетесь выполнять асинхронные операции (как в функции do из примера).
Другой способ сделать это — использовать функции loop.call_later и loop.call_at, которые планируют вызов асинхронного колбэка:


import asyncio

def do(n=0):
print(n)
loop = asyncio.get_event_loop()
loop.call_later(1, do, n+1)
loop.call_later(1, do, n+1)

loop = asyncio.get_event_loop()
do()
loop.run_forever()


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Оператор break подавляет исключение, если используется в блоке finally, даже когда блок except отсутствует:


for i in range(10):
try:
1 / i
finally:
print('finally')
break
print('after try')

print('after while')


Вывод:


finally
after while


То же самое верно и для continue, однако его нельзя использовать в блоке finally до версии Python 3.8:


SyntaxError: 'continue' not supported inside 'finally' clause


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Если вы хотите, чтобы объекты класса имели автоинкрементируемый ID, это можно сделать, отслеживая текущий ID в атрибуте класса:


class Task:
_task_id = 0

def __init__(self):
self._id = self._task_id
type(self)._task_id += 1


Учтите, что нельзя писать self._task_id += 1. Это создаст атрибут _task_id в экземпляре, а не в классе. Вместо этого стоит использовать фабричный метод, чтобы сделать код красивее:


class Task:
_task_id = 0

def __init__(self, task_id):
self._id = task_id

@classmethod
def create(cls):
obj = cls(cls._task_id)
cls._task_id += 1
return obj


Эта версия также проще для тестирования, так как можно легко задать любой пользовательский ID.

📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🚀 Подборка полезных 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 Типичный Сисадмин

Excel лайфхак 📌
https://t.me/Excel_lifehack Excel лайфхак

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 Свежие новости Москвы
https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП
👎1
Можно добавлять символы Unicode в строковый литерал не только по их номеру, но и по имени.


>>> '\N{EM DASH}'
'—'
>>> '\u2014'
'—'


Это также совместимо с f-строками:


>>> width = 800
>>> f'Width \N{EM DASH} {width}'
'Width — 800'


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Python предоставляет мощную библиотеку для работы с датой и временем — datetime.
Интересная особенность в том, что объекты datetime имеют специальный интерфейс для поддержки часовых поясов (а именно атрибут tzinfo), но сам модуль реализует этот интерфейс лишь частично, оставляя остальную работу другим модулям.

Наиболее популярный модуль для этой задачи — pytz.
Хитрость в том, что pytz не полностью соответствует интерфейсу tzinfo. В документации pytz это указано уже в первых строках:

«Эта библиотека отличается от задокументированного Python API для реализаций 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, может напрямую передаваться в атрибут tzinfo, не требует нормализации, хотя работает немного медленнее.

📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
В Python можно переопределить оператор квадратных скобок ([]), реализовав магический метод __getitem__.
Вот так можно создать объект, который виртуально содержит бесконечное количество повторяющихся элементов:


class Cycle:
def __init__(self, lst):
self._lst = lst

def __getitem__(self, index):
return self._lst[index % len(self._lst)]

print(Cycle(['a', 'b', 'c'])[100]) # 'b'


Необычность здесь в том, что оператор [] поддерживает особый синтаксис. Его можно использовать не только так — [2], но и так — [2:10], [2:10:2], [2::2] или даже [:].
Обычно это интерпретируется как [start:stop:step], но вы можете задать любую логику для своих объектов.

Что же передаётся в параметр index метода __getitem__, если использовать такой синтаксис? Для этого в Python существуют объекты slice.


class Inspector:
def __getitem__(self, index):
print(index)

Inspector()[1]
# 1

Inspector()[1:2]
# slice(1, 2, None)

Inspector()[1:2:3]
# slice(1, 2, 3)

Inspector()[:]
# slice(None, None, None)


Можно даже комбинировать кортежи и срезы:


Inspector()[:, 0, :]
# (slice(None, None, None), 0, slice(None, None, None))


Объект slice сам по себе ничего не делает — он просто хранит атрибуты start, stop и step:


s = slice(1, 2, 3)
s.start # 1
s.stop # 2
s.step # 3


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Оператор in можно использовать с генераторами: x in g.
Python будет итерироваться по g, пока не найдёт x или пока генератор не закончится.


>>> def g():
... print(1)
... yield 1
... print(2)
... yield 2
... print(3)
... yield 3
...
>>> 2 in g()
1
2
True


Однако range() делает для вас больше.
У него переопределён магический метод __contains__, который позволяет оператору in работать с O(1) сложностью:


In [1]: %timeit 10**20 in range(10**30)
375 ns ± 10.7 ns per loop


Имейте в виду, что это не работает для функции xrange() в Python 2.

📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🚀 Подборка полезных 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 Типичный Сисадмин

Excel лайфхак 📌
https://t.me/Excel_lifehack Excel лайфхак

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 Свежие новости Москвы
https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП
💩1
В списковых включениях (list comprehensions) может быть больше одного цикла for и условия if:


In : [(x, y) for x in range(3) for y in range(3)]
Out: [
(0, 0), (0, 1), (0, 2),
(1, 0), (1, 1), (1, 2),
(2, 0), (2, 1), (2, 2)
]



In : [
(x, y)
for x in range(3)
for y in range(3)
if x != 0
if y != 0
]
Out: [(1, 1), (1, 2), (2, 1), (2, 2)]


Кроме того, любое выражение внутри for и if может использовать все переменные, которые были определены ранее:


In : [
(x, y)
for x in range(3)
for y in range(x + 2)
if x != y
]
Out: [
(0, 1),
(1, 0), (1, 2),
(2, 0), (2, 1), (2, 3)
]


Можно смешивать if и for в любом порядке:


In : [
(x, y)
for x in range(5)
if x % 2
for y in range(x + 2)
if x != y
]
Out: [
(1, 0), (1, 2),
(3, 0), (3, 1), (3, 2), (3, 4)
]


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
В Python функция range() определяет все целые числа в полуоткрытом интервале.
То есть range(2, 10) математически означает [2, 10),
или, говоря на языке Python: [2, 3, 4, 5, 6, 7, 8, 9].

Несмотря на асимметрию, это не ошибка и не случайность.
В этом есть логика: такой подход позволяет "склеивать" два соседних интервала без риска ошибиться на единицу:

[a, c) = [a, b) + [b, c)

Для сравнения, если бы использовались закрытые интервалы, получалось бы так:

[a, c] = [a, b] + [b+1, c]

Эта же идея объясняет, почему индексация начинается с нуля:
[0, N) содержит ровно N элементов.

Эдсгер Дейкстра написал на эту тему отличную статью ещё в 1982 году.

📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2
Условное использование менеджеров контекста обычно доставляет неудобства: нельзя просто разместить with внутри блока if, не заключив туда весь блок with. Это часто приводит к дублированию кода:


def print_whole_file(
*,
path: Optional[str] = None,
file_obj: Optional[TextIO] = None
):
assert path or file_obj

if path:
with open(path) as f:
print(f.read(), end='')
else:
print(file_obj.read(), end='')


Способ борьбы с этой проблемой — использовать ExitStack и вызывать enter_context внутри if:


def print_whole_file(
*,
path: Optional[str] = None,
file_obj: Optional[TextIO] = None
):
assert path or file_obj

with ExitStack() as stack:
if path:
file_obj = stack.enter_context(
open(path)
)

print(file_obj.read(), end='')


Однако более очевидный способ достичь того же — использовать тривиальные менеджеры контекста, которые ничего не делают, когда они не нужны, вместо «настоящих». Начиная с Python 3.7, их можно получить с помощью contextlib.nullcontext:


def print_whole_file(
*,
path: Optional[str] = None,
file_obj: Optional[TextIO] = None
):
assert path or file_obj

if path:
context = open(path)
else:
context = nullcontext(file_obj)

with context as f:
print(f.read(), end='')


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3