Jste zde

Ještě jednou a lépe: porovnání s None v Pythonu

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 == a is 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žto is 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íž je x 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)

Přidat komentář