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

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

前往频道在 Telegram

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

显示更多

📈 Telegram 频道 Библиотека Python разработчика | Книги по питону 的分析概览

频道 Библиотека Python разработчика | Книги по питону (@bookpython) 俄语 语言赛道中的 是活跃参与者。目前社区聚集了 18 328 名订阅者,在 技术与应用 类别中位列第 7 299,并在 俄罗斯 地区排名第 36 904

📊 受众指标与增长动态

невідомо 创建以来,项目保持高速增长,吸引了 18 328 名订阅者。

根据 03 六月, 2026 的最新数据,频道保持稳定运转。过去 30 天订阅人数变化为 -85,过去 24 小时变化为 -8,整体触达仍然可观。

  • 认证状态: 未认证
  • 互动率 (ER): 平均受众互动率为 6.04%。内容发布后 24 小时内通常能获得 2.53% 的反应,占订阅者总量。
  • 帖子覆盖: 每篇帖子平均可获得 1 107 次浏览,首日通常累积 463 次浏览。
  • 互动与反馈: 受众积极参与,单帖平均反应数为 2
  • 主题关注点: 内容集中在 numbers, yield, модуль, none, декоратор 等核心主题上。

📝 描述与内容策略

作者将该频道定位为表达主观观点的平台:
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq

凭借高频更新(最新数据采集于 04 六月, 2026),频道始终保持新鲜度与高覆盖。分析显示受众积极互动,使其成为 技术与应用 类别中的关键影响点。

18 328
订阅者
-824 小时
-357
-8530
帖子存档
⚡ Как ускорить код на Python? Используем map, filter, reduce ⚡ Привет, друзья! Сегодня расскажу о том, как можно ускорить выполнение кода, заменяя обычные циклы на встроенные функции map(), filter() и reduce(). Эти инструменты позволяют писать более компактный, читаемый и быстрый код. ✅ map() Функция map() применяется к каждому элементу последовательности и возвращает новый итератор. ❌ Обычный способ:

numbers = [1, 2, 3, 4, 5]
squared = []
for num in numbers:
    squared.append(num ** 2)
✅ Быстрее с map():

numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
За счёт того, что map() использует C-оптимизированную логику, код выполняется быстрее. ✅ filter() Фильтрует элементы последовательности по заданному условию. ❌ Медленный вариант:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = []
for num in numbers:
    if num % 2 == 0:
        evens.append(num)
✅ Быстрее с filter():

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = list(filter(lambda x: x % 2 == 0, numbers))
Такой код читается легче и работает быстрее. ✅ reduce() Позволяет выполнять кумулятивные операции (например, суммирование, умножение). ❌ Классический способ:

numbers = [1, 2, 3, 4, 5]
product = 1
for num in numbers:
    product *= num
✅ Быстрее с reduce():

from functools import reduce

numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)
Этот метод полезен, если нужно свести список к одному значению. 💡 Важно: reduce() чаще заменяют sum() или math.prod(), но для сложных операций он остаётся полезным. Такие функции помогают писать код, который не только быстрее работает, но и легче читается. 📲 Мы в MAX 👉@BookPython

⚡️ Готовые решения и лучшие практики для надёжной защиты API в архитектуре бэкенда 📅 26 января | 20:00 мск | бесплатно Хотит
⚡️ Готовые решения и лучшие практики для надёжной защиты API в архитектуре бэкенда 📅 26 января | 20:00 мск | бесплатно Хотите, чтобы ваши API были надёжно защищены без потери производительности? На вебинаре разберём: - Типовые угрозы и уязвимости API в современных backend-системах - Аутентификация и авторизация: лучшие подходы, паттерны и типичные ошибки - Защита на уровне архитектуры: rate limiting, throttling, контроль доступа - Роль API Gateway и прокси в обеспечении безопасности - Лучшие практики проектирования защищённых API и контрактов 💡 Полезно для: - Software Architects, проектирующих внешние и внутренние API - Backend-разработчиков, работающих с интерфейсами - Технических лидов, отвечающих за безопасность и устойчивость систем ✅ После вебинара вы сможете: - Проектировать API с учётом безопасности на уровне архитектуры - Выбирать и применять готовые решения для защиты API - Использовать чек-лист лучших практик для создания защищённых интерфейсов - Осознанно балансировать между безопасностью, сложностью и производительностью 👉 Регистрируйтесь https://vk.cc/cTDTJV Занятие приурочено к старту курса "Software Architect", обучение на котором позволит освоить компетенции архитектора по моделированию и построению отказоустойчивых, масштабируемых и безопасных информационных систем.

