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

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

Kanalga Telegram’da o‘tish

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

Ko'proq ko'rsatish

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

Библиотека Python разработчика | Книги по питону (@bookpython) Rus til segmentidagi kanali faol ishtirokchi. Hozirda hamjamiyat 18 228 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 7 200-o'rinni va Rossiya mintaqasida 36 684-o'rinni egallagan.

📊 Auditoriya ko‘rsatkichlari va dinamika

невідомо sanasidan buyon loyiha tez o‘sib, 18 228 obunachiga ega bo‘ldi.

13 Iyul, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni -82 ga, so‘nggi 24 soatda esa 0 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.

  • Tasdiqlash holati: Tasdiqlanmagan
  • Jalb etish (ER): Auditoriya o‘rtacha 5.66% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 2.82% ini tashkil etuvchi reaksiyalarni to‘playdi.
  • Post qamrovi: Har bir post o‘rtacha 1 031 marta ko‘riladi; birinchi sutkada odatda 514 ta ko‘rish yig‘iladi.
  • Reaksiyalar va o‘zaro ta’sir: Auditoriya faol: har bir postga o‘rtacha 5 ta reaksiya keladi.
  • Tematik yo‘nalishlar: Kontent numbers, yield, модуль, none, декоратор kabi asosiy mavzularga jamlangan.

📝 Tavsif va kontent siyosati

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

Yuqori yangilanish chastotasi (oxirgi ma’lumot 14 Iyul, 2026 da olingan) sababli kanal doimo dolzarb va katta qamrovli bo‘lib qoladi. Analitika auditoriya kontent bilan faol hamkorlik qilishini, uni Texnologiyalar & Aralashmalar toifasidagi muhim ta’sir nuqtasiga aylantirishini ko‘rsatadi.

18 228
Obunachilar
Ma'lumot yo'q24 soatlar
-137 kunlar
-8230 kunlar
Postlar arxiv
Что такое контекстный менеджер в Python? Контекстный менеджер в Python - это специальный тип объекта, который определяет методы enter() и exit() и используется с инструкцией with. Эти объекты часто применяются в операциях, которые требуют установки и освобождения ресурсов.  Частый сценарий - это работа с файлом:

with open('file.txt', 'r') as file:
    data = file.read()
Здесь контекстный менеджер гарантирует, что файл будет корректно закрыт после завершения блока with, даже если при чтении файла возникнет исключение. Вот как можно написать простой контекстный менеджер самостоятельно:

import time
 
class Timer:
    def __enter__(self):
        self.start = time.time()
 
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.end = time.time()
        print(f'Время выполнения: {self.end - self.start:.2f} секунд')
 
with Timer():
    # код, время выполнения которого нужно измерить
    time.sleep(2)
📲 Мы в MAX 👉@BookPython

В Python вы можете переопределить оператор квадратных скобок ([]), определив магический метод getitem. Примером может быть объект Cycle, который виртуально содержит бесконечное количество повторяющихся элементов:

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])  # prints 'b'
Необычность здесь заключается в том, что оператор [] поддерживает уникальный синтаксис. Он может использоваться не только так — [2], но и так — [2:10], или [2:10:2], или [2::2], или даже [:]. Семантика — [start:stop:step], но вы можете применять её так, как вам нужно, для ваших собственных объектов. Но что же получает getitem в качестве параметра index, если использовать этот синтаксис? Для этого существуют объекты slice.

In : class Inspector:
...:     def __getitem__(self, index):
...:         print(index)
...:
In : Inspector()[1]
1
In : Inspector()[1:2]
slice(1, 2, None)
In : Inspector()[1:2:3]
slice(1, 2, 3)
In : Inspector()[:]
slice(None, None, None)
Вы даже можете комбинировать синтаксис кортежей и срезов:

In : Inspector()[:, 0, :]
(slice(None, None, None), 0, slice(None, None, None))
Slice не делает ничего, кроме как просто хранит атрибуты start, stop и step.

In : s = slice(1, 2, 3)
In : s.start
Out: 1
In : s.stop
Out: 2
In : s.step
Out: 3
📲 Мы в MAX 👉@BookPython

Вредные советы python разработчику l=[['a', 'b', 'c'], ['1', '2'], ['#']] sum(l, []) В Python можно выпрямить вложенные списк
Вредные советы python разработчику

l=[['a', 'b', 'c'], ['1', '2'], ['#']]
sum(l, [])
В Python можно выпрямить вложенные списки с помощью... функции sum(). Вот код (выполнять, пока никто не видит): Дело в том, что sum() принимает первым аргументом итерируемый объект, а вторым — значение, с которого начинается операция. По умолчанию это 0, но если указать пустой список [], то sum() начнёт с него. Затем sum() последовательно применяет операцию сложения к элементам первого аргумента, начиная со значения второго аргумента. В случае списков это означает конкатенацию. 📲 Мы в MAX 👉@BookPython

Функция enumerate Эта встроенная функция снабжает циклы счётчиком. Возвращает генераторный объект, который имеет метод, вызываемый встроенной функцией next: на каждом проходе цикла возвращает кортеж {индекс, значение}. Цикл for проходит по этим кортежам автоматически, что позволяет распаковывать их значения с помощью присваивания кортежей почти так, как в zip.

S = "stroka"

example = enumerate(S)
next(example) # -> (0, 's')
Пример использования:

shopping_list = ['яблоки', 'бананы', 'апельсины', 'хлеб']

for index, item in enumerate(shopping_list, start=1):
    print(f"Пункт {index}: {item}")
📲 Мы в MAX 👉@BookPython

Очередь с приоритетом — это структура данных, которая поддерживает две операции: добавление элемента и извлечение минимального из всех ранее добавленных элементов. Одной из самых распространённых реализаций очереди с приоритетом является бинарная куча. Это полное бинарное дерево со следующим свойством: ключ, хранящийся в каждом узле, меньше или равен (≤) ключам в дочерних узлах. Минимум всех элементов находится в корне такого дерева.




              1

      3               7

  5       4       9       8

15 16   17 18   19
В бинарной куче сложность операций вставки и извлечения составляет O(log n). Обычный способ хранения полного бинарного дерева в памяти — это массив, где дочерние элементы для x[i] находятся в x[2*i+1] и x[2*i+2].

[1, 3, 7, 5, 4, 9, 8, 15, 16, 17, 18, 19]
В Python нет бинарной кучи в виде класса, но предоставляется ряд функций, которые позволяют использовать список как бинарную кучу. Эти функции находятся в модуле heapq.

In [1]: from heapq import *
In [2]: heap = [3,2,1]
In [3]: heapify(heap)
In [4]: heap
Out[4]: [1, 2, 3]
In [5]: heappush(heap, 0)
In [6]: heap
Out[6]: [0, 1, 3, 2]
In [7]: heappop(heap)
Out[7]: 0
In [8]: heap
Out[8]: [1, 2, 3]
📲 Мы в MAX 👉@BookPython

Если вы хотите перехватить как IndexError, так и KeyError, вы можете и должны использовать LookupError, их общего предка. Это оказалось полезным при доступе к сложным вложенным данным.

try:
    db_host = config['databases'][0]['hosts'][0]
except LookupError:
    db_host = 'localhost'
📲 Мы в MAX 👉@BookPython

>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit
Вы когда-нибудь задумывались, почему при попытке выйти из интерактивного Python с помощью простого exit или quit появляется это сообщение? Решение довольно неожиданное, но изящное. Это не специальный случай для интерактивной оболочки, она просто показывает представление каждого вычисленного результата, а эта строка - просто представление функции exit. Строго говоря, вы не должны использовать exit в своих повседневных проектах, поскольку она была создана специально для интерактивной оболочки. Вместо этого используйте sys.exit(). 📲 Мы в MAX 👉@BookPython

