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