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

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

Open in Telegram

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

Show more

📈 Analytical overview of Telegram channel Библиотека Python разработчика | Книги по питону

Channel Библиотека Python разработчика | Книги по питону (@bookpython) in the Russian language segment is an active participant. Currently, the community unites 18 329 subscribers, ranking 7 317 in the Technologies & Applications category and 36 872 in the Russia region.

📊 Audience metrics and dynamics

Since its creation on невідомо, the project has demonstrated rapid growth, gathering an audience of 18 329 subscribers.

According to the latest data from 05 June, 2026, the channel demonstrates stable activity. Although there has been a change in the number of participants by -86 over the last 30 days and by -1 over the last 24 hours, overall reach remains high.

  • Verification status: Not verified
  • Engagement rate (ER): The average audience engagement rate is 6.08%. Within the first 24 hours after publication, content typically collects 2.60% reactions from the total number of subscribers.
  • Post reach: On average, each post receives 1 114 views. Within the first day, a publication typically gains 477 views.
  • Reactions and interaction: The audience actively supports content: the average number of reactions per post is 2.
  • Thematic interests: Content is focused on key topics such as numbers, yield, модуль, none, декоратор.

📝 Description and content policy

The author describes the resource as a platform for expressing subjective opinions:
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq

Thanks to the high frequency of updates (latest data received on 07 June, 2026), the channel maintains relevance and a high level of publication reach. Analytics show that the audience actively interacts with content, making it an important point of influence in the Technologies & Applications category.

18 329
Subscribers
-124 hours
-277 days
-8630 days
Posts Archive
В Python множества поддерживают операторы сравнения, где a < b означает, что a является подмножеством b:

>>> {1} < {1, 2}
True
>>> {1} < {2, 3}
False
Это означает, что множества частично упорядочены, то есть существуют такие a и b, что и a < b, и b < a — ложны:

>>> {1} < {2, 3}
False
>>> {1} > {2, 3}
False
Некоторые функции, такие как min, max и sorted, требуют полного порядка, поэтому их применение к списку множеств может дать неожиданные результаты:

>>> min([{1}, {2}])
{1}
>>> min([{2}, {1}])
{2}
👉@BookPython

Дарим подписку на Яндекс Музыку Ответьте на 1 вопрос и Яндекс Музыка для вас и 3-х ваших близких 30 дней бесплатно. Кинопоиск
Дарим подписку на Яндекс Музыку Ответьте на 1 вопрос и Яндекс Музыка для вас и 3-х ваших близких 30 дней бесплатно. Кинопоиск и Яндекс Книги тоже в подписке. Попробуйте сейчас❤️ Попробовать #реклама 18+ music.yandex.ru О рекламодателе Реклама на Яндексе

С версии Python 3.0 выбрасывание исключения внутри блока except автоматически добавляет перехваченное исключение в атрибут __context__ нового исключения. Это приводит к тому, что оба исключения отображаются в traceback:

try:
    1 / 0
except ZeroDivisionError:
    raise ValueError('Zero!')
Результат выполнения:

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    1 / 0
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    raise ValueError('Zero!')
ValueError: Zero!
Вы также можете добавить __cause__ к любому исключению с помощью выражения raise ... from:

division_error = None

try:
    1 / 0
except ZeroDivisionError as e:
    division_error = e

raise ValueError('Zero!') from division_error
Результат выполнения:
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    1 / 0
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "test.py", line 8, in <module>
    raise ValueError('Zero!') from division_error
ValueError: Zero!
👉@BookPython

Прямой доступ к атрибутам объекта может быть не самой лучшей идеей. Если клиенты взаимодействуют с объектом через методы, вы всегда можете изменить способ обработки каждого запроса, в то время как при прямом доступе к атрибутам это может быть невозможно. Разные языки решают эту проблему по-разному. В Ruby синтаксически невозможно получить прямой доступ к атрибуту: obj.x — это вызов метода x. В Java рекомендуется делать все атрибуты приватными и писать тривиальные геттеры, например: public int getX() { return this.x; }. Python предлагает решение, которое в некотором роде похоже на то, что есть в Ruby. Вы можете определить свойство (`property`), чтобы obj.x вызывал метод вместо прямого возврата атрибута x.

