Библиотека Python разработчика | Книги по питону
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq
نمایش بیشتر📈 تحلیل کانال تلگرام Библиотека Python разработчика | Книги по питону
کانال Библиотека Python разработчика | Книги по питону (@bookpython) در بخش زبانی روسی بازیگری فعال است. در حال حاضر جامعه شامل 17 969 مشترک است و جایگاه 7 264 را در دسته فناوری و برنامهها و رتبه 36 611 را در منطقه روسيا دارد.
📊 شاخصهای مخاطب و پویایی
از زمان ایجاد در невідомо، پروژه رشد سریعی داشته و 17 969 مشترک جذب کرده است.
بر اساس آخرین دادهها در تاریخ 30 اکتبر, 2026، کانال فعالیت پایداری دارد. در ۳۰ روز گذشته تغییر اعضا برابر -95 و در ۲۴ ساعت گذشته برابر -1 بوده و همچنان دسترسی گستردهای حفظ شده است.
- وضعیت تأیید: تأیید نشده
- نرخ تعامل (ER): میانگین تعامل مخاطب 5.36% است و در ۲۴ ساعت نخست پس از انتشار، محتوا معمولاً 2.75% واکنش نسبت به کل مشترکان کسب میکند.
- دسترسی پستها: هر پست به طور میانگین 963 بازدید دریافت میکند. در اولین روز معمولاً 494 بازدید جمعآوری میشود.
- واکنشها و تعامل: مخاطبان بهطور فعال حمایت میکنند؛ میانگین واکنش به هر پست 4 است.
- علایق موضوعی: محتوا بر موضوعات کلیدی مانند numbers, yield, модуль, none, декоратор تمرکز دارد.
📝 توضیح و سیاست محتوایی
نویسنده این فضا را محل بیان دیدگاههای شخصی توصیف میکند:
“Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍
По всем вопросам @evgenycarter
РКН clck.ru/3Ko7Hq”
به لطف بهروزرسانیهای پرتکرار (آخرین داده در تاریخ 31 اکتبر, 2026)، کانال همواره بهروز و دارای دسترسی بالاست. تحلیلها نشان میدهد مخاطبان بهطور فعال با محتوا تعامل دارند و آن را به نقطه اثرگذاری مهم در دسته فناوری و برنامهها تبدیل کردهاند.
'port' нет в config, устанавливаем его значение по умолчанию:
if 'port' not in config:
config['port'] = 80
port = config['port']
Но можно сделать это более элегантно с помощью setdefault:
port = config.setdefault('port', 80)
Метод setdefault устанавливает новое значение, если оно ещё не задано, и возвращает сохранённое значение вне зависимости от того, было ли оно изменено:
In : config = {}
In : config.setdefault('port', 80)
Out: 80
In : config.setdefault('port', 443)
Out: 80
👉@BookPython
a = 10
b = 20
c = a + b
Хороший пример:
price = 10
tax = 20
total_cost = price + tax
Теперь сразу понятно, что делает код!
2️⃣ Разбивайте код на функции
Вместо длинных кусков кода, используйте функции:
def calculate_total(price, tax):
return price + tax
total_cost = calculate_total(10, 20)
Теперь код можно переиспользовать и проще тестировать.
3️⃣ Следуйте PEP 8
Форматирование кода влияет на его читаемость. Например, пробелы вокруг операторов делают код более понятным:
# Плохо
total=price+tax
# Хорошо
total = price + tax
Пользуйтесь black или flake8, чтобы следить за стилем.
4️⃣ Избегайте магических чисел
Если в коде встречаются непонятные числа, лучше заменить их на константы:
# Плохо
if age > 18:
print("Взрослый")
# Хорошо
LEGAL_AGE = 18
if age > LEGAL_AGE:
print("Взрослый")
5️⃣ Используйте list comprehensions
Вместо:
numbers = [1, 2, 3, 4, 5]
squared_numbers = []
for num in numbers:
squared_numbers.append(num ** 2)
Лучше:
squared_numbers = [num ** 2 for num in numbers]
Чище и лаконичнее!
Читаемый код делает разработку приятнее, ускоряет исправление багов и упрощает поддержку. Напишите в комментариях, какие еще приемы вы используете для улучшения читаемости кода! 👇
👉 @BookPythonmultiprocessing.
Проблема:
Допустим, у нас есть функция, которая выполняет вычисления для каждого элемента списка:
import time
def slow_function(x):
time.sleep(1) # Симуляция долгих вычислений
return x * x
data = [1, 2, 3, 4, 5]
results = [slow_function(x) for x in data]
print(results)
Этот код выполняется 5 секунд, потому что вычисления идут последовательно.
Решение: multiprocessing.Pool
Используем multiprocessing, чтобы запустить вычисления параллельно:
from multiprocessing import Pool
with Pool() as pool:
results = pool.map(slow_function, data)
print(results)
Теперь код выполняется всего 1 секунду! 🎉
✅ Python автоматически распределяет вычисления по ядрам процессора
✅ Код остаётся читаемым и простым
✅ Работает во всех системах (но в Windows нужен if name == "__main__")
Итоги:
- Используйте multiprocessing.Pool для CPU-интенсивных задач
- Это легко и быстро внедряется в существующий код
- Безопасный способ ускорения без Cython и Numba
А какие ещё способы ускорения Python-кода вы знаете? Делитесь в комментариях! 👇
👉 @BookPythonfor и 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)
]
Можно также добавлять условия if для фильтрации значений:
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)
]
Вы можете комбинировать for и if в любом порядке:
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)
]
👉@BookPythonsleep(x), которая должна "заморозить" программу на x секунд, но на практике может завершиться раньше, если появится сигнал.
Однако, начиная с Python 3.5, благодаря PEP 475, Python автоматически обрабатывает все такие вызовы. Следующая программа завершится при первом полученном SIGINT в любой версии Python до 3.5. Но в Python 3.5+ она будет спать ровно 5 секунд, независимо от сигналов.
import signal
import time
def signal_handler(signal, frame):
print('Caught')
signal.signal(signal.SIGINT, signal_handler)
time.sleep(5)
👉@BookPythonselect_related и prefetch_related
Django ORM лениво загружает связанные объекты, что может привести к множественным SQL-запросам (N+1). Вместо этого используйте:
# select_related — жадная загрузка (для ForeignKey, OneToOne)
posts = Post.objects.select_related("author").all()
# prefetch_related — для ManyToMany и Reverse ForeignKey
posts = Post.objects.prefetch_related("comments").all()
Это значительно уменьшает количество запросов к базе.
2️⃣ Используйте only и defer
Если вам не нужны все поля модели, загружайте только необходимые:
users = User.objects.only("id", "username") # Загружаем только ID и имя
А если хотите исключить несколько полей:
users = User.objects.defer("bio", "last_login") # Исключаем ненужные поля
3️⃣ Агрегация вместо перебора в Python
Вместо:
total_likes = sum(post.likes.count() for post in posts)
Используйте annotate:
from django.db.models import Count
posts = Post.objects.annotate(total_likes=Count("likes"))
Это выполнится на стороне базы, а не в Python, что намного быстрее.
4️⃣ Используйте exists() вместо count()
Если вам нужно проверить, есть ли записи в базе, не используйте count(), это дорогостоящий запрос:
if User.objects.filter(email="test@example.com").exists(): # Быстро
❌ Плохо:
if User.objects.filter(email="test@example.com").count() > 0: # Долго
5️⃣ Кешируйте запросы
Django поддерживает кеширование, и если запросы повторяются, можно использовать:
from django.core.cache import cache
users = cache.get("users")
if not users:
users = list(User.objects.all()) # Загружаем пользователей
cache.set("users", users, timeout=60 * 15) # Кешируем на 15 минут
Эти простые приемы помогут вам ускорить Django-приложение и уменьшить нагрузку на базу данных. А вы уже используете их в своих проектах? Делитесь в комментариях! 👇
👉@BookPythonyield вместо return. Они не возвращают сразу все значения, а запоминают своё состояние и отдают результат по мере необходимости. Это особенно полезно при обработке больших объемов данных, так как позволяет не загружать всю информацию в память сразу.
Пример: экономия памяти
Допустим, нам нужно обработать миллион чисел и взять из них только четные. Обычный способ:
def get_even_numbers(n):
result = []
for i in range(n):
if i % 2 == 0:
result.append(i)
return result
numbers = get_even_numbers(10**6)
print(len(numbers)) # 500000
Такой код загружает в память весь список, что может быть проблемой при больших данных.
А теперь переделаем на генератор:
def get_even_numbers_gen(n):
for i in range(n):
if i % 2 == 0:
yield i
numbers = get_even_numbers_gen(10**6)
print(sum(1 for _ in numbers)) # 500000
Здесь список не создается, а элементы выдаются по одному. Это экономит память и ускоряет обработку!
Где применять?
✔️ Чтение больших файлов построчно (yield line)
✔️ Работа с потоками данных
✔️ Генерация последовательностей без создания списков
👉@BookPythonpython foo.py; в этом случае foo.py просто выполняется.
Однако, можно также использовать python -m foo. Если foo — это не пакет, то foo.py ищется в sys.path и выполняется. Если это пакет, то Python сначала выполняет foo/__init__.py, а затем foo/__main__.py. Обратите внимание, что во время выполнения __init__.py значение __name__ равно foo, но во время выполнения __main__.py оно равно __main__.
Можно также запустить Python с каталогом: python dir/ или даже python dir.zip. В этом случае Python ищет dir/__main__.py и выполняет его, если находит.
Пример:
$ ls foo
__init__.py __main__.py
$ cat foo/__init__.py
print(__name__)
$ cat foo/__main__.py
print(__name__)
$ python -m foo
foo
__main__
$ python foo/
__main__
$ python foo/__init__.py
__main__
👉@BookPythonio предоставляет два типа файловых объектов в памяти. Такие объекты могут быть полезны для работы с интерфейсами, которые поддерживают только файлы, без необходимости создавать их на диске. Очевидный пример — модульное тестирование.
Эти два типа — BytesIO и StringIO, которые работают соответственно с байтами и строками.
from io import StringIO
f = StringIO()
f.write('first\n') # Вывод: 6
f.write('second\n') # Вывод: 7
f.seek(0) # Вывод: 0
print(f.readline()) # Вывод: 'first\n'
print(f.readline()) # Вывод: 'second\n'
👉@BookPythonzip может быть хорошим выбором. Она возвращает генератор, который выдаёт кортежи, содержащие по одному элементу из каждого исходного итерируемого объекта:
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 принимает итерируемые объекты как отдельные аргументы, а не список аргументов.
Для распаковки значений можно использовать оператор *:
In : list(zip(*zip(eng, ger)))
Out: [('one', 'two', 'three'), ('eins', 'zwei', 'drei')]
👉@BookPythonlist позволяет хранить массив из любых объектов. Это довольно удобно, но может быть неэффективно. Для компактного представления массивов базовых значений можно использовать модуль array. Поддерживаемые значения включают различные типы C, такие как char, int, long, double и другие. Фактическое представление определяется реализацией C.
import array
a = array.array('B') # Создаем массив байтов
a.append(240)
a.append(159)
a.append(144)
a.append(180)
print(a.tobytes().decode('utf8')) # Выводит: '🐴'
👉@BookPython