Ловушка замыканий: Почему ваши лямбды в цикле сломаны (Late Binding) Вы пишете код, который генерирует список функций (например, колбэки для кнопок в UI или динамические фильтры). Кажется, что все логично, но на выходе получаете сюрприз. Проблемный код:

# Хотим создать 3 функции, которые возвращают 0, 1 и 2 соответственно
funcs = []
for i in range(3):
    funcs.append(lambda: i)

# Проверяем
results = [f() for f in funcs]
print(results) 
# Ожидание: [0, 1, 2]
# Реальность: [2, 2, 2]

Почему так происходит? Это называется Late Binding (позднее связывание). В Python замыкания (closures) захватывают переменные по ссылке, а не по значению. Когда вы объявляете lambda: i, Python не сохраняет текущее число 0, 1 или 2. Он сохраняет инструкцию: «когда меня вызовут, пойди в локальную область видимости, найди переменную с именем i и возьми ее значение». К моменту, когда вы начинаете вызывать функции из списка results, цикл for уже завершился. Переменная i в этой области видимости навсегда осталась равной 2. Все три лямбды смотрят на одну и ту же переменную i. Как лечить? Есть два каноничных способа заставить Python запомнить значение «здесь и сейчас». 1. Аргумент по умолчанию (Hack way) Значения аргументов по умолчанию вычисляются в момент определения функции.

funcs = []
for i in range(3):
    # i=i создает локальную переменную i внутри функции 
    # и присваивает ей текущее значение i из цикла
    funcs.append(lambda i=i: i) 

Это работает быстро, но выглядит немного грязно и может сбить с толку линтеры или коллег. 2. functools.partial (Enterprise way) Более чистый и явный способ. partial создает новый callable-объект, «замораживая» переданные аргументы.

from functools import partial

funcs = []
for i in range(3):
    # Здесь значение i фиксируется жестко
    funcs.append(partial(lambda x: x, i))

Где это стреляет в реальной жизни? - Генерация command для кнопок в Tkinter/PyQt. - Динамическое создание task в asyncio циклах. - Патчинг тестов в циклах. Не дайте переменным пережить свое время. #python #internals #functionalprogramming #gotchas 📲 Мы в MAX 👉@BookPython

Профилируем Python в продакшене: почему cProfile не подходит, и чем хорош py-spy Когда на проде начинает течь память или скачет CPU, первая мысль, подключить профайлер. Стандартный cProfile, это детерминированный профайлер. Он хукает каждый вызов функции. 📉 Цена: Оверхед может замедлить приложение в 2-5 раз. На нагруженном проде это означает добить сервис окончательно. Для Live-систем нужен Sampling Profiler (сэмплирующий профайлер). Золотой стандарт сейчас - py-spy. Как это работает? py-spy написан на Rust. Он работает как внешний процесс, который читает память вашего Python-процесса (через системные вызовы, аналогично gdb). Он делает «снимки» стека вызовов с высокой частотой (по дефолту 100 раз в секунду). ✅ Результат: Оверхед стремится к нулю. Код инструментализировать не нужно. Рестарт сервиса не нужен. Два главных режима работы: 1. Live View (как htop, но для функций) Посмотреть в реальном времени, в каких функциях процесс проводит больше всего времени.

# Нужно только знать PID процесса
py-spy top --pid 12345

Вы увидите список функций, отсортированный по OwnTime (время внутри функции) и TotalTime (время с учетом дочерних вызовов). 2. Flame Graph (Огненный граф) Для глубокого анализа лучше записать работу сервиса за период и визуализировать стек.