class Example:
    def __init__(self, x):
        self._x = x

    @property
    def x(self):
        return self._x
👉@BookPython

Конкурс! Начинаем год с подарков от Actibo После праздников не всегда легко вернуться к работе, поэтому предлагаем вам немног
Конкурс! Начинаем год с подарков от Actibo После праздников не всегда легко вернуться к работе, поэтому предлагаем вам немного взбодриться. ✨Разыгрываем три ящика энергетических напитков Actibo, по 12 баночек в каждом. Переходи по ссылке к розыгрышу и выполняй условия. Узнать больше #реклама О рекламодателе

Рассмотрим следующую иерархию классов:

class GrandParent:
    pass

class Parent1(GrandParent):
    pass

class Parent2(GrandParent):
    pass

class Child(Parent1, Parent2):
    pass
В каком порядке будет производиться поиск метода Child.x()? Наивный подход заключается в рекурсивном поиске через все родительские классы, что даст порядок: Child, Parent1, GrandParent, Parent2. Такой метод используется во многих языках программирования, однако он не совсем логичен, так как Parent2 более специфичен, чем GrandParent, и его нужно проверять раньше. Чтобы исправить эту проблему, Python использует линеаризацию C3 (C3 superclass linearization), алгоритм, который всегда ищет метод сначала во всех дочерних классах, а затем уже в родительских. Пример вывода MRO (Method Resolution Order):

In : Child.__mro__
Out:
(__main__.Child,
 __main__.Parent1,
 __main__.Parent2,
 __main__.GrandParent,
 object)
👉@BookPython

