bool в Python

Contents
Введение
if X vs if X is True
Явно задать bool для своего объекта
Сравнение с bool
Видео
Похожие статьи

Введение

bool наследует от int

https://github.com/python/cpython/blob/main/Doc/c-api/bool.rst

Большинство значений — True

Почти любое значение оценивается как True, если оно имеет какое-либо содержимое.

Любая строка — True, кроме пустых строк.

Любое число — True, кроме 0.

Любой список, кортеж, набор и словарь — True, кроме пустых.

print(bool("testsetup.ru")) print(bool(1961)) print(bool(-273)) print(bool(["cordoba", "fuengirola", "malaga"]))

True True True True

Некоторые значения — False

Существует не так много значений, которые оцениваются как ложные, за исключением пустых значений, таких как (), [], {}, "", число 0 и значение None.

И, конечно, значение False оценивается как ложное.

print(bool(False)) print(bool(None)) print(bool(0)) print(bool("")) print(bool(())) print(bool([])) print(bool({}))

False False False False False False False

if X vs if X is True

В дальнейшем нам пригодится понимание разницы между if X и if X is True

if X is True - это более жёсткое условие.

url = "testsetup.ru" if url: print('if url') if url is True: print('if url is True!')

if url

url это не пустая строка, поэтому if url выполняется как True.

Но url это не True. Тип url - str

Если сделать url пустой строкой, то ни одно из условий не выполнится.

url = "" if url: print('if url') if url is True: print('if url is True!')

 

Если переменная явно задана как True, или значение получено из функции, которая возвращает True, то оба условия выполнятся.

verified = True if verified: print('if verified') if verified is True: print('if verified is True!')

if verified if verified is True!

Явно задать bool для своего объекта

Применим bool() к объектам класса, у которого нет кастомных методов кроме __init__()

class My: def __init__(self, length: int) -> None: self.length = length if __name__ == '__main__': print(bool(My(0))) # True print(bool(My(1))) # True # print(bool(My("a"))) # TypeError: '>' not supported between instances of 'str' and 'int'

True
True

Так как пустой объект пользовательского класса не попадает в группу объектов, которые считаются False мы получили оба раза True

Чтобы явно задать нужное поведение используем магический метод __bool__()

class My: def __init__(self, length: int) -> None: self.length = length def __bool__(self) -> bool: return True if self.length > 0 else False if __name__ == '__main__': print(bool(My(0))) # False print(bool(My(1))) # True print(bool(My(-1))) # False

False True False

Обратите внимание, на то, что можно использовать и противоположную логику. Интуитивно это будет непонятно, но формально никто так делать не запрещает.

class My: def __init__(self, length: int) -> None: self.length = length def __bool__(self) -> bool: return True if self.length <= 0 else False if __name__ == '__main__': print(bool(My(0))) # True print(bool(My(1))) # False

True
False

Из __bool__() можно возвращать только bool

class My: def __init__(self, length: int) -> None: self.length = length def __bool__(self) -> bool: return 0 if __name__ == '__main__': print(bool(My(0))) # False

TypeError: __bool__ should return bool, returned int

Второй магический метод, который можно использовать для той же цели - это __len__()

class My: def __init__(self, length: int) -> None: self.length = length def __len__(self) -> int: return self.length if __name__ == '__main__': print(bool(My(0))) # False print(bool(My(1))) # True print(bool(My(-1))) # ValueError: __len__() should return >= 0

False True

Способ не идентичен предыдущему , например, отрицательные числа в My() уже не передать.

ValueError: __len__() should return >= 0

__len__() должен возвращать int

class My: def __init__(self, length: int) -> None: self.length = length def __len__(self) -> int: return "heihei.ru" # TypeError: 'str' object cannot be interpreted as an integer if __name__ == '__main__': print(bool(My(0))) # False

TypeError: 'str' object cannot be interpreted as an integer

Сравнение с bool

Вспомним главу if X vs if X is True

Пример сравнения с True, который выполнится как True

class My: def __bool__(self) -> bool: print('__bool__ called') return True my = My() if my: print('Done!')

__bool__ called Done!

А следующий пример не выполнится как True, потому что там явно проверяется является ли my константой True.

my является объектом класса My поэтому даже до вызова метода __bool__() дело не дойдёт.

class My: def __bool__(self) -> bool: print('__bool__ called') return True my = My() if my is True: print('Done!')

 

Способ, которого рекомендуется избегать, потому что == вызывает метод __eq__() а не __bool__() поэтому результат может быть непредсказуемым.

Например, если добавить к этому примеру метод __eq__(), который всё время возвращает True, мы получим совершенно другой результат

class My: def __init__(self, length: int) -> None: self.length = length def __bool__(self) -> bool: print('__bool__ called') return True if self.length > 0 else False def __eq__(self, other: object) -> bool: print('__eq__ called') return True my = My(0) if my == True: print('Done!') my = My(-1) if my == True: print('Done!')

__eq__ called Done! __eq__ called Done!

Оба раза сравнение сработало как True, хотя длина меньше либо равна нулю.

Method Resulution Order

# builtins.py Python 3.12.2 # … class bool(int): """ bool(x) -> bool Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed. """ def __and__(self, *args, **kwargs): # real signature unknown """ Return self&value. """ pass def __init__(self, x): # real signature unknown; restored from __doc__ pass def __invert__(self, *args, **kwargs): # real signature unknown """ ~self """ pass @staticmethod # known case of __new__ def __new__(*args, **kwargs): # real signature unknown """ Create and return a new object. See help(type) for accurate signature. """ pass def __or__(self, *args, **kwargs): # real signature unknown """ Return self|value. """ pass def __rand__(self, *args, **kwargs): # real signature unknown """ Return value&self. """ pass def __repr__(self, *args, **kwargs): # real signature unknown """ Return repr(self). """ pass def __ror__(self, *args, **kwargs): # real signature unknown """ Return value|self. """ pass def __rxor__(self, *args, **kwargs): # real signature unknown """ Return value^self. """ pass def __xor__(self, *args, **kwargs): # real signature unknown """ Return self^value. """ pass

print(bool.__mro__)

(<class 'bool'>, <class 'int'>, <class 'object'>)

print(True * 5)

5

print(True + True + 2)

4

print(1 / False)

Traceback (most recent call last): File "C:\python\main.py", line 21, in print(1 / False) ~~^~~~~~~ ZeroDivisionError: division by zero

Banner image

Видео

Один из важных источников информации, для написания статьи - видео из курса "Лучший курс по Python"

Article author: Andrei Olegovich

Related articles
Basics
Python
Installation
OOP in Python
flake8
docstring
#!: Shebang
Objects
os
pathlib
flake8
Banner image

Search this site

Subscribe to Telegram channel @aofeed to follow new articles and updates to old ones

Go to channel

@aofeed

Ask a question in the Telegram group

@aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: