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

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

РКН clck.ru/3Ko7Hq
Download Telegram
В 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'


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

Что же передаётся в __getitem__ в таких случаях? Объекты 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)
print(s.start) # 1
print(s.stop) # 2
print(s.step) # 3


📲 Мы в MAX

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

Правильный способ сделать это — использовать конструкцию try с except Exception, а не голый except:


try:
foreign()
except Exception:
logging.warn('fail', exc_info=True)


Голый except эквивалентен except BaseException. А разница между BaseException и Exception в том, что BaseException включает исключения, которые, как правило, ловить не следует, например, KeyboardInterrupt.

📲 Мы в MAX

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

Во-первых, в интерактивных интерпретаторах Python _ используется для хранения результата последнего выполненного выражения:


>>> 2 + 2
4
>>> _
4


Во-вторых, в документации модуля gettext рекомендуется создавать псевдоним для функции gettext() в виде _(), чтобы не загромождать код.

В-третьих, _ используется, когда необходимо придумать имя для значения, которое не представляет интереса:


>>> log_entry = '10:50:24 14234 GET /api/v1/test'
>>> time, _, method, location = log_entry.split()


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41
Есть три ситуации, в которых только что созданную переменную нельзя аннотировать типом: распаковка кортежей, циклы for и инструкции with.

Все эти примеры некорректны:


name: str, age: int = student

for x: int in numbers:
...

with connection() as conn: Connection:
...


Правильный способ указать тип таких переменных — объявить их заранее, без инициализации:


conn: Connection
with connection() as conn:
...


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
В Python сортировка по умолчанию является стабильной, то есть сохраняет порядок равных элементов:


a = [2, -1, 0, 1, -2]
sorted(a, key=lambda x: x**2)
# [0, -1, 1, 2, -2]


Функции max и min тоже стараются быть согласованными с поведением sorted.
max работает аналогично sorted(a, reverse=True)[0], а min — как sorted(a)[0].
Это означает, что обе функции возвращают самый левый возможный результат:


max([2, -2], key=lambda x: x**2)
# 2

max([-2, 2], key=lambda x: x**2)
# -2

min([2, -2], key=lambda x: x**2)
# 2

min([-2, 2], key=lambda x: x**2)
# -2


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21
Модуль collections предоставляет класс ChainMap, который позволяет использовать несколько отображений (словарей) как одно объединённое:


from collections import ChainMap

d = ChainMap(dict(a=1), dict(a=2, b=2))
d['a'] # 1
d['b'] # 2
d['c'] # ...
# KeyError: 'c'


ChainMap последовательно просматривает все вложенные отображения и возвращает первое найденное значение. Однако все операции изменения затрагивают только первое отображение:


d = ChainMap(dict(a=1), dict(a=2, b=2))
d['c'] = 3
d
# ChainMap({'a': 1, 'c': 3}, {'a': 2, 'b': 2})


📲 Мы в MAX

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