py-spy record -o profile.svg --pid 12345 --duration 60

Вы получите SVG-файл. Чем шире полоска, тем больше времени занимает функция. Вертикаль - это глубина стека. Сразу видно, кто «съел» процессорное время. Нюансы для Middle+: - GIL: py-spy умеет показывать, держит ли функция GIL. Добавьте флаг --gil. - Docker/K8s: Так как py-spy использует системный вызов ptrace, контейнеру нужны привилегии. В Kubernetes часто нужно добавить securityContext: capabilities: add: ["SYS_PTRACE"] подам, чтобы иметь возможность профилировать их на лету. #profiling #optimization #pyspy #debugging #python 📲 Мы в MAX 👉@BookPython

Локальное окружение для начинающего ML-инженера ML начинается с окружения. Разберём настройку Python-окружения, виртуальных с
Локальное окружение для начинающего ML-инженера ML начинается с окружения. Разберём настройку Python-окружения, виртуальных сред, Jupyter и VS Code, а также структуру ML-проекта и управление зависимостями. 📌22 января в 18:00 МСК Открытый урок курса «Machine Learning» Зарегистрироваться: https://vk.cc/cTC0sV Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

📌 Декораторы в Python: как они работают и зачем нужны? Сегодня я покажу вам, как работают декораторы в Python и зачем они вообще нужны. Декораторы позволяют изменять поведение функций без изменения их кода. Они широко применяются в логировании, кешировании, управлении доступом и многом другом. Допустим, у нас есть функция, которая просто выводит «Hello, world!»:

def greet():
    print("Hello, world!")
Теперь мы хотим, чтобы перед выполнением этой функции выполнялся какой-то код, например, логирование. Вместо изменения greet(), мы создадим декоратор:

def log_decorator(func):
    def wrapper():
        print(f"Вызов функции {func.__name__}")
        return func()
    return wrapper
И теперь используем его:

@log_decorator
def greet():
    print("Hello, world!")

greet()
👉 Вывод:
Вызов функции greet
Hello, world!
Как это работает? 1. Декоратор принимает функцию (func) в качестве аргумента. 2. Внутри создаётся вложенная функция wrapper(), которая выполняет дополнительную логику перед вызовом func(). 3. wrapper() возвращается вместо func, фактически подменяя её. Можно даже передавать аргументы в декорируемую функцию:

def log_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"Вызов {func.__name__} с аргументами: {args}, {kwargs}")
        return func(*args, **kwargs)
    return wrapper

@log_decorator
def add(a, b):
    return a + b

print(add(3, 5))
👉 Вывод:
Вызов add с аргументами: (3, 5), {}
8
🔥 Декораторы это мощный инструмент, который делает код чище и удобнее. Если ещё не использовали их в проектах, самое время попробовать! А какие декораторы вы используете в своих проектах? Делитесь в комментариях! ⬇️ 📲 Мы в MAX 👉@BookPython

🐍 Как улучшить читаемость кода в Python? Читаемый код - это не роскошь, а необходимость. Если ваш код трудно понять, даже если он работает, это плохой код. Сегодня разберем несколько простых, но мощных приемов, которые сделают ваш код более понятным. 1️⃣ Используйте говорящие имена переменных Плохой пример:

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]
Чище и лаконичнее! Читаемый код делает разработку приятнее, ускоряет исправление багов и упрощает поддержку. Напишите в комментариях, какие еще приемы вы используете для улучшения читаемости кода! 👇 📲 Мы в MAX 👉@BookPython

Pydantic V2: Забываем root_validator, используем model_validator правильно Переход на Pydantic V2, это не только ускорение за счет ядра на Rust, но и переосмысление валидации. Самая частая боль при миграции, проверка зависимостей между несколькими полями. В V1 мы использовали root_validator и работали со словарем values (прощай, автодополнение IDE). В V2 правильный путь - model_validator в режиме after. В чем соль? В режиме mode='after' валидация запускается после того, как поля были распаршены и приведены к типам. Вы работаете с экземпляром класса (self), а не с сырым словарем. Пример (валидация периода дат):

