Булевий тип даних
Має усього два значення: False
та True
.
Тип bool
успадковано від int
:
>>> bool.mro()
[<class 'bool'>, <class 'int'>, <class 'object'>]
>>>
Успадковуватись від bool
не можна:
>>> class A(bool):pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'bool' is not an acceptable base type
>>>
Літералам False
та True
відповідають цілі числа 0
і 1
.
>>> True == 1
True
>>> True is 1
<stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
False
>>> True * 7
7
>>>
Створення об'єктів
- за допомогою літералів
- bool() без аргументів повертає
False
Приведення інших типів до bool
bool(x)
Функція повертає False
у наступних випадках:
- якщо у об'єкта
x
визначено метод__bool__()
і він повертаєFalse
- якщо у об'єкта
x
визначено метод__len__()
і він повертає0
- якщо значення
x
числового типу дорівнює нулю (0, 0.0, 0j, ...) - якщо об'єкт
x
— пустий контейнер (list, str, tuple, dict, ...) - якщо значення об'єкта
x
— одне зNone
чиFalse
У всіх інших випадках результатом функції буде True
.
>> bool(0)
False
>>> bool(1)
True
>>> bool('string')
True
>>> bool('')
False
>>> bool()
False
>>> class MyClass: f):
... def __bool__(self):::::
... return False
...
>>> c = MyClass()
>>> bool(c)
False
>>> class AlwaysTrue: pass
...
>>> c = AlwaysTrue()
>>> bool(c)
True
>>>
Булевий контекст
Значення об'єктів можна розглядати як істині (truthy) і хибні (falsy).
x
є falsy, якщоbool(x)==False
x
є truthy, якщоbool(x)==True
Коли ми використовуємо значення у логічних виразах
або при перевірці умов в інструкціях if
та while
,
ми використовуємо їх у булевому контексті.
Приклад. Функції передається непустий список цілих чисел. Функція виводить лише парні числа з цього списка.
def print_even(data):
if not data: # if len(data) == 0:
raise ValueError("The argument data cannot be empty")
for value in data:
if not value % 2: # if value % 2 == 0:
print(value)
Логічні операції
Оператори у порядку збільшення пріорітету:
Операція | Результат |
---|---|
x or y |
y якщо bool(x) is False , інакше x |
x and y |
x якщо bool(x) is False , інакше y |
not x |
True якщо bool(x) is False , інакше False |
Приклади:
>>> 7 or 5
7
>>> 'string' or None
'string'
>>> None or 'string'
'string'
>>> def f(list_=None): # аргумент з дефолтним значенням [] мутабельного типу — не найкраща ідея, тому None
... new_list = list_ or []
... return new_list
...
>>> f()
[]
>>> f([1,2])
[1, 2]
>>>
>>> 7 and 5
5
>>> 'string' and False
False
>>> False and 'string'
False
>>>
Оператор not
має нижчий пріорітет ніж інші "нелогічні" оператори.
Тому вираз
not a == b
інтерпретується як
not (a == b)
Наступний вираз:
a == not b
не є коректним і призведе до SyntaxError
.
"Ліниві" логічні обчислення
Операція or
є "лінивою".
Значення другого операнда обчислюється лише тоді, коли перший операнд є falsy:
>>> l = [1, 2]
>>> l.pop() or l.pop()
2
>>> l
[1]
>>> l = [1, 0]
>>> l.pop() or l.pop()
1
>>> l
[]
>>>
Операція and
є "лінивою".
Значення другого операнда обчислюється лише тоді, коли перший операнд є truthy:
>>> l = [1, 0]
>>> l.pop() and l.pop()
0
>>> l
[1]
>>> l = [1, 2]
>>> l.pop() and l.pop()
1
>>> l
[]
>>>
Операції порівняння
Усього в Python є вісім операцій порівняння. Усі операції порівняння мають однаковий пріорітет. У операцій порівняння пріорітет вищий ніж у логічних операцій.
Операція | Що означає | Спеціальний метод |
---|---|---|
< | строго меньше | __lt__() |
<= | меньше або дорівнює | __le__() |
> | строго більше | __gt__() |
>= | більше або дорівнює | __ge__() |
== | дорівнює | __eq__() |
!= | не дорівнює | |
is | ідентичне | |
is not | неідентичне |
Об'єкти різних типів, за винятком числових, при порівнянні на рівність завжди дають False
.
>>> [1,2] == '12'
False
>>> 1 == 1.0
True
>>>
Об'єкти одного класа за замовчуванням не рівні між собою:
>>> class MyClass:
... def __init__(self, value):
... self.value = value
...
>>> c1 = MyClass(1)
>>> c2 = MyClass(1)
>>> c1 == c2
False
>>>
Для порівняння на рівність клас має реалізувати відповідний магічний метод:
>>> class MyClass:
... def __init__(self, value):
... self.value = value
... def __eq__(self, other):
... return self.value == other.value
...
>>> c1 = MyClass(1)
>>> c2 = MyClass(1)
>>> c1 == c2
True
>>>
Щоб об'єкти одного класа можна було впорядкувати (наприклад, відсортувати),
клас має реалізувати відповідні магічні методи:
__lt__(), __le__(), __gt__() і __ge__()
.
Але, як правило, достатньо щоб клас реалізував __lt__()
та __eq__
.
>>> class V:
... def __init__(self, value):
... self.value = value
... def __eq__(self, other):
... return self.value == other.value
... def __lt__(self, other):
... return self.value < other.value
... def __repr__(self):
... return f'{self.__class__.__name__}({self.value})'
...
>>>
>>> v1 = V(1)
>>> v2 = V(1)
>>> v3 = V(2)
>>> l = [V(777), v3, v2, v1, v3]
>>> l
[V(777), V(2), V(1), V(1), V(2)]
>>> l.sort()
>>> l
[V(1), V(1), V(2), V(2), V(777)]
>>>
Поведінка is
та is not
не може бути перевизначена.
Ця операція працює з об'єктами будь-яких класів і ніколи не піднімає винятків.
>>> a=1
>>> s='s'
>>> a is s
False
>>>
Згортання операцій порівняння
Наступний вираз:
x < y <= z
є еквівалентом виразу:
x < y and y <= z
Зауважте: значення y
обчислюється лише один раз.