Tentokrát se podíváme na to, jak v Pythonu správně porovnávat objekty s None
.
Původní kód
S následujícím kódem jste se již určitě setkali:
x = foo() if x == None: ...
Případně s touto obměnou v testech s využitím standardního modulu unittest
:
self.assertEqual(x, None)
V obou případech se použije operátor ==
(i v testech).
Proč takto ne?
Důvodů je hned několik:
- PEP8 (Style Guide for Python Code) říká: Comparisons to singletons like None should always be done with is or is not, never the equality operators. Proč, to si hned ukážeme.
- Operátory
==
ais
slouží k různým účelům. Operátor==
slouží pro obecné porovnání dvou objektů na rovnost z hlediska vnitřní struktury (na základě metody__eq__()
), kdežtois
se používá pro porovnání na základě identity (zda se jedná o dva totožné objekty). Příklad:
a = [1, 2, 3] b = [1, 2, 3] print(a == b) # True print(a is b) # False
- Použití
x == None
není bezpečné, protože třída, jejíž jex
instance, může mít vlastní operátor porovnání:
class A: def __eq__(self, other): # Každé porovnání přes == vyhodnoť jako pravdivé. return True def foo(): return A() x = foo() if x == None: # Vyhodnotí se jako True! ... # Tento kód se vykoná! if x is None: # Vyhodnotí se jako False (očekávané). ... # Tento kód se NEvykoná (očekávané).
- Operátor
is
je rychlejší, než==
(o cca 90% u mě na PC), viz níže. Toto je ale jen teoretická výhoda, která se v praxi pravděpodobně nijak neprojeví. Takže to berte jen jako zajímavost :).
import timeit print(timeit.timeit('0 is None', number=100_000_000)) # 1.21 sekund print(timeit.timeit('0 == None', number=100_000_000)) # 2.30 sekund
Jak to udělat lépe?
None
je tzv. singleton (jedinečná instance), takže bychom pro porovnání měli použít is
a nikoliv ==
. Čili:
if x is None: ...
a v testech pak
self.assertIsNone(x)