ruk·si

🐍 Python
Equality

Updated at 2018-06-10 22:00

is checks for identity while == checks for equality.

a = [1, 2, 3]
b = a
c = list(a)

assert a == b
assert a is b
assert a == c
assert a is not c

Any content or value makes an object truthy.

assert not False
assert True

assert not None         # None is falsy

assert not ()           # empty tuple is falsy
assert (None,)          # any content makes tuple truthy

assert not []           # empty list is falsy
assert [None]           # any content make list truthy

assert not set()        # empty set is falsy
assert {None}           # any content makes set truthy

assert not {}           # empty dict is falsy
assert {'key': None}    # any content makes dict truthy

assert not ''           # empty str is falsy
assert ' '              # any content makes str truthy

assert not 0            # zero integer is falsy
assert -123 and 123     # non-zero integers are truthy

assert not 0.0          # zero float is falsy
assert -.1 and 12.3     # non-zero floats are truthy

a == b is syntactical sugar for a.eq(b)``

Always use is to check for singletons like None. is is less error prone and faster as it can't be overloaded like ==.

from typing import Optional

def greet(name: Optional[str] = None):
    if name is None:
        return 'Hello!'
    else:
        return f'Hello, {name}!'

assert greet() == 'Hello!'
assert greet('Ruksi') == 'Hello, Ruksi!'

Never use is with strings or integers. It usually works because of interning, but is undocumented implementation quirk.

s1 = 'ABC'
s2 = 'ABC'
assert s1 is s2 # BAD, never do this even if it works for now

Prefer isinstance(obj, cls) over type(obj) == cls. And make sure cls is always an abstract class which's metaclass derives from abc.ABCMeta. There are plenty of useful abstract classes in typing and numbers, although int and float are usually the best.

import numbers
from typing import Callable, Collection, Container, Hashable, \
    Iterable, MutableSequence, Sequence, Sized

assert isinstance(list(), Collection)
assert isinstance(list(), Sized)
assert isinstance(list(), Container)
assert isinstance(list(), Sequence)
assert isinstance(list(), MutableSequence)
assert isinstance(list(), Iterable)
assert not isinstance(list(), Hashable)

def greet() -> str:
    return 'Hello!'

assert isinstance(greet, Callable)
assert isinstance(lambda x: x + 1, Callable)

assert isinstance(123, int)
assert not isinstance(123, float)

assert isinstance(1.23, float)
assert not isinstance(1.23, int)

assert isinstance(123, numbers.Number)
assert isinstance(123, numbers.Complex)
assert isinstance(123, numbers.Real)
assert isinstance(123, numbers.Rational)  # different than decimal.Decimal
assert isinstance(123, numbers.Integral)

assert isinstance(1.23, numbers.Number)
assert not isinstance(1.23, numbers.Integral)

assert isinstance(True, numbers.Number)  # Booleans are numbers 1 and 0
assert isinstance(False, numbers.Number)

Source

  • Python Tricks The Book, Dan Bader
  • Fluent Python, Luciano Ramalho