Skip to content

Commit 8184f3f

Browse files
committed
fluent python chapter 1: python data model
1 parent a344298 commit 8184f3f

File tree

9 files changed

+125
-77
lines changed

9 files changed

+125
-77
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# How to run tests?
2+
python -m pytest
3+
4+
# Python Data Model
5+
6+
The first thing to know about special methods (__len__ etc) is that they are meant
7+
to be called the python interpreter, and not by you. You don't write `obj.__len__()`.
8+
You write `len(obj)`.
9+
10+
More often than not, the special method call is implicit. For example, the statement
11+
`for i in x:` actually causes the invocation of `iter(x)`, which in turn may call
12+
`x.__iter__()` if that's available, or use `x.__getitem__()` as a fallback.
13+
14+
You should be implementing them more often than invoking them explicitly.
15+
16+
## __repr__ vs __str__
17+
https://stackoverflow.com/questions/1436703/what-is-the-difference-between-str-and-repr
18+
19+
* The default implementation is useless (it’s hard to think of one which wouldn’t be, but yeah)
20+
* __repr__ goal is to be unambiguous
21+
* __str__ goal is to be readable
22+
23+
## Collections API
24+
25+
The "Collection" ABC (abstract base class) has 3 parents:
26+
* Iterable (`__iter__`): to support the `for` construct
27+
* Sized (`__len__`): to support the `len` function
28+
* Container (`__contains__`): to support the `in` operator
29+
30+
The "Collection" ABC (abstract base class) has 3 children:
31+
* Sequence (__getitem__, __iter__, etc)
32+
* Mapping (__getitem__, __contains__, etc)
33+
* Set
34+
35+
There's also a `Reversible` ABC and `Sequence` is a child of it.
36+
37+
Note that python doesn't require concrete classes to actually inherit from any of
38+
these ABCs. Any class that implements `__len__` satisfies the `Sized` interface.

python_sandbox/python_sandbox/fluent_python/__init__.py

Whitespace-only changes.

python_sandbox/python_sandbox/fluent_python/chapter1/__init__.py

Whitespace-only changes.

python_sandbox/python_sandbox/fluent_python/chapter1/cards.py

Lines changed: 0 additions & 62 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import collections
2+
3+
Card = collections.namedtuple("Card", ["rank", "suit"])
4+
5+
6+
class FrenchDeck:
7+
ranks = [str(n) for n in range(2, 11)] + list("JQKA")
8+
suits = "spades diamonds clubs hearts".split()
9+
10+
def __init__(self):
11+
self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks]
12+
13+
def __len__(self):
14+
return len(self._cards)
15+
16+
def __getitem__(self, position):
17+
return self._cards[position]
18+
19+
20+
suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
21+
22+
23+
def spades_high(card):
24+
rank_value = FrenchDeck.ranks.index(card.rank)
25+
return rank_value * len(suit_values) + suit_values[card.suit]
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from python_data_model.cards import Card, FrenchDeck, spades_high
2+
from random import choice
3+
import sys
4+
5+
6+
def test_cards():
7+
print(f"sys.path: {sys.path}")
8+
beer_card = Card("7", "diamonds")
9+
assert beer_card.rank == "7"
10+
assert beer_card.suit == "diamonds"
11+
12+
13+
def test_deck():
14+
deck = FrenchDeck()
15+
assert len(deck) == 52
16+
assert deck[0] == Card("2", "spades")
17+
assert deck[-1] == Card("A", "hearts")
18+
# choice works with a sequence and FrenchDeck is a sequence because it implements
19+
# both __len__ and __getitem__
20+
print(f"Pick a random card: {choice(deck)}")
21+
print(f"Pick a random card: {choice(deck)}")
22+
23+
# slicing works
24+
assert deck[:3] == [Card("2", "spades"), Card("3", "spades"), Card("4", "spades")]
25+
assert deck[-3:] == [Card("Q", "hearts"), Card("K", "hearts"), Card("A", "hearts")]
26+
27+
# iteration works too because of __getitem__
28+
print("iterating cards")
29+
for card in deck:
30+
print(card)
31+
32+
# in works too
33+
# If a collection has no __contains__ method, the "in" operator does a sequential scan
34+
assert Card("Q", "hearts") in deck
35+
assert Card("7", "beasts") not in deck
36+
37+
# sort cards
38+
print("sorted cards")
39+
for card in sorted(deck, key=spades_high):
40+
print(card)
41+
42+
# you can iterate the cards in reverse order
43+
print("reversed cards")
44+
for card in reversed(deck):
45+
print(card)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from python_data_model.vectors import Vector
2+
3+
4+
def test_vectors():
5+
v1 = Vector(2, 4)
6+
v2 = Vector(2, 1)
7+
assert v1 + v2 == Vector(4, 5)
8+
9+
v = Vector(3, 4)
10+
assert abs(v) == 5.0
11+
12+
print("v * 3:", v * 3)
13+
assert v * 3 == Vector(9, 12)

python_sandbox/python_sandbox/fluent_python/chapter1/vectors.py renamed to python_sandbox/python_sandbox/fluent_python/python_data_model/vectors.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ def __init__(self, x=0, y=0):
77
self.y = y
88

99
def __repr__(self):
10-
return 'Vector(%r, %r)' % (self.x, self.y)
10+
return "Vector(%r, %r)" % (self.x, self.y)
1111

1212
def __abs__(self):
1313
return hypot(self.x, self.y)
@@ -26,17 +26,5 @@ def __add__(self, other):
2626
def __mul__(self, scalar):
2727
return Vector(self.x * scalar, self.y * scalar)
2828

29-
30-
def main():
31-
v1 = Vector(2, 4)
32-
v2 = Vector(2, 1)
33-
print('v1 + v2:', v1 + v2)
34-
35-
v = Vector(3, 4)
36-
print('abs(v):', abs(v))
37-
38-
print('v * 3:', v * 3)
39-
40-
41-
if __name__ == '__main__':
42-
main()
29+
def __eq__(self, other):
30+
return self.x == other.x and self.y == other.y

python_sandbox/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
hydra-core==0.11.3
22
pyyaml==5.3.1
3+
pytest==7.1.3

0 commit comments

Comments
 (0)