from pydantic import BaseModel, model_validator
from datetime import datetime

class DateRange(BaseModel):
    start_dt: datetime
    end_dt: datetime

    @model_validator(mode='after')
    def check_dates_order(self):
        # Обращаемся через self — IDE видит поля и их типы!
        if self.end_dt <= self.start_dt:
            raise ValueError("Дата окончания должна быть позже начала")
        return self

# Тест
try:
    DateRange(
        start_dt="2024-01-01T12:00:00", 
        end_dt="2023-01-01T12:00:00"
    )
except ValueError as e:
    print(e)

Нюансы для профи: 1. mode='before': Используйте только если вам нужно модифицировать сырые входные данные (например, JSON) до того, как Pydantic начнет их парсить. Это аналог pre=True из V1. 2. Производительность: Валидаторы на Python, это узкое горлышко. Если у вас HighLoad, старайтесь выразить ограничения через Field (например, ge, le), так как они отрабатывают на Rust-уровне, что значительно быстрее вызова python-функции. Используйте возможности типизации на 100%. #pydantic #fastapi #bestpractices #python 📲 Мы в MAX 👉@BookPython

🦾 Чем реально отличается Senior ML от уверенного Middle? На открытом вебинаре разберём продвинутые методы машинного обучения
🦾 Чем реально отличается Senior ML от уверенного Middle? На открытом вебинаре разберём продвинутые методы машинного обучения, о которых обычно говорят вскользь или не говорят вовсе. Рекомендательные системы, временные ряды, reinforcement learning, GenAI, байесовские подходы и деплой моделей в прод: где и зачем они применяются сегодня и почему без них невозможно расти дальше в профессии. Это честный разговор о том, какие навыки действительно ценятся на уровне Senior, какие задачи решают специалисты ML Advanced и какие карьерные возможности открываются после перехода на эту ступень. Вы сможете задать любые вопросы и получить ответы от эксперта. 📋 Встречаемся 28 января в 18:00 МСК в преддверии старта курса «Machine Learning. Advanced». Регистрация открыта: https://vk.cc/cTo0ZX Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

Списковые включения (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)
]
Можно также добавлять условия 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)
]
📲 Мы в MAX 👉@BookPython

Structured Concurrency в Python 3.11+ (TaskGroup vs Gather) Если вы до сих пор используете asyncio.gather() для запуска конкурентных задач, вы, вероятно, теряете контроль над ошибками. Главная проблема gather: если одна таска падает, остальные продолжают работать (если не стоит return_exceptions=False, который убивает всё сразу, но "грязно"). Плюс, отлавливать несколько ошибок одновременно через try / except - это боль. В Python 3.11+ (и через trio / anyio раньше) стандартом стала Structured Concurrency через asyncio.TaskGroup. Как это выглядит:

import asyncio

async def task_fail(name, sec):
    await asyncio.sleep(sec)
    raise ValueError(f"Error in {name}")

async def task_ok(name, sec):
    await asyncio.sleep(sec)
    print(f"Task {name} done")

async def main():
    try:
        async with asyncio.TaskGroup() as tg:
            tg.create_task(task_ok("A", 1))
            tg.create_task(task_fail("B", 2)) # Упадет через 2 сек
            tg.create_task(task_fail("C", 1.5)) # Упадет через 1.5 сек
            
    except* ValueError as eg: 
        # Обратите внимание на except* (ExceptionGroup)
        print(f"Caught errors: {eg.exceptions}")

# Запуск
# asyncio.run(main())

Почему TaskGroup это выбор Middle+: 1. Атомарность скоупа: Если одна задача внутри контекстного менеджера падает, TaskGroup автоматически отменяет (cancel) все остальные запущенные задачи в группе. Вы не оставляете "зомби-процессы" в фоне. 2. Exception Groups: Если упало несколько задач одновременно (или во время отмены), Python соберет их в ExceptionGroup. Конструкция except* позволяет элегантно обрабатывать дерево исключений. Вывод: Для скриптов gather сойдет. Для надежных сервисов, где важна консистентность состояния и корректный шатдаун корутин - переезжайте на TaskGroup. #asyncio #python311 #bestpractices #concurrency 📲 Мы в MAX 👉@BookPython

