Оператор not
(логическое отрицание)
Наверное, лучше всего использовать оператор not
:
>>> value = True
>>> not value
False
>>> value = False
>>> not value
True
Итак, вместо вашего кода:
if bool == True:
return False
else:
return True
Вы можете использовать:
return not bool
Логическое отрицание как функция
В модуле operator
также есть две функции operator.not_
и его псевдоним operator.__not__
на случай, если вам понадобится эта функция вместо как оператор:
>>> import operator
>>> operator.not_(False)
True
>>> operator.not_(True)
False
Это может быть полезно, если вы хотите использовать функцию, для которой требуется функция предиката или обратный вызов.
Например map
или filter
:
>>> lst = [True, False, True, False]
>>> list(map(operator.not_, lst))
[False, True, False, True]
>>> lst = [True, False, True, False]
>>> list(filter(operator.not_, lst))
[False, False]
Конечно, того же можно достичь с помощью эквивалентной функции lambda
:
>>> my_not_function = lambda item: not item
>>> list(map(my_not_function, lst))
[False, True, False, True]
Не использовать оператор побитового инвертирования ~
для логических значений
Может возникнуть соблазн использовать побитовый оператор инвертирования ~
или эквивалентную операторную функцию operator.inv
(или один из трех других псевдонимов). Но поскольку bool
является подклассом int
, результат может быть неожиданным, поскольку он не возвращает «обратное логическое значение», он возвращает «обратное целое число»:
>>> ~True
-2
>>> ~False
-1
Это потому, что True
эквивалентно 1
и False
- 0
, а побитовая инверсия работает с побитовым представлением целых чисел 1
и 0
.
Так что их нельзя использовать для "отрицания" bool
.
Отрицание с массивами NumPy (и подклассами)
Если вы имеете дело с массивами NumPy (или подклассами, такими как pandas.Series
или pandas.DataFrame
), содержащими логические значения, вы можете фактически использовать побитовый обратный оператор (~
) для отрицания всех логических значений в массив:
>>> import numpy as np
>>> arr = np.array([True, False, True, False])
>>> ~arr
array([False, True, False, True])
Или эквивалентная функция NumPy:
>>> np.bitwise_not(arr)
array([False, True, False, True])
Вы не можете использовать оператор not
или функцию operator.not
в массивах NumPy, потому что они требуют, чтобы они возвращали один bool
(не массив логических значений), однако NumPy также содержит логическую функцию not, которая работает с элементом -wise:
>>> np.logical_not(arr)
array([False, True, False, True])
Это также может быть применено к небулевым массивам:
>>> arr = np.array([0, 1, 2, 0])
>>> np.logical_not(arr)
array([ True, False, False, True])
Настройка ваших собственных классов
not
работает путем вызова bool
значения и отменяет результат. В простейшем случае значение true просто вызовет __bool__
для объекта.
Таким образом, реализовав __bool__
(или __nonzero__
в Python 2), вы можете настроить значение истинности и, следовательно, результат not
:
class Test(object):
def __init__(self, value):
self._value = value
def __bool__(self):
print('__bool__ called on {!r}'.format(self))
return bool(self._value)
__nonzero__ = __bool__ # Python 2 compatibility
def __repr__(self):
return '{self.__class__.__name__}({self._value!r})'.format(self=self)
Я добавил оператор print
, чтобы вы могли убедиться, что он действительно вызывает метод:
>>> a = Test(10)
>>> not a
__bool__ called on Test(10)
False
Аналогично, вы можете реализовать метод __invert__
для реализации поведения, когда применяется ~
:
class Test(object):
def __init__(self, value):
self._value = value
def __invert__(self):
print('__invert__ called on {!r}'.format(self))
return not self._value
def __repr__(self):
return '{self.__class__.__name__}({self._value!r})'.format(self=self)
Снова с print
вызовом, чтобы увидеть, что он на самом деле называется:
>>> a = Test(True)
>>> ~a
__invert__ called on Test(True)
False
>>> a = Test(False)
>>> ~a
__invert__ called on Test(False)
True
Однако реализация __invert__
может привести к путанице, поскольку ее поведение отличается от "нормального" поведения Python. Если вы когда-нибудь сделаете это, четко документируйте это и убедитесь, что у него довольно хороший (и распространенный) вариант использования.