Skip to content

Commit

Permalink
fluent python chapter 1: python data model
Browse files Browse the repository at this point in the history
  • Loading branch information
jduan committed Oct 9, 2022
1 parent a344298 commit 8184f3f
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 77 deletions.
38 changes: 38 additions & 0 deletions python_sandbox/python_sandbox/fluent_python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# How to run tests?
python -m pytest

# Python Data Model

The first thing to know about special methods (__len__ etc) is that they are meant
to be called the python interpreter, and not by you. You don't write `obj.__len__()`.
You write `len(obj)`.

More often than not, the special method call is implicit. For example, the statement
`for i in x:` actually causes the invocation of `iter(x)`, which in turn may call
`x.__iter__()` if that's available, or use `x.__getitem__()` as a fallback.

You should be implementing them more often than invoking them explicitly.

## __repr__ vs __str__
https://stackoverflow.com/questions/1436703/what-is-the-difference-between-str-and-repr

* The default implementation is useless (it’s hard to think of one which wouldn’t be, but yeah)
* __repr__ goal is to be unambiguous
* __str__ goal is to be readable

## Collections API

The "Collection" ABC (abstract base class) has 3 parents:
* Iterable (`__iter__`): to support the `for` construct
* Sized (`__len__`): to support the `len` function
* Container (`__contains__`): to support the `in` operator

The "Collection" ABC (abstract base class) has 3 children:
* Sequence (__getitem__, __iter__, etc)
* Mapping (__getitem__, __contains__, etc)
* Set

There's also a `Reversible` ABC and `Sequence` is a child of it.

Note that python doesn't require concrete classes to actually inherit from any of
these ABCs. Any class that implements `__len__` satisfies the `Sized` interface.
Empty file.
Empty file.
62 changes: 0 additions & 62 deletions python_sandbox/python_sandbox/fluent_python/chapter1/cards.py

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
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]


suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)


def spades_high(card):
rank_value = FrenchDeck.ranks.index(card.rank)
return rank_value * len(suit_values) + suit_values[card.suit]
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from python_data_model.cards import Card, FrenchDeck, spades_high
from random import choice
import sys


def test_cards():
print(f"sys.path: {sys.path}")
beer_card = Card("7", "diamonds")
assert beer_card.rank == "7"
assert beer_card.suit == "diamonds"


def test_deck():
deck = FrenchDeck()
assert len(deck) == 52
assert deck[0] == Card("2", "spades")
assert deck[-1] == Card("A", "hearts")
# choice works with a sequence and FrenchDeck is a sequence because it implements
# both __len__ and __getitem__
print(f"Pick a random card: {choice(deck)}")
print(f"Pick a random card: {choice(deck)}")

# slicing works
assert deck[:3] == [Card("2", "spades"), Card("3", "spades"), Card("4", "spades")]
assert deck[-3:] == [Card("Q", "hearts"), Card("K", "hearts"), Card("A", "hearts")]

# iteration works too because of __getitem__
print("iterating cards")
for card in deck:
print(card)

# in works too
# If a collection has no __contains__ method, the "in" operator does a sequential scan
assert Card("Q", "hearts") in deck
assert Card("7", "beasts") not in deck

# sort cards
print("sorted cards")
for card in sorted(deck, key=spades_high):
print(card)

# you can iterate the cards in reverse order
print("reversed cards")
for card in reversed(deck):
print(card)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from python_data_model.vectors import Vector


def test_vectors():
v1 = Vector(2, 4)
v2 = Vector(2, 1)
assert v1 + v2 == Vector(4, 5)

v = Vector(3, 4)
assert abs(v) == 5.0

print("v * 3:", v * 3)
assert v * 3 == Vector(9, 12)
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def __init__(self, x=0, y=0):
self.y = y

def __repr__(self):
return 'Vector(%r, %r)' % (self.x, self.y)
return "Vector(%r, %r)" % (self.x, self.y)

def __abs__(self):
return hypot(self.x, self.y)
Expand All @@ -26,17 +26,5 @@ def __add__(self, other):
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)


def main():
v1 = Vector(2, 4)
v2 = Vector(2, 1)
print('v1 + v2:', v1 + v2)

v = Vector(3, 4)
print('abs(v):', abs(v))

print('v * 3:', v * 3)


if __name__ == '__main__':
main()
def __eq__(self, other):
return self.x == other.x and self.y == other.y
1 change: 1 addition & 0 deletions python_sandbox/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
hydra-core==0.11.3
pyyaml==5.3.1
pytest==7.1.3

0 comments on commit 8184f3f

Please sign in to comment.