Что такое «сырые» строки (Raw Strings) в Python? В Python "сырые" строки (или raw strings) — это строки, в которых символы об
Что такое «сырые» строки (Raw Strings) в Python? В Python "сырые" строки (или raw strings) — это строки, в которых символы обратного слэша \ воспринимаются буквально, а не как специальные символы (например, \n для новой строки, \t для табуляции и т. д.). Они обозначаются префиксом r перед строкой, например: r"строка". Сырые строки удобны, когда вам нужно использовать много обратных слэшей, например, в путях к файлам или регулярных выражениях, где \ часто встречается. Сырые строки упрощают код и помогают избежать ошибок, связанных с экранированием символов. Пример использования

# Обычная строка
print("C:\\new_folder\\file.txt")  # Выводит: C:\new_folder\file.txt

# Сырая строка
print(r"C:\new_folder\file.txt")   # Выводит: C:\new_folder\file.txt
В первом случае \\ используется для экранирования, чтобы Python не воспринял \n как символ новой строки. В случае сырой строки r"...", экранирование не нужно, так как \ воспринимается буквально. 📲 Мы в MAX 👉@BookPython

Сравнение производительности dict() и {} в Python Какое-то время назад, во время разбора кода, мы обсудили выбор dict() вмест
Сравнение производительности dict() и {} в Python Какое-то время назад, во время разбора кода, мы обсудили выбор dict() вместо {} в новом коде на Python. Коллега утверждал, что dict() более читаем и чётче выражает предназначение кода, поэтому следует предпочесть его. Меня это не убедило, но в тот момент контраргументов не нашлось, поэтому я воздержался. Это заставило меня задуматься: в чём разница между типом dict и литеральным выражением {}? https://habr.com/ru/articles/788440/ original https://madebyme.today/blog/python-dict-vs-curly-brackets/ 📲 Мы в MAX 👉@BookPython

🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. https://max.ru/tipsysdmin Типичный Сисадмин Excel лайфхак 📌 https://t.me/Excel_lifehack Excel лайфхак Английский с нуля 🇬🇧 https://max.ru/UchuEnglish 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика Программирование Go📌 https://max.ru/golang_lib Библиотека Go (Golang) разработчика Программирование React📌 https://max.ru/react_lib React Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии 📌 https://max.ru/progjob Вакансии в IT Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Бонус 📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП

Когда вы пишете собственный метод __repr__ для какого-то объекта, обычно нужно включать представление его атрибутов. Для этого при форматировании следует вызывать repr() для объектов, так как по умолчанию вызывается str(). Это делается с помощью нотации !r:

class Pair:
    def __init__(self, left, right):
        self.left = left
        self.right = right
        
    def __repr__(self):
        class_name = type(self).__name__
        return f'{class_name}({self.left!r}, {self.right!r})'
📲 Мы в MAX 👉@BookPython

Модуль functools для манипуляций с функциями Модуль functools в Python предоставляет инструменты для работы с функциями, позволяя выполнять различные манипуляции с ними. Вот некоторые из наиболее важных функций и возможностей, которые предоставляет functools: 1. functools.partial: Позволяет зафиксировать некоторые аргументы функции и создать новую функцию с предопределенными значениями.

   from functools import partial

   def multiply(x, y):
       return x * y

   double = partial(multiply, 2)
   print(double(5))  # Вывод: 10
   
2. functools.reduce: Применяет функцию к паре элементов в последовательности, сокращая ее до одного значения. Обычно используется для аккумуляции значений.

   from functools import reduce

   numbers = [1, 2, 3, 4]
   product = reduce(lambda x, y: x * y, numbers)
   print(product)  # Вывод: 24
   
3. functools.lru_cache: Кэширует результаты вызовов функции, чтобы ускорить повторные вызовы с теми же аргументами. Полезно для функций с дорогими вычислениями.

   from functools import lru_cache

   @lru_cache(maxsize=None)
   def fibonacci(n):
       if n < 2:
           return n
       return fibonacci(n - 1) + fibonacci(n - 2)

   print(fibonacci(10))  # Вывод: 55
   
