Jak uzyskać przeciwieństwo (negację) wartości logicznej w Pythonie?

106

Dla następującej próbki:

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

Czy istnieje sposób, aby pominąć drugą instrukcję if? Po prostu powiedzieć komputerowi, aby zwrócił odwrotność wartości logicznej bool?

amyassin
źródło
6
Jest to prawdopodobnie tylko pseudokod, ale inti boolsą obie nazwy wbudowane (dla typów, które reprezentują) i nie powinny być wykorzystywane jako nazw zmiennych.
SingleNegationElimination
Tak, to tylko pseudo-kod ,, celów demonstracyjnych tylko ...
amyassin
7
if x == True:powinno być napisane if x:.
Mike Graham

Odpowiedzi:

180

Możesz po prostu użyć:

return not bool
jtbandes
źródło
4
Jest również int in range (....)nieefektywne. Utworzy listę, a następnie przeprowadzi wyszukiwanie liniowe. Lepiej niż x in range(low, high)jest low <= x < high.
MRAB
Zauważ, że not Nonezwróci False. Przynajmniej dla mnie tego się nie spodziewałem. Spodziewałbym not Nonesię, że Nonetak notmoże być użyte do negacji, nawet jeśli wartość zwracana może być None. Sposób, w jaki jest zaimplementowany w Pythonie, musisz najpierw zweryfikować, czy faktycznie masz wartość logiczną.
Omni
54

notOperatora (negacja logiczna)

Prawdopodobnie najlepszym sposobem jest użycie operatora not:

>>> value = True
>>> not value
False

>>> value = False
>>> not value
True

Więc zamiast twojego kodu:

if bool == True:
    return False
else:
    return True

Możesz użyć:

return not bool

Logiczna negacja jako funkcja

W operatormodule są również dwie funkcje operator.not_i jego alias operator.__not__na wypadek, gdybyś potrzebował go jako funkcji zamiast operatora:

>>> import operator
>>> operator.not_(False)
True
>>> operator.not_(True)
False

Mogą być przydatne, jeśli chcesz użyć funkcji, która wymaga funkcji predykatu lub wywołania zwrotnego.

Na przykład maplub 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]

Oczywiście to samo można osiągnąć za pomocą równoważnej lambdafunkcji:

>>> my_not_function = lambda item: not item

>>> list(map(my_not_function, lst))
[False, True, False, True]

Nie używaj odwracającego operatora bitowego ~na wartościach logicznych

Można pokusić się o użycie bitowego operatora odwracającego ~lub równoważnej funkcji operatora operator.inv(lub jednego z pozostałych 3 aliasów). Ale ponieważ booljest to podklasa intwyniku, może być nieoczekiwana, ponieważ nie zwraca „odwrotnej wartości logicznej”, zwraca „odwrotną liczbę całkowitą”:

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

Dzieje się tak, ponieważ Truejest równoważne 1i Falsedo, 0a inwersja bitowa działa na bitowej reprezentacji liczb całkowitych 1 i 0.

Dlatego nie można ich użyć do „zanegowania” a bool.

Negacja z tablicami NumPy (i podklasami)

Jeśli masz do czynienia z tablicami NumPy (lub podklasami takimi jak pandas.Serieslub pandas.DataFrame) zawierającymi wartości logiczne, możesz w rzeczywistości użyć operatora odwrotnego bitowego ( ~), aby zanegować wszystkie wartości logiczne w tablicy:

>>> import numpy as np
>>> arr = np.array([True, False, True, False])
>>> ~arr
array([False,  True, False,  True])

Lub równoważna funkcja NumPy:

>>> np.bitwise_not(arr)
array([False,  True, False,  True])

Nie można używać notoperatora ani operator.notfunkcji w tablicach NumPy, ponieważ wymagają one, aby zwracały one pojedynczy bool(nie tablicę wartości logicznych), jednak NumPy zawiera również funkcję logiczną, która nie działa z uwzględnieniem elementów:

>>> np.logical_not(arr)
array([False,  True, False,  True])

Można to również zastosować do tablic innych niż boolowskie:

>>> arr = np.array([0, 1, 2, 0])
>>> np.logical_not(arr)
array([ True, False, False,  True])

Dostosowywanie własnych zajęć

notdziała poprzez wywołanie boolwartości i zanegowanie wyniku. W najprostszym przypadku wartość prawda po prostu wywoła __bool__obiekt.

Tak więc implementując __bool__(lub __nonzero__w Pythonie 2) możesz dostosować wartość prawdy, a tym samym wynik 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)

Dodałem printoświadczenie, abyś mógł sprawdzić, czy naprawdę wywołuje metodę:

>>> a = Test(10)
>>> not a
__bool__ called on Test(10)
False

Podobnie możesz zaimplementować __invert__metodę, aby zaimplementować zachowanie, gdy ~jest stosowane:

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)

Znowu z printwezwaniem, aby zobaczyć, że faktycznie się nazywa:

>>> a = Test(True)
>>> ~a
__invert__ called on Test(True)
False

>>> a = Test(False)
>>> ~a
__invert__ called on Test(False)
True

Jednak implementacja __invert__tego typu może być myląca, ponieważ jej zachowanie różni się od „normalnego” zachowania w Pythonie. Jeśli kiedykolwiek to zrobisz, udokumentuj to i upewnij się, że ma całkiem dobry (i powszechny) przypadek użycia.

MSeifert
źródło
11

Python ma operator „nie”, prawda? Czy to nie tylko „nie”? Jak w,

  return not bool
Patrick87
źródło
2

Możesz po prostu porównać tablicę boolowską. Na przykład

X = [True, False, True]

następnie

Y = X == False

dałby ci

Y = [False, True, False]
Sebastian
źródło
1
Może dla tablicy Numpy, ale dla standardowej listy Pythona jest to niepoprawne. Ponieważ PO również nie wspomina, nie widzę, jak to odpowiada na pytanie.
SiHa
2

Jeśli próbujesz zaimplementować przełącznik , aby za każdym razem, gdy ponownie uruchamiasz trwały kod, był on negowany, możesz to osiągnąć w następujący sposób:

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

Uruchomienie tego kodu najpierw ustawi toggleto Truei za każdym razem, gdy ten fragment zostanie wywołany, toggle zostanie zanegowany.

user1767754
źródło
2

Przyjęta tutaj odpowiedź jest najbardziej poprawna dla danego scenariusza.

Zastanawiałem się, czy po prostu odwrócić ogólną wartość logiczną. Okazuje się, że przyjęte rozwiązanie działa tutaj jako jeden liner, a jest też inny jednoliniowiec, który również działa. Zakładając, że masz zmienną „n”, o której wiesz, że jest wartością logiczną, najłatwiejszym sposobem jej odwrócenia są:

n = n is False

co było moim oryginalnym rozwiązaniem, a następnie zaakceptowaną odpowiedzią z tego pytania:

n = not n

To ostatnie JEST bardziej przejrzyste, ale zastanawiałem się nad wydajnością i przebiłem to timeit- i okazuje się, że n = not njest to również SZYBSZY sposób na odwrócenie wartości boolowskiej.

user1411616
źródło
Nie używaj n is Falsedo sprawdzania prawdy.
gerrit
0

Inny sposób na osiągnięcie tego samego wyniku, który okazał się przydatny w przypadku ramki danych pandy.

Jak zasugerowano poniżej przez mousetail:

bool(1 - False)

bool(1 - True)
Kandyd
źródło
Dlaczego nie bool(1 - False)?
mousetail
Dobrze. Tak jest lepiej i krócej.
Kandyd
Czy nie ma logicznej inwersji ramek danych pandy, jak w przypadku tablic numpy?
gerrit