Библиотека Python разработчика | Книги по питону
19.1K subscribers
1.06K photos
404 videos
82 files
1.03K links
Полезные материалы для питониста по Фреймворкам Django, Flask, FastAPI, Pyramid, Tornado и др.

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

РКН clck.ru/3Ko7Hq
Download Telegram
Распаковка параметров функций в Python 2 и 3

В Python 2 существовала интересная возможность распаковывать параметры функций прямо в их определении. Пример:


def between(x, (start, stop)):
return start < x < stop

interval = (5, 10)
print(between(2, interval)) # False
print(between(7, interval)) # True


Более того, это работало даже рекурсивно:


def determinant_2_x_2(((a, b), (c, d))):
return a * d - c * b

matrix = [
(1, 2),
(3, 4),
]
print(determinant_2_x_2(matrix)) # -2


Но начиная с Python 3, эта возможность была удалена из языка. Чтобы добиться того же результата, теперь нужно распаковывать параметры вручную:


def determinant_2_x_2(matrix):
row1, row2 = matrix
a, b = row1
c, d = row2
return a * d - c * b

matrix = [
(1, 2),
(3, 4),
]
print(determinant_2_x_2(matrix)) # -2


Удаление этой функциональности сделало код более явным и читаемым, но для любителей компактности Python 2 по-прежнему вызывает лёгкую ностальгию.

📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41
Почему range() в Python использует полуоткрытые интервалы?

Функция range() в Python работает с полуоткрытыми интервалами. Например, range(2, 10) задаёт числа в диапазоне [2, 10), то есть [2, 3, 4, 5, 6, 7, 8, 9]. На первый взгляд это может показаться неочевидным или асимметричным, но у такого подхода есть свои преимущества.

Почему полуоткрытые интервалы?
Полуоткрытые интервалы позволяют легко "склеивать" смежные диапазоны без риска ошибок на единицу:

- Если a = 2, b = 5, и c = 10, то [a, c) можно выразить как:

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

Это работает идеально, потому что конец одного интервала (`b`) автоматически становится началом следующего.

В случае закрытых интервалов, такая "склейка" требует дополнительной обработки:

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


Связь с индексацией с нуля
Индексация с нуля в Python также связана с этим принципом. Рассмотрим диапазон range(0, N):
- Этот диапазон включает ровно N элементов, что делает код более предсказуемым:

for i in range(0, N):
print(i)

Здесь i проходит значения от 0 до N-1, что логично и удобно.

Преимущества для работы с массивами
Полуоткрытые интервалы идеально подходят для работы с индексами массивов:

arr = [10, 20, 30, 40, 50]
print(arr[1:3]) # [20, 30]

Интервал [1:3) охватывает элементы с индексами 1 и 2, но не 3, что упрощает вычисления границ.

Исторический контекст
Этот подход имеет глубокие корни в компьютерной науке. Эдсгер Дейкстра, один из пионеров программирования, в 1982 году написал блестящую статью, в которой обосновал преимущества полуоткрытых интервалов. Это не просто удобство — это вопрос корректности и простоты работы с данными.

📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Как узнать размер генератора в Python?

В Python часто возникает задача определить размер генератора без необходимости извлечения всех его значений. Это полезно, если вы работаете с большими потоками данных и хотите избежать избыточного расхода памяти.

Пример с len()
Некоторые итераторы, такие как range, поддерживают вызов len():


len(range(10000)) # 10000


Однако генераторы не имеют длины, и попытка вызвать len() вызовет ошибку:


gen = (x ** 2 for x in range(10000))
len(gen) # TypeError: object of type 'generator' has no len()


Стандартное решение: преобразование в список
Один из способов получить размер генератора — это преобразовать его в список:


gen = (x ** 2 for x in range(10000))
print(len(list(gen))) # 10000


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

Более эффективный подход: подсчёт с помощью sum
Чтобы избежать лишнего расхода памяти, можно подсчитать количество элементов в генераторе с использованием sum():


gen = (x ** 2 for x in range(10000))
print(sum(1 for _ in gen)) # 10000


Этот метод обходит генератор "лениво", не создавая дополнительных списков, что делает его идеальным для работы с большими потоками данных.

Резюме
- Используйте len() только для итераторов, поддерживающих его (например, range).
- Для генераторов избегайте преобразования в список, если важна экономия памяти.
- Используйте sum(1 for _ in gen) для эффективного подсчёта элементов генератора.

📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2💩2
Media is too big
VIEW IN TELEGRAM
Прежде чем читать длиннющий релиз новой версии Python 3.14, посмотрите это видео Евгения Афонасьева, тимлида разработки Antifraud в Авито 🚀

За 12 минут он рассказал, какие фичи стоят внимания внедрения в работу, про небольшие, но приятные обновления тоже не забыл.

📺 Смотрим и обсуждаем по ссылке!
Please open Telegram to view this post
VIEW IN TELEGRAM
💩2
Когда вам нужно очистить список в Python, вы, скорее всего, используете lst = []. Однако на самом деле вы просто создаёте новый пустой список и присваиваете его переменной lst, а все другие переменные, которые ссылаются на исходный список, продолжают хранить его содержимое.

Пример:

lst = [1, 2, 3]
lst2 = lst
lst = []
print(lst2) # [1, 2, 3]


Хотя это кажется очевидным, правильное решение стало доступно только с введением метода lst.clear() в Python 3.3.

До этого для очистки списка приходилось использовать:
- del lst[:], или
- lst[:] = [].

Оба варианта работают, поскольку срезы позволяют модифицировать часть списка. Если вы берёте срез [:], он охватывает весь список.

Теперь же lst.clear() является более читаемым и современным решением.

📲 Мы в MAX

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