Магические методы и пустые списки в Python

Автор: CoolPython

Методы с двойным подчеркиванием в начале и в конце, например, __eq__, __hash__, __init__, в Python называют магическими методами. Их назвали так потому, что они добавляют магию в поведение класса.

Например, метод __init__ неявно вызывается при инициализации объекта:

Foo:
    def __init__(self, a, b):
        self.a = a
        self.b = b

foo = Foo(7, 9) # вызывается __init__ 
print(foo.a, foo.b) # 7, 9

Но сегодня я хочу поговорить о магичесом методе __bool__. В тех классах, где этот метод определен, он сообщает интерпретатору, как оценить булево значение произвольного объекта.

Зачем нам это? Это нестареющая классика: чтобы проверить словарь или список на непустоту, начинающие часто используют стиль, как в C++:

if len(a) != 0:
    pass

В то время как PEP8 рекомендует делать просто:

if not a: 
    pass

И это работает ровно потому, что в момент if a: вызывается метод __bool__ класса список.

Для пользовательских объектов, где __bool__ не перегружен, по умолчанию возвращается True.

if foo:
    print(True)
else:
    print(False)

#  True

Но если добавить

Foo:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __bool__(self):
        return False

То поведение изменится:

if foo:
    print(True)
else:
    print(False)

#  False

Кстати, в случае, если метода __bool__ в классе нет, то интерпретатор будет искать метод __len__ (длина). Поведение такое же: если __len__ возвращает 0, то логическое значение оценивается как False.

Что с этим делать? Помнить, что falsy (значения, которые оцениваются как False) в Python это:

  • пустые словари {},
  • списки [],
  • кортежи (),
  • множества set(),
  • строки «»,
  • пустые range(0),
  • нули любого численного типа: 0, 0.0, 0j
  • константы None и собственно False

А truthy значения это:

  • любые пользовательские объекты по умолчанию
  • непустые словари, множества, строки, списки, …
  • константа True

И писать проверку на непустоту красиво:

not a: 
    pass