Оптимизация SQL-запросов в Django ORM Сегодня я покажу вам, как оптимизировать SQL-запросы в Django ORM, чтобы ваш код работал быстрее и эффективнее. Если ваш Django-проект начал тормозить, скорее всего, проблема в количестве и сложности запросов к базе данных. 1️⃣ Используйте select_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-приложение и уменьшить нагрузку на базу данных. А вы уже используете их в своих проектах? Делитесь в комментариях! 👇 📲 Мы в MAX 👉@BookPython

Почему при зарплате 400к денег всё равно нет? Замечал, как люди с доходом 80к умудряются копить на отпуск и покупать айфоны? А у многих айтишников при 300-400к — в конце месяца ноль. Знакомо? Есть 5 конкретных причин, почему так происходит при высоком доходе. Снял видео — разбираю каждую. 5 минут, без воды. Посмотри, возможно узнаешь себя или коллег! Смотреть #реклама 16+ sbsite.pro О рекламодателе

Оптимизация кода с помощью генераторов в Python Сегодня хочу показать вам, как использование генераторов может сделать ваш код быстрее, экономнее по памяти и элегантнее. Что такое генераторы? Генераторы — это функции, которые используют yield вместо 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) ✔️ Работа с потоками данных ✔️ Генерация последовательностей без создания списков 📲 Мы в MAX 👉@BookPython

Python поддерживает несколько способов запуска скрипта. Обычный вариант — это python 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__
📲 Мы в MAX 👉@BookPython

Модуль io предоставляет два типа файловых объектов в памяти. Такие объекты могут быть полезны для работы с интерфейсами, которые поддерживают только файлы, без необходимости создавать их на диске. Очевидный пример — модульное тестирование. Эти два типа — 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'
📲 Мы в MAX 👉@BookPython

Продвижение в Telegram с помощью Яндекс Директа ⚡Запустите продвижение в телеграм-каналах и привлекайте целевую аудиторию 📱
+3
Продвижение в Telegram с помощью Яндекс Директа ⚡Запустите продвижение в телеграм-каналах и привлекайте целевую аудиторию 📱 Таргетинг по тематикам, регионам и каналам в Telegram Попробовать #реклама yandex.ru О рекламодателе

Если вам нужно итерироваться по нескольким итерируемым объектам одновременно, функция 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 принимает итерируемые объекты как отдельные аргументы, а не список аргументов. Для распаковки значений можно использовать оператор *:

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

list позволяет хранить массив из любых объектов. Это довольно удобно, но может быть неэффективно. Для компактного представления массивов базовых значений можно использовать модуль 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'))  # Выводит: '🐴'
📲 Мы в MAX 👉@BookPython

Когда в Python используется переменная, сначала она ищется в текущей области видимости. Если такая переменная не найдена, поиск продолжается во вложенной области. Это повторяется до тех пор, пока не будет достигнуто глобальное пространство имен.

x = 1
def scope():
    x = 2
    def inner_scope():
        print(x)  # выводит 2
    inner_scope()
scope()
Однако присваивание переменной работает иначе. Новая переменная всегда создается в текущей области видимости, если не указано global или nonlocal:

x = 1
def scope():
    x = 2
    def inner_scope():
        x = 3
        print(x)  # выводит 3
    inner_scope()
    print(x)  # выводит 2
scope()
print(x)  # выводит 1
global позволяет использовать переменные из глобального пространства имен, а nonlocal ищет переменную в ближайшей окружающей области видимости. Сравните:

x = 1
def scope():
    x = 2
    def inner_scope():
        global x
        x = 3
        print(x)  # выводит 3
    inner_scope()
    print(x)  # выводит 2
scope()
print(x)  # выводит 3

x = 1
def scope():
    x = 2
    def inner_scope():
        nonlocal x
        x = 3
        print(x)  # выводит 3
    inner_scope()
    print(x)  # выводит 3
scope()
print(x)  # выводит 1
📲 Мы в MAX 👉@BookPython