Python Data Model

Pithy

Python Data Model is the API we use to make our own objects play well with the most idiomatic language features (stdlib)

The data model is a description of Python as a framework. It formalizes the interfaces of the build blocks of the language itself.

The python interpreter invokes special methods to perofrm basic object operations, special method names are always written with double underscores __getitem__.

Question

Why use special methods and follow the python data model?

Answer

Not only is it easier to read:

  • our objects can support and interact with fundamental language constructs, you don’t have to recreate the wheel you can just use stdlib
  • we can get better performance as special methods can leverage CPython
Python
# French deck example from Fluent Python
import collections

Card = collections.namedtuple('Card', ['rank', 'suit'])

class FrenchDeck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = 'spades diamonds clubs hearts'.split()

    def __init__(self):
        self._cards = [Card(rank, suit) for suit in self.suits
                                        for rank in self.ranks]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, position):
        return self._cards[position]

# Using the class
deck = FrenchDeck()

>>> len(deck)
52

>>> Card('Q', 'hearts') in deck
True

>>> for card in deck:
>>>    print(card)
Card(rank='2', suit='spades')
Card(rank='3', suit='spades')

Special Methods

You should never call special methods yourself, they’re meant only for the interpreter.

python
# bad
my_obj.__len__()
# good
len(my_obj) 
# which in turn calls __len__()

__repr__ & __str__

Python
def __repr__(self):
    return f'Vector({self.x!r}, {self.y!r})'

def __str__(self):
    return f'<{self.x}, {self.y}>'

# Example use
v = Vector(3, 4)
repr(v)  # 'Vector(3, 4)'     unambiguous, can recreate it
str(v)   # '<3, 4>'           readable, human friendly

Purpose: get the string representation of the object for inspection

  • repr goal is to be unambiguous - if possible, match the source code necessary to re-create the represented object.
  • str goal is to be readable

Example output of both

Python
str(today)
'2012-03-14 09:21:58.130922'
repr(today)
'datetime.datetime(2012, 3, 14, 9, 21, 58, 130922)'