Como faço para obter o oposto (negação) de um booleano em Python?

97

Para o seguinte exemplo:

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

Existe alguma maneira de pular a segunda instrução if? Apenas dizer ao computador para retornar o oposto do booleano bool?

amyassin
fonte
6
Provavelmente é apenas um pseudocódigo, mas inte boolsão nomes internos (para os tipos que representam) e não devem ser usados ​​como nomes de variáveis.
SingleNegationElimination
sim, é apenas um pseudo-código ,, apenas para fins de demonstração ...
amyassin
6
if x == True:deve ser escrito if x:.
Mike Graham

Respostas:

169

Você pode apenas usar:

return not bool
jtbandes
fonte
4
Além disso, int in range (....)é ineficiente. Ele criará uma lista e, em seguida, fará uma pesquisa linear. Melhor do que x in range(low, high)é low <= x < high.
MRAB de
48

O notoperador (negação lógica)

Provavelmente, a melhor maneira é usar o operador not:

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

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

Então, em vez de seu código:

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

Você pode usar:

return not bool

A negação lógica como função

Também há duas funções no operatormódulo operator.not_e seu apelido operator.__not__caso você precise dele como função em vez de como operador:

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

Isso pode ser útil se você quiser usar uma função que requer uma função de predicado ou um retorno de chamada.

Por exemplo mapou 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]

Claro que o mesmo também pode ser alcançado com uma lambdafunção equivalente :

>>> my_not_function = lambda item: not item

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

Não use o operador invertido bit a bit ~em booleanos

Alguém pode ficar tentado a usar o operador invertido bit a bit ~ou a função de operador equivalente operator.inv(ou um dos outros 3 aliases lá). Mas porque boolé uma subclasse do intresultado pode ser inesperado porque não retorna o "booleano inverso", ele retorna o "inteiro inverso":

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

Isso porque Trueé equivalente a 1e Falseto 0e a inversão bit a bit opera na representação bit a bit dos inteiros 1 e 0.

Portanto, eles não podem ser usados ​​para "negar" a bool.

Negação com matrizes NumPy (e subclasses)

Se você estiver lidando com matrizes NumPy (ou subclasses como pandas.Seriesou pandas.DataFrame) contendo booleanos, você pode usar o operador inverso bit a bit ( ~) para negar todos os booleanos em uma matriz:

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

Ou a função NumPy equivalente:

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

Você não pode usar o notoperador ou a operator.notfunção em matrizes NumPy porque eles exigem que retornem um único bool(não uma matriz de booleanos); no entanto, NumPy também contém uma função não lógica que funciona em elementos:

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

Isso também pode ser aplicado a matrizes não booleanas:

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

Personalizando suas próprias aulas

notfunciona chamando boolo valor e negando o resultado. No caso mais simples, o valor verdade apenas chamará __bool__o objeto.

Portanto, ao implementar __bool__(ou __nonzero__no Python 2), você pode personalizar o valor verdadeiro e, portanto, o resultado de 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)

Eu adicionei uma printinstrução para que você possa verificar se ela realmente chama o método:

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

Da mesma forma, você pode implementar o __invert__método para implementar o comportamento quando ~é aplicado:

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)

Novamente com uma printchamada para ver se é realmente chamado:

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

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

No entanto, uma implementação __invert__como essa pode ser confusa porque seu comportamento é diferente do comportamento "normal" do Python. Se você fizer isso, documente-o claramente e certifique-se de que tenha um caso de uso muito bom (e comum).

MSeifert
fonte
11

Python tem um operador "não", certo? Não é apenas "não"? Como em,

  return not bool
Patrick87
fonte
3

Você pode apenas comparar o array booleano. Por exemplo

X = [True, False, True]

então

Y = X == False

daria a você

Y = [False, True, False]
Sebastian
fonte
1
Para um array Numpy, talvez, mas para uma lista Python padrão, isso está incorreto. Como o OP não menciona nenhum dos dois, não consigo ver como isso responde à pergunta.
SiHa 01 de
3

A resposta aceita aqui é a mais correta para o cenário fornecido.

Isso me fez pensar sobre simplesmente inverter um valor booleano em geral. Acontece que a solução aceita aqui funciona como uma linha e há outra linha que também funciona. Supondo que você tenha uma variável "n" que você sabe que é booleana, as maneiras mais fáceis de invertê-la são:

n = n is False

qual foi a minha solução original e, em seguida, a resposta aceita a partir desta pergunta:

n = not n

O último é mais claro, mas me perguntei sobre o desempenho e consegui passar timeit- e descobri que n = not ntambém é a maneira MAIS RÁPIDA de inverter o valor booleano.

user1411616
fonte
2

Se você estiver tentando implementar uma alternância , de modo que sempre que executar novamente um código persistente ele seja negado, você pode conseguir isso da seguinte maneira:

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

A execução deste código definirá primeiro togglecomo Truee sempre que este snippet for chamado, a alternância será negada.

user1767754
fonte