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

Od Petr Zemek, 2018-06-05

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)
Obsah tohoto pole je soukromý a nebude veřejně zobrazen.

Filtrované HTML (využíváno)

  • Povolené HTML značky: <a href hreflang> <em> <strong> <cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <table>
  • Zvýraznění syntaxe kódu lze povolit přes následující značky: <code>, <blockcode>, <bash>, <c>, <cpp>, <haskell>, <html>, <java>, <javascript>, <latex>, <perl>, <php>, <python>, <ruby>, <rust>, <sql>, <text>, <vim>, <xml>, <yaml>.
  • Řádky a odstavce se zalomí automaticky.
  • Webové a e-mailové adresy jsou automaticky převedeny na odkazy.
CAPTCHA
3 + 17 =
Vyřešte tento jednoduchý matematický příklad a vložte výsledek. Např. pro 1+3 vložte 4.
Nějak se mi tady rozmohl spam, takže poprosím o ověření.