Eles sempre dão o mesmo resultado.
Na verdade, not 'ham' in 'spam and eggs'
parece ter um caso especial para executar uma única operação "não ativada", em vez de uma operação "interna" e, em seguida, negar o resultado:
>>> import dis
>>> def notin():
'ham' not in 'spam and eggs'
>>> dis.dis(notin)
2 0 LOAD_CONST 1 ('ham')
3 LOAD_CONST 2 ('spam and eggs')
6 COMPARE_OP 7 (not in)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> def not_in():
not 'ham' in 'spam and eggs'
>>> dis.dis(not_in)
2 0 LOAD_CONST 1 ('ham')
3 LOAD_CONST 2 ('spam and eggs')
6 COMPARE_OP 7 (not in)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> def not__in():
not ('ham' in 'spam and eggs')
>>> dis.dis(not__in)
2 0 LOAD_CONST 1 ('ham')
3 LOAD_CONST 2 ('spam and eggs')
6 COMPARE_OP 7 (not in)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> def noteq():
not 'ham' == 'spam and eggs'
>>> dis.dis(noteq)
2 0 LOAD_CONST 1 ('ham')
3 LOAD_CONST 2 ('spam and eggs')
6 COMPARE_OP 2 (==)
9 UNARY_NOT
10 POP_TOP
11 LOAD_CONST 0 (None)
14 RETURN_VALUE
A princípio pensei que eles sempre davam o mesmo resultado, mas que not
por si só era simplesmente um operador de negação lógico de baixa precedência, que poderia ser aplicado a in b
tão facilmente quanto qualquer outra expressão booleana, ao passo que not in
era um operador separado por conveniência e clareza .
A desmontagem acima foi reveladora! Parece que, embora not
obviamente seja um operador de negação lógico, a forma not a in b
é casada especial de forma que não está realmente usando o operador geral. Isso torna not a in b
literalmente a mesma expressão que a not in b
, em vez de meramente uma expressão que resulta no mesmo valor.
not x in xs
nos documentos.