4. functools.wraps: Декоратор, который сохраняет метаданные оригинальной функции (такие как имя и документация) при создании декоратора.

   from functools import wraps

   def my_decorator(func):
       @wraps(func)
       def wrapper(*args, **kwargs):
           print("Что-то делаем перед вызовом функции")
           return func(*args, **kwargs)
       return wrapper

   @my_decorator
   def say_hello():
       """Выводит приветствие."""
       print("Привет!")

   print(say_hello.__name__)  # Вывод: say_hello
   print(say_hello.__doc__)   # Вывод: Выводит приветствие.
   
5. functools.total_ordering: Упрощает реализацию всех методов сравнения для класса, определяя только несколько из них.

   from functools import total_ordering

   @total_ordering
   class Point:
       def __init__(self, x, y):
           self.x = x
           self.y = y

       def __eq__(self, other):
           return (self.x, self.y) == (other.x, other.y)

       def __lt__(self, other):
           return (self.x, self.y) < (other.x, other.y)

   p1 = Point(1, 2)
   p2 = Point(3, 4)
   print(p1 < p2)  # Вывод: True
   print(p1 <= p2)  # Вывод: True
   
Эти функции и декораторы делают functools мощным инструментом для функционального программирования в Python. 📲 Мы в MAX 👉@BookPython

Генератор можно остановить. Ты можешь явно вызвать g.close(), но обычно это делает сборщик мусора. Когда вызывается close, в точке, где выполнение генератора было приостановлено, выбрасывается исключение GeneratorExit:

def gen():
    try:
        yield 1
        yield 2
    finally:
        print('END')


g = gen()
print(next(g))  # выведет '1'
g.close()       # выведет 'END'
Обрати внимание на три момента: 1. Нельзя использовать yield при обработке GeneratorExit Если в блоке finally попытаться сделать yield, возникнет ошибка RuntimeError:

def gen():
    try:
        yield 1
    finally:
        yield 3  # ошибка!


g = gen()
next(g)
g.close()  # RuntimeError
2. Исключение не выбрасывается, если генератор ещё не запускался В этом случае генератор просто переходит в состояние остановлен, но finally не выполняется:

def gen():
    try:
        yield 1
    finally:
        print('END')


g = gen()
g.close()         # ничего не выводит
print(list(g))    # выведет '[]'
3. close() ничего не делает, если генератор уже завершён Если генератор полностью отработал, close() не вызывает finally повторно и просто игнорируется:

def gen():
    try:
        yield 1
        yield 2
    finally:
        print('END')


g = gen()
print(list(g))     # ['1', '2']
print('Closing now')
g.close()

# Вывод:
# END
# [1, 2]
# Closing now
📲 Мы в MAX 👉@BookPython

Стандартный модуль json имеет интерфейс командной строки, который может быть полезен для форматирования JSON с помощью одного только Python. Этот модуль называется json.tool и используется следующим образом:

$ echo '{"a": [], "b": "c"}' | python -m json.tool
{
    "a": [],
    "b": "c"
}
📲 Мы в MAX 👉@BookPython

Все объекты в Python создаются с помощью вызова метода __new__. Даже если вы определяете свой собственный __new__ для класса, вы должны вызвать super().__new__(...). Можно подумать, что object.__new__ — это базовая реализация, отвечающая за создание всех объектов. Но это не совсем так. Существует несколько таких реализаций, и они несовместимы. Например, у dict есть собственная низкоуровневая реализация __new__, и объекты типов, унаследованных от dict, нельзя создать с помощью object.__new__:

In : class D(dict):
...:     pass
...:

In : class A:
...:     pass
...:

In : object.__new__(A)
Out: <__main__.A at 0x7f200c8902e8>

In : object.__new__(D)
...
TypeError: object.__new__(D) is not safe,
use D.__new__()
📲 Мы в MAX 👉@BookPython

🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. https://max.ru/tipsysdmin Типичный Сисадмин Excel лайфхак 📌 https://t.me/Excel_lifehack Excel лайфхак Английский с нуля 🇬🇧 https://max.ru/UchuEnglish 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика Программирование Go📌 https://max.ru/golang_lib Библиотека Go (Golang) разработчика Программирование React📌 https://max.ru/react_lib React Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии 📌 https://max.ru/progjob Вакансии в IT Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Бонус 📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП

Python позволяет перегружать многие разные операторы, и оператор сдвига — один из них. Вот пример того, как можно создать композицию функций с использованием этого оператора. Здесь символы, похожие на стрелки, показывают направление потока данных:

from collections import deque
from math import sqrt


class Compose:
    def __init__(self):
        self._functions = deque()

    def __call__(self, *args, **kwargs):
        result = None
        for f in self._functions:
            result = f(*args, **kwargs)
            args = [result]
            kwargs = dict()
        return result

    def __rshift__(self, f):
        self._functions.append(f)
        return self

    def __lshift__(self, f):
        self._functions.appendleft(f)
        return self


compose = Compose


sqrt_abs = (compose() << sqrt << abs)
sqrt_abs2 = (compose() >> abs >> sqrt)

print(sqrt_abs(-4))   # 2.0
print(sqrt_abs2(-4))  # 2.0
Объяснение: << — добавляет функцию в начало цепочки (выполняется первой). >> — добавляет функцию в конец цепочки (выполняется последней). В примере sqrt_abs(-4) сначала берёт abs(-4) → 4, а затем sqrt(4) → 2.0. sqrt_abs2(-4) делает то же самое, но функции добавлены в другом порядке. 📲 Мы в MAX 👉@BookPython

Класс объекта доступен через атрибут __class__:

>>> [1, 2].__class__
<class 'list'>
Однако более привычный способ получить класс — использовать функцию type. Кроме того, это единственный способ, который работает со старыми стилями классов.

>>> type([1, 2])
<class 'list'>
Если вы хотите проверить, является ли объект экземпляром заданного класса, следует использовать isinstance, а не сравнение:

>>> class A:
...     pass
...
>>> class B(A):
...     pass
...
>>> type(B())
<class '__main__.B'>
>>> isinstance(B(), A)
True
📲 Мы в MAX 👉@BookPython

В Python числа с плавающей точкой могут иметь значение NaN. Его можно получить с помощью math.nan. NaN не равен ничему, включая самого себя:

>>> math.nan == math.nan
False
Кроме того, объект NaN не является уникальным — можно получить несколько разных объектов NaN из разных источников:

>>> float('nan')
nan
>>> float('nan') is float('nan')
False
Это означает, что обычно нельзя использовать NaN в качестве ключа словаря:

>>> d = {}
>>> d[float('nan')] = 1
>>> d[float('nan')] = 2
>>> d
{nan: 1, nan: 2}
📲 Мы в MAX 👉@BookPython

В Python None равен None, поэтому может показаться, что проверку на None можно делать через ==:

ES_TAILS = ('s', 'x', 'z', 'ch', 'sh')

def make_plural(word, exceptions=None):
    if exceptions == None:  # ← ← ←
        exceptions = {}

    if word in exceptions:
        return exceptions[word]
    elif any(word.endswith(t) for t in ES_TAILS):
        return word + 'es'
    elif word.endswith('y'):
        return word[0:-1] + 'ies'
    else:
        return word + 's'

exceptions = dict(
    mouse='mice',
)

print(make_plural('python'))
print(make_plural('bash'))
print(make_plural('ruby'))
print(make_plural('mouse', exceptions=exceptions))
Однако так делать неправильно. Действительно, None равен None, но не только он может быть равен None. Пользовательские объекты тоже могут вернуть True при сравнении с None через ==:

class A:
    def __eq__(self, other):
        return True

print(A() == None)  # True
print(A() is None)  # False
Правильный способ проверки на None — использовать is None. 📲 Мы в MAX 👉@BookPython