Skip to content

Commit 66bb4d5

Browse files
committed
update chpt 01 & 02
1 parent fbef8cc commit 66bb4d5

9 files changed

Lines changed: 566 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
.DS_Store
2+
!**/__pycache__/
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
>>> from frenchdeck import FrenchDeck, Card
2+
>>> beer_card = Card('7', 'diamonds')
3+
>>> beer_card
4+
Card(rank='7', suit='diamonds')
5+
>>> deck = FrenchDeck()
6+
>>> len(deck)
7+
52
8+
>>> deck[:3]
9+
[Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
10+
>>> deck[12::13]
11+
[Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'), Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')]
12+
>>> Card('Q', 'hearts') in deck
13+
True
14+
>>> Card('Z', 'clubs') in deck
15+
False
16+
>>> for card in deck: # doctest: +ELLIPSIS
17+
... print(card)
18+
Card(rank='2', suit='spades')
19+
Card(rank='3', suit='spades')
20+
Card(rank='4', suit='spades')
21+
...
22+
>>> for card in reversed(deck): # doctest: +ELLIPSIS
23+
... print(card)
24+
Card(rank='A', suit='hearts')
25+
Card(rank='K', suit='hearts')
26+
Card(rank='Q', suit='hearts')
27+
...
28+
>>> for n, card in enumerate(deck, 1): # doctest: +ELLIPSIS
29+
... print(n, card)
30+
1 Card(rank='2', suit='spades')
31+
2 Card(rank='3', suit='spades')
32+
3 Card(rank='4', suit='spades')
33+
...
34+
>>> suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
35+
>>> def spades_high(card):
36+
... rank_value = FrenchDeck.ranks.index(card.rank)
37+
... return rank_value * len(suit_values) + suit_values[card.suit]
38+
39+
Rank test:
40+
41+
>>> spades_high(Card('2', 'clubs'))
42+
0
43+
>>> spades_high(Card('A', 'spades'))
44+
51
45+
46+
>>> for card in sorted(deck, key=spades_high): # doctest: +ELLIPSIS
47+
... print(card)
48+
Card(rank='2', suit='clubs')
49+
Card(rank='2', suit='diamonds')
50+
Card(rank='2', suit='hearts')
51+
...
52+
Card(rank='A', suit='diamonds')
53+
Card(rank='A', suit='hearts')
54+
Card(rank='A', suit='spades')
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import collections
2+
3+
Card = collections.namedtuple('Card', ['rank', 'suit'])
4+
5+
# python3 -m doctest frenchdeck.doctest -v
6+
7+
# python的special methods(magic method)的使用例子
8+
# 支持sequence的操作
9+
# __getitem__ delegates to the [] operator
10+
11+
12+
class FrenchDeck:
13+
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
14+
suits = 'spades diamonds clubs hearts'.split()
15+
16+
def __init__(self):
17+
self._cards = [Card(rank, suit) for suit in self.suits
18+
for rank in self.ranks]
19+
20+
def __len__(self):
21+
return len(self._cards)
22+
23+
def __getitem__(self, position):
24+
return self._cards[position]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
>>> from vector2d import Vector
2+
>>> v1 = Vector(2, 4)
3+
>>> v2 = Vector(2, 1)
4+
>>> v1 + v2
5+
Vector(4, 5)
6+
>>> v = Vector(3, 4)
7+
>>> abs(v)
8+
5.0
9+
>>> v * 3
10+
Vector(9, 12)
11+
>>> abs(v * 3)
12+
15.0
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"""
2+
vector2d.py: a simplistic class demonstrating some special methods
3+
4+
It is simplistic for didactic reasons. It lacks proper error handling,
5+
especially in the ``__add__`` and ``__mul__`` methods.
6+
7+
This example is greatly expanded later in the book.
8+
9+
Addition::
10+
11+
>>> v1 = Vector(2, 4)
12+
>>> v2 = Vector(2, 1)
13+
>>> v1 + v2
14+
Vector(4, 5)
15+
16+
Absolute value::
17+
18+
>>> v = Vector(3, 4)
19+
>>> abs(v)
20+
5.0
21+
22+
Scalar multiplication::
23+
24+
>>> v * 3
25+
Vector(9, 12)
26+
>>> abs(v * 3)
27+
15.0
28+
29+
"""
30+
31+
32+
import math
33+
34+
class Vector:
35+
36+
def __init__(self, x=0, y=0):
37+
self.x = x
38+
self.y = y
39+
40+
def __repr__(self):
41+
return f'Vector({self.x!r}, {self.y!r})'
42+
43+
def __abs__(self):
44+
return math.hypot(self.x, self.y)
45+
46+
def __bool__(self):
47+
return bool(abs(self))
48+
49+
def __add__(self, other):
50+
x = self.x + other.x
51+
y = self.y + other.y
52+
return Vector(x, y)
53+
54+
def __mul__(self, scalar):
55+
return Vector(self.x * scalar, self.y * scalar)
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""
2+
List Comprehensions and Generator Expressions
3+
4+
built-in sequences
5+
- container sequences: list, tuple, collections.deque
6+
- flat sequences: str, bytes, array.array
7+
8+
memory diagram for tuple and array (Figure 2-1, page 23)
9+
10+
- mutable sequences: list, bytearray, array.array, collections.deque
11+
- immutable sequences: tuple, str, bytes
12+
13+
Built-in concrete sequence types do not subclass the Sequence and MutableSequence
14+
abstract base classes (ABCs), but they are virtual subclasses, rigistered with those ABCs
15+
(Chapter 13)
16+
17+
List Comprehensions
18+
19+
Generator Expressions
20+
save memory because it yields items one by one using iterator protocol instead of
21+
building a whole list just to feed another constructor
22+
23+
https://github.com/fluentpython/example-code-2e/tree/master/02-array-seq
24+
https://github.com/fluentpython/example-code-2e/blob/master/02-array-seq/array-seq.ipynb
25+
"""
26+
27+
from collections import abc
28+
issubclass(tuple, abc.Sequence) # True
29+
issubclass(list, abc.MutableSequence) # True
30+
31+
import array
32+
a=array.array('d',[1,2,3])
33+
# >>> a
34+
# array('d', [1.0, 2.0, 3.0])
35+
36+
37+
symbols = '$¢£¥€¤'
38+
codes = []
39+
for symbol in symbols:
40+
codes.append(ord(symbol))
41+
codes
42+
43+
symbols = '$¢£¥€¤'
44+
codes = [ord(symbol) for symbol in symbols]
45+
codes
46+
47+
# assignment expression (walnut operator)
48+
codes = [last := ord(c) for c in x]
49+
last
50+
51+
symbols = '$¢£¥€¤'
52+
beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]
53+
beyond_ascii
54+
55+
beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))
56+
beyond_ascii
57+
58+
colors = ['black', 'white']
59+
sizes = ['S', 'M', 'L']
60+
tshirts = [(color, size) for color in colors for size in sizes]
61+
tshirts
62+
63+
64+
# Initializing a tuple and an array from a generator expression
65+
symbols = '$¢£¥€¤'
66+
tuple(ord(symbol) for symbol in symbols)
67+
68+
import array
69+
array.array('I', (ord(symbol) for symbol in symbols))
70+
71+
colors = ['black', 'white']
72+
sizes = ['S', 'M', 'L']
73+
for tshirt in ('%s %s' % (c, s) for c in colors for s in sizes):
74+
print(tshirt)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""
2+
Tuples As Records VS Are Not Just Immutable Lists
3+
4+
- Tuples used as records (unnamed)
5+
- Tuples as Immutable Lists
6+
7+
To evaluate a tuple literal, Python compiler generates bytecode for a tuple constant
8+
in one operation
9+
10+
Given a tuple t, tuple(t) simply returns a reference to the same t. There is no need to copy.
11+
"""
12+
13+
# Tuples used as records
14+
lax_coordinates = (33.9425, -118.408056)
15+
city, year, pop, chg, area = ('Tokyo', 2003, 32_450, 0.66, 8014)
16+
traveler_ids = [('USA', '31195855'), ('BRA', 'CE342567'), ('ESP', 'XDA205856')]
17+
18+
for passport in sorted(traveler_ids):
19+
print('%s/%s' % passport)
20+
21+
22+
for country, _ in traveler_ids:
23+
print(country)
24+
25+
26+
# Tuples as Immutable Lists
27+
a = (10, 'alpha', [1, 2])
28+
b = (10, 'alpha', [1, 2])
29+
a == b # True
30+
31+
b[-1].append(99) # (10, 'alpha', [1, 2, 99])
32+
a == b # False
33+
34+
35+
# an object is only hashable if its value cannot ever change.
36+
# An unhashable tuple cannot be inserted as a dict key or a set element
37+
def fixed(o):
38+
try:
39+
hash(o)
40+
except TypeError:
41+
return False
42+
return True
43+
44+
45+
tf = (10, 'alpha', (1, 2)) # Contains no mutable items
46+
tm = (10, 'alpha', [1, 2]) # Contains a mutable item (list)
47+
fixed(tf) # True
48+
fixed(tm) # False
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"""
2+
Sequence unpacking and sequence patterns
3+
4+
edge cases:
5+
[record] with only one record in list
6+
(record,) with only one record in tuple
7+
8+
- Sequence unpacking
9+
- Pattern Matching with Sequences
10+
- Instances of str, byte, and bytearray are not handled as sequences in the context of match/case
11+
- Unlike unpacking, patterns do NOT destructure iterables that are not sequences (e.g., iterators)
12+
- case [name, _, _, (lat, lon) as coord]: # bind any part of a pattern with a variable using the as keyword
13+
- case [name, *_, (float(lat), float(lon))]:
14+
"""
15+
16+
# -- Sequence unpacking --
17+
# Using * to grab excess items
18+
lax_coordinates = (33.9425, -118.408056)
19+
latitude, longitude = lax_coordinates # unpacking
20+
latitude
21+
22+
t = (20, 8)
23+
divmod(*t) # (2, 4)
24+
quotient, remainder = divmod(*t)
25+
26+
import os
27+
_, filename = os.path.split('/home/luciano/.ssh/id_rsa.pub')
28+
filename
29+
30+
a, b, *rest = range(5)
31+
a, b, rest # (0, 1, [2, 3, 4])
32+
33+
a, b, *rest = range(2)
34+
a, b, rest # (0, 1, [])
35+
36+
a, *body, c, d = range(5)
37+
a, body, c, d # (0, [1, 2], 3, 4)
38+
39+
*head, b, c, d = range(5)
40+
head, b, c, d # ([0, 1], 2, 3, 4)
41+
42+
43+
# Unpacking with * in function calls and sequence literals
44+
def fun(a, b, c, d, *rest):
45+
return a, b, c, d, rest
46+
47+
48+
fun(*[1, 2], 3, *range(4, 7)) # (1, 2, 3, 4, (5, 6))
49+
*range(4), 4 # (0, 1, 2, 3, 4)
50+
[*range(4), 4] # [0, 1, 2, 3, 4]
51+
{*range(4), 4, *(5, 6, 7)} # {0, 1, 2, 3, 4, 5, 6, 7}
52+
53+
54+
# -- Pattern Matching with Sequences --
55+
# match/case sequence handlings
56+
# sequence pattern can be tuples or lists or any combination of nested tuples and lists.
57+
metro_areas = [
58+
('Tokyo', 'JP', 36.933, (35.689722, 139.691667)),
59+
('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
60+
('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
61+
('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
62+
('São Paulo', 'BR', 19.649, (-23.547778, -46.635833)),
63+
]
64+
65+
def main():
66+
print(f'{"":15} | {"latitude":>9} | {"longitude":>9}')
67+
for record in metro_areas:
68+
match record:
69+
case [name, _, _, (lat, lon)] if lon <= 0:
70+
print(f'{name:15} | {lat:9.4f} | {lon:9.4f}')
71+
main()
72+
# | latitude | longitude
73+
# Mexico City | 19.4333 | -99.1333
74+
# New York-Newark | 40.8086 | -74.0204
75+
# São Paulo | -23.5478 | -46.6358
76+
77+
78+
# Instances of str, byte, and bytearray are not handled as sequences in the context of match/case
79+
# match tuple(phone):
80+
# case ['1', *rest]:
81+
# ...
82+
# case ['2', *rest]:
83+
# ...
84+
# case ['3' | '4', *rest]:
85+
# ...

0 commit comments

Comments
 (0)