bool в Python
| Введение | |
| 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
Видео
Один из важных источников информации, для написания статьи - видео из курса "Лучший курс по Python"
Article author: Andrei Olegovich
| Basics | |
| Python | |
| Installation | |
| OOP in Python | |
| flake8 | |
| docstring | |
| #!: Shebang | |
| Objects | |
| os | |
| pathlib | |
| flake8 |