Як отримати протилежне (заперечення) логічного значення в Python?


106

Для наступного зразка:

def fuctionName(int, bool):
    if int in range(...):
        if bool == True:
            return False
        else:
            return True

Чи є спосіб пропустити друге твердження if? Просто сказати комп’ютеру повернути протилежне логічне значення bool?


6
Це, ймовірно, просто псевдокод, але intі boolє обома вбудованими іменами (для типів, які вони представляють), і їх не слід використовувати як імена змінних.
SingleNegationElimination

так, це просто псевдокод, лише демонстраційні цілі ...
amyassin

7
if x == True:слід писати if x:.
Mike Graham

Відповіді:


180

Ви можете просто використовувати:

return not bool

4
Крім того, int in range (....)неефективний. Він створить список, а потім виконає лінійний пошук. Краще, ніж x in range(low, high)є low <= x < high.
MRAB

Зверніть увагу, що not Noneповернеться False. Принаймні для мене це не те, що я очікував. Я сподіваюсь, not Noneщо Noneце notможе бути використано для заперечення, навіть якщо повернене значення може бути None. Те, як це реалізовано в Python, вам доведеться перевірити, що ви насправді отримали логічну форму.
masi

54

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(або один із інших 3-х псевдонімів). Але оскільки boolпідклас intрезультату може бути несподіваним, оскільки він не повертає "зворотне логічне значення", він повертає "обернене ціле число":

>>> ~True
-2
>>> ~False
-1

Це тому , що Trueеквівалентно 1і Falseдо 0і побітова інверсія діє на побітового поданні цілих чисел 1 і 0.

Тому їх не можна використовувати для "заперечення" a 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, яка працює елементарно:

>>> 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значення і заперечуючи результат. У найпростішому випадку значення істини буде просто викликати __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. Якщо ви коли-небудь зробите це чітко задокументуйте і переконайтеся, що він має досить хороший (і поширений) варіант використання.



2

Ви можете просто порівняти логічний масив. Наприклад

X = [True, False, True]

тоді

Y = X == False

дав би тобі

Y = [False, True, False]

1
Можливо, для масиву Numpy, але для стандартного списку Python це неправильно. Оскільки OP нічого не згадує, я не бачу, як це відповідає на питання.
SiHa

2

Якщо ви намагаєтеся реалізувати перемикач , щоб у будь-який час повторно запустити постійний код, який його заперечує, ви можете досягти цього наступним чином:

try:
    toggle = not toggle
except NameError:
    toggle = True

Виконання цього коду спочатку встановити toggleв Trueі в будь-який час цього фрагмента IST називається, перемикання буде заперечується.


2

Тут прийнята відповідь є найбільш правильною для даного сценарію.

Це змусило мене задуматися про те, щоб взагалі просто інвертувати логічне значення. Виявляється, прийняте рішення тут працює як один лайнер, а є ще один лайнер, який також працює. Якщо припустити, що у вас є змінна "n", яка, на вашу думку, є логічною, найпростіші способи її інвертування:

n = n is False

що було моїм оригінальним рішенням, а потім прийнятою відповіддю на це питання:

n = not n

Останнє є більш зрозумілим, але я замислювався про продуктивність і прокручував її timeit- і виявляється, що n = not nце також ШАХТІШИЙ спосіб інвертувати логічне значення.


Не використовуйте n is Falseдля перевірки істини.
gerrit

0

Ще один спосіб досягти того самого результату, який я знайшов корисним для фрейму даних pandas.

Як пропонується нижче за допомогою мишачого хвоста:

bool(1 - False)

bool(1 - True)

Чому ні bool(1 - False)?
мишачий хвіст

Правильно. Це краще і коротше.
Candide

Чи не існує логічної інверсії фреймів даних pandas, як у масивах numpy?
gerrit
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.