Сочи, в продаже студия с ремонтом, ипотека без ПВ! - 9 мин до моря – строительство по ФЗ-214 – вид на горы – пятиэтажный паркинг – благоустроенная территория – школа и детский сад на территории Квартиры от 18м² доступные в: ✅ ипотеку (возможна программа без первоначального взноса ✅ беспроцентную рассрочку ✅ материнский капитал Оставь телефон чтобы узнать цену! Узнать цену Финансовые услуги оказывает: ПАО Банк ВТБ, ПАО "Совкомбанк". #реклама mrqz.me О рекламодателе

Обе конструкции for и with могут быть асинхронными. async with использует магические методы __aenter__ и __aexit__, а async for — методы __aiter__ и __anext__. Все они асинхронные, и внутри них можно использовать await:

import asyncio

class Sleep:
    def __init__(self, t):
        self._t = t

    async def __aenter__(self):
        await asyncio.sleep(self._t / 2)

    async def __aexit__(self, *args):
        await asyncio.sleep(self._t / 2)

async def main():
    async with Sleep(2):
        print('*')

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Когда вы реализуете метод __iter__, часто вместо написания итератора с методом __next__ используется оператор yield, который делает метод __iter__ генератором:

class Bracketed:                  
    def __init__(self, data):     
        self._data = data         
                                  
    def __iter__(self):           
        for x in self._data:      
            yield '({})'.format(x)
                                  
print(list(Bracketed([1, 2, 3]))) 
# ['(1)', '(2)', '(3)']
PEP 525 позволяет делать то же самое с методом __aiter__. Наличие операторов yield и await в теле функции делает её асинхронным генератором. В то время как await используется для взаимодействия с циклом событий, yield управляет работой с for:

import asyncio                          
                                        
class Slow:                             
    def __init__(self, data, t=1):      
        self._data = data               
        self._t = t                     
                                        
    async def __aiter__(self):          
        for x in self._data:            
            await asyncio.sleep(self._t)
            yield x                     
                                        
async def main():                       
    async for x in Slow([1, 2, 3]):     
        print(x)                        
                                        
loop = asyncio.get_event_loop()         
loop.run_until_complete(main())
👉@BookPython

. Пожалуйста,не игнорируйте наше приглашение! Сегодня мы хотим поделиться с вами полезной подборкой каналов которые могут быть вам полезны Скорее выбирайте категорию: Срок действия приглашений всего 1 час! ✅Вяжем шапки,варежки,свитера - t.me/+Hdmk0q50F2pkZTQy ✅АМИГУРУМИ-Вяжем игрушки- t.me/+VmvP1ECGDHxkODA6 ✅ Вязание(видео-уроки)- t.me/+m6L00g4STpszYWJi ✅Вяжем детям- t.me/+ksSjU7lzERw0MzYy ✅Вязание для новичков- t.me/+0sfy52JoKXExODZi Вяжем носочки- t.me/+HFXLXcKLa0cwMWMy Вязание крючком- t.me/+uPHYFp-PVuFkOTIy Вязание спицами- t.me/+9hwOHqLS0VA3ZjRi Узоры крючком- t.me/+DL6dsn4DQGsyNTRi Узоры спицами- t.me/+iwAtESzRlnw2ZjAy Схемы вязания- t.me/+wMa55NfPqWoxOWVi Бесплатные выкройки,уроки шитья - t.me/+NDrsreeCCEIwM2Qy Шитье для новичков- t.me/+472nw5vr3b05ZDgy Узнать больше #реклама О рекламодателе

Если вы хотите передать данные по цепочке вызовов, самый простой способ — использовать аргументы функций. Однако в некоторых случаях модифицировать все функции в цепочке, чтобы передать новые данные, крайне неудобно. Вместо этого вы можете настроить некоторый контекст, который будет доступен для всех функций по цепочке. Как это можно реализовать технически? Самое простое решение — глобальная переменная. В Python также можно использовать модули и классы как хранилища контекста, так как они, строго говоря, тоже являются глобальными переменными. Вы, вероятно, делаете это ежедневно, например, для работы с логгерами. Если ваше приложение многопоточное, обычная глобальная переменная не подойдет, так как она не является потокобезопасной. Одновременно может выполняться несколько цепочек вызовов, и каждая из них нуждается в собственном контексте. Модуль threading решает эту проблему с помощью объекта threading.local(), который является потокобезопасным. Вы можете хранить данные, просто устанавливая атрибуты, например: threading.local().symbol = '@'. Но оба этих подхода не подходят для асинхронных приложений, где функции не только вызываются, но и могут быть приостановлены с помощью await. Если корутина выполняет await, цикл событий может переключиться на другую корутину из совершенно другой цепочки вызовов. Это приведет к некорректной работе, как в следующем примере:

import asyncio
import sys

global_symbol = '.'

async def indication(timeout):
    while True:
        print(global_symbol, end='')
        sys.stdout.flush()
        await asyncio.sleep(timeout)

async def sleep(t, indication_t, symbol='.'):
    loop = asyncio.get_event_loop()

    global global_symbol
    global_symbol = symbol
    loop.create_task(indication(indication_t))
    await asyncio.sleep(t)

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(
    sleep(1, 0.1, '0'),
    sleep(1, 0.1, 'a'),
    sleep(1, 0.1, 'b'),
    sleep(1, 0.1, 'c'),
))
Решить эту проблему можно, если цикл событий будет устанавливать и восстанавливать контекст каждый раз, когда он возобновляет выполнение корутины. Модуль aiotask_context реализует это, изменяя способ создания задач с помощью loop.set_task_factory. Пример рабочей версии:

import asyncio                                
import sys                                    
import aiotask_context as context             
                                              
async def indication(timeout):                
    while True:                               
        print(context.get('symbol'), end='')  
        sys.stdout.flush()                    
        await asyncio.sleep(timeout)          
                                              
async def sleep(t, indication_t, symbol='.'): 
    loop = asyncio.get_event_loop()           
                                              
    context.set(key='symbol', value=symbol)   
    loop.create_task(indication(indication_t))
    await asyncio.sleep(t)                    
                                              
loop = asyncio.get_event_loop()               
loop.set_task_factory(context.task_factory)   
loop.run_until_complete(asyncio.gather(       
    sleep(1, 0.1, '0'),                       
    sleep(1, 0.1, 'a'),                       
    sleep(1, 0.1, 'b'),                       
    sleep(1, 0.1, 'c'),                       
))
👉@BookPython

Когда корутина asyncio хочет остановиться и взаимодействовать с циклом событий (event loop), она использует await obj (или yield from obj до Python 3.6). Объект obj должен быть другой корутиной, объектом asyncio.Future или любым пользовательским объектом, похожим на Future (любой объект, у которого определен метод __await__).

async def coroutine():
    await another_coroutine()

async def another_coroutine():
    future = asyncio.Future()
    await future

loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine())
Когда корутина ожидает (await) другую корутину, вторая начинает выполняться вместо первой. Если она ожидает третью, то выполняется третья. Это продолжается до тех пор, пока какая-нибудь корутина не ожидает объект Future. Объект Future фактически возвращает значение, и тогда цикл событий (event loop) получает управление. Какое значение возвращает Future? Оно возвращает сам себя. Можете ли вы напрямую использовать yield для Future? Нет, это внутренняя деталь, о которой вам обычно не нужно беспокоиться.

class Awaitable:
    def __await__(self):
        future = asyncio.Future()
        yield future
            # RuntimeError: yield was used
            # instead of yield from in task

async def coroutine():
    await Awaitable()

loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine())
Почему возникает эта ошибка? Как asyncio понимает, что это вы используете yield для Future, а не сам Future? Есть простая защита: Future устанавливает внутренний флаг перед тем, как вернуть управление. 👉@BookPython

Ну не умею я красиво одеваться! Давай научу, выбирай свой возраст: Мне 18-25 лет - t.me/+brfkWSTU5XsyZjFi Мне 26-35 лет - t.m
Ну не умею я красиво одеваться! Давай научу, выбирай свой возраст: Мне 18-25 лет - t.me/+brfkWSTU5XsyZjFi Мне 26-35 лет - t.me/+d7jHTPt6NMBhNTRi Мне 36-45 лет - t.me/+pAX1bYlEPzVjZWVi Мне 46-55 лет - t.me/+HryLmBlZHJ4wZjQy Мне 56-65 лет - t.me/+Z-41IQXIxvA2NzJi Мне 70+ лет - t.me/+XrP_rFNe6EE2NzQy Тут нет моего возраста - t.me/+jrBV7m8bYQIwNTEy Узнать больше #реклама О рекламодателе

Иногда вам нужно запустить блок кода с несколькими контекстными менеджерами. Например:

with open('f') as f:
    with open('g') as g:
        with open('h') as h:
            pass
Начиная с Python 2.7 и 3.1, это можно сделать с помощью одного выражения with:

o = open
with o('f') as f, o('g') as g, o('h') as h:
    pass
До этого можно было использовать функцию contextlib.nested:

with nested(o('f'), o('g'), o('h')) as (f, g, h):
    pass
Однако в современных версиях Python эта функция устарела и вызывает предупреждение. Вместо неё рекомендуется использовать более продвинутый инструмент — contextlib.ExitStack. Он позволяет войти в любое количество контекстов в произвольное время, но гарантирует их корректное завершение:

from contextlib import ExitStack

with ExitStack() as stack:
    f = stack.enter_context(o('f'))
    g = stack.enter_context(o('g'))
    other = [
        stack.enter_context(o(filename))
        for filename in filenames
    ]
Это особенно полезно, когда количество контекстных менеджеров неизвестно заранее. 👉@BookPython

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

In : lion = 'Löwe'
In : lion.encode('utf-8')[2:]
Out: b'\xb6we'
In : lion.encode('utf-8')[2:].decode('utf-8')
...
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb6 in position 0: invalid start byte
Также это означает, что для пропуска первых N символов строки их необходимо прочитать и декодировать. Рассчитать смещение заранее невозможно. Однако можно пропустить фиксированное количество байтов, принимая во внимание некоторые особенности. Вот как может быть закодирован символ в UTF-8:

0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
Как видно, байт является начальным байтом символа, если его вид не совпадает с 10xxxxxx. Такие байты называются продолжением символа (continuation bytes). Давайте пропустим их:

def cut_bytes(s, n):
    result = s.encode('utf-8')[n:]
    mask = int('11000000', 2)
    conbyte = int('10000000', 2)
    while result[0] and result[0] & mask == conbyte:
        result = result[1:]

    return result.decode('utf-8')
Пример использования:

In : cut_bytes(lion, 2)
Out: 'we'
In : cut_bytes(lion, 1)
Out: 'öwe'
👉@BookPython

Скидки до 70% в Rendez-Vous На сайте Rendez-Vous стартовала финальная распродажа!✨ До конца января у вас есть уникальная возможность приобрести качественную обувь и одежду со скидками до 70%! Это шанс пополнить гардероб элегантными и удобными моделями по выгодным ценам❤️ А еще действует скидка +10% при покупке трех и более товаров и категории обувь, сумки и одежда (кроме топов, маек и футболок). Переходите по ссылке и выбирайте. Перейти на сайт #реклама rendez-vous.onelink.me О рекламодателе

Соединять части пути к файлу удобно с помощью функции os.path.join:

In : dir_path = '/home/vadim/'
In : file_name = 'test.py'
In : os.path.join(dir_path, file_name)
Out: '/home/vadim/test.py'
Это обычно лучше, чем использование строковой конкатенации:

In : dir_path + '/' + file_name
Out: '/home/vadim//test.py'
os.path.join использует правильный разделитель для текущей платформы (например, \ для Windows) и предотвращает появление двойного разделителя (//). Начиная с Python 3.4, можно использовать класс Path из модуля pathlib. (С версии Python 3.6 его экземпляры также можно передавать в os.path.join.) Класс Path поддерживает объединение путей через оператор /:

In : Path('/home/vadim/') / Path('test.py')
Out: PosixPath('/home/vadim/test.py')
👉@BookPython

Дарим подписку на Яндекс Музыку Ответьте на 1 вопрос и Яндекс Музыка для вас и 3-х ваших близких 30 дней бесплатно. Кинопоиск
Дарим подписку на Яндекс Музыку Ответьте на 1 вопрос и Яндекс Музыка для вас и 3-х ваших близких 30 дней бесплатно. Кинопоиск и Яндекс Книги тоже в подписке. Попробуйте сейчас❤️ Попробовать #реклама 18+ music.yandex.ru О рекламодателе Реклама на Яндексе

Подборка Telegram каналов для программистов Системное администрирование 📌 https://t.me/sysadmin_girl Девочка Сисадмин https://t.me/srv_admin_linux Админские угодья https://t.me/linux_srv Типичный Сисадмин https://t.me/linux_odmin Linux: Системный администратор https://t.me/devops_star DevOps Star (Звезда Девопса) https://t.me/i_linux Системный администратор https://t.me/linuxchmod Linux https://t.me/sys_adminos Системный Администратор https://t.me/tipsysdmin Типичный Сисадмин (фото железа, было/стало) https://t.me/sysadminof Книги для админов, полезные материалы https://t.me/i_odmin Все для системного администратора https://t.me/i_odmin_book Библиотека Системного Администратора https://t.me/i_odmin_chat Чат системных администраторов https://t.me/i_DevOps DevOps: Пишем о Docker, Kubernetes и др. https://t.me/sysadminoff Новости Линукс Linux 1C разработка 📌 https://t.me/odin1C_rus Cтатьи, курсы, советы, шаблоны кода 1С Программирование C++📌 https://t.me/cpp_lib Библиотека C/C++ разработчика https://t.me/cpp_knigi Книги для программистов C/C++ https://t.me/cpp_geek Учим C/C++ на примерах Программирование Python 📌 https://t.me/pythonofff Python академия. Учи Python быстро и легко🐍 https://t.me/BookPython Библиотека Python разработчика https://t.me/python_real Python подборки на русском и английском https://t.me/python_360 Книги по Python Rus Java разработка 📌 https://t.me/BookJava Библиотека Java разработчика https://t.me/java_360 Книги по Java Rus https://t.me/java_geek Учим Java на примерах GitHub Сообщество 📌 https://t.me/Githublib Интересное из GitHub Базы данных (Data Base) 📌 https://t.me/database_info Все про базы данных Мобильная разработка: iOS, Android 📌 https://t.me/developer_mobila Мобильная разработка https://t.me/kotlin_lib Подборки полезного материала по Kotlin Фронтенд разработка 📌 https://t.me/frontend_1 Подборки для frontend разработчиков https://t.me/frontend_sovet Frontend советы, примеры и практика! https://t.me/React_lib Подборки по React js и все что с ним связано Разработка игр 📌 https://t.me/game_devv Все о разработке игр Библиотеки 📌 https://t.me/book_for_dev Книги для программистов Rus https://t.me/programmist_of Книги по программированию https://t.me/proglb Библиотека программиста https://t.me/bfbook Книги для программистов https://t.me/books_reserv Книги для программистов БигДата, машинное обучение 📌 https://t.me/bigdata_1 Data Science, Big Data, Machine Learning, Deep Learning Программирование 📌 https://t.me/bookflow Лекции, видеоуроки, доклады с IT конференций https://t.me/coddy_academy Полезные советы по программированию https://t.me/rust_lib Полезный контент по программированию на Rust https://t.me/golang_lib Библиотека Go (Golang) разработчика https://t.me/itmozg Программисты, дизайнеры, новости из мира IT https://t.me/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 https://t.me/nodejs_lib Подборки по Node js и все что с ним связано https://t.me/ruby_lib Библиотека Ruby программиста QA, тестирование 📌 https://t.me/testlab_qa Библиотека тестировщика Шутки программистов 📌 https://t.me/itumor Шутки программистов Защита, взлом, безопасность 📌 https://t.me/thehaking Канал о кибербезопасности https://t.me/xakep_1 Статьи из "Хакера" Книги, статьи для дизайнеров 📌 https://t.me/ux_web Статьи, книги для дизайнеров Английский 📌 https://t.me/UchuEnglish Английский с нуля Математика 📌 https://t.me/Pomatematike Канал по математике https://t.me/phis_mat Обучающие видео, книги по Физике и Математике Excel лайфхак📌 https://t.me/Excel_lifehack https://t.me/tikon_1 Новости высоких технологий, науки и техники💡 https://t.me/mir_teh Мир технологий (Technology World) Вакансии 📌 https://t.me/sysadmin_rabota Системный Администратор https://t.me/progjob Вакансии в IT

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

In : format(0.1, '.17f')
Out: '0.10000000000000001'
Модуль decimal позволяет использовать десятичную арифметику с произвольной точностью:

In : Decimal(1) / Decimal(3)
Out: Decimal('0.3333333333333333333333333333')
Однако и этого может быть недостаточно:

In [61]: Decimal(1) / Decimal(3) * Decimal(3) == Decimal(1)
Out[61]: False
Для точных вычислений можно использовать fractions, где любое число хранится в виде рационального:

In : Fraction(1) / Fraction(3) * Fraction(3) == Fraction(1)
Out: True
Очевидным ограничением остается то, что иррациональные числа (например, π) все равно будут представлены только в приближенной форме. 👉@BookPython

Тесты могут требовать временные файлы или директории. Для этого отлично подойдет модуль tempfile. Так как временные файлы обычно нужно удалять после использования, tempfile предоставляет как контекстный менеджер, так и простые функции:

import os
import tempfile

with tempfile.TemporaryDirectory() as dir_path:
    open(os.path.join(dir_path, 'a'), 'w').close()
    open(os.path.join(dir_path, 'b'), 'w').close()
    open(os.path.join(dir_path, 'c'), 'w').close()

    assert files_of(dir_path) == ['a', 'b', 'c']
👉@BookPython