Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit cbd1388

Browse files
committed
updates to ch.14
1 parent b4ad845 commit cbd1388

File tree

4 files changed

+233
-16
lines changed

4 files changed

+233
-16
lines changed

‎14-inheritance/README.rst‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Sample code for Chapter 14 - "Inheritance: for good or for worse"
1+
Sample code for Chapter 14 - "Inheritance: for better or for worse"
22

33
From the book "Fluent Python, Second Edition" by Luciano Ramalho (O'Reilly, 2021)
44
https://learning.oreilly.com/library/view/fluent-python-2nd/9781492056348/

‎14-inheritance/diamond.py‎

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,62 @@
1-
class A:
2-
def ping(self):
3-
print('ping:', self)
1+
"""
2+
diamond1.py: Demo of diamond-shaped class graph.
43
4+
# tag::LEAF_MRO[]
5+
>>> Leaf.__mro__ # doctest:+NORMALIZE_WHITESPACE
6+
(<class 'diamond1.Leaf'>, <class 'diamond1.A'>, <class 'diamond1.B'>,
7+
<class 'diamond1.Root'>, <class 'object'>)
58
6-
class B(A):
7-
def pong(self):
8-
print('pong:', self)
9+
# end::LEAF_MRO[]
10+
11+
# tag::DIAMOND_CALLS[]
12+
>>> leaf1 = Leaf() # <1>
13+
>>> leaf1.ping() # <2>
14+
<instance of Leaf>.ping() in Leaf
15+
<instance of Leaf>.ping() in A
16+
<instance of Leaf>.ping() in B
17+
<instance of Leaf>.ping() in Root
918
19+
>>> leaf1.pong() # <3>
20+
<instance of Leaf>.pong() in A
21+
<instance of Leaf>.pong() in B
22+
23+
# end::DIAMOND_CALLS[]
24+
"""
25+
26+
# tag::DIAMOND_CLASSES[]
27+
class Root: # <1>
28+
def ping(self):
29+
print(f'{self}.ping() in Root')
1030

11-
class C(A):
1231
def pong(self):
13-
print('PONG:', self)
32+
print(f'{self}.pong() in Root')
1433

34+
def __repr__(self):
35+
cls_name = type(self).__name__
36+
return f'<instance of {cls_name}>'
1537

16-
class D(B, C):
1738

39+
class A(Root): # <2>
1840
def ping(self):
41+
print(f'{self}.ping() in A')
1942
super().ping()
20-
print('post-ping:', self)
2143

22-
def pingpong(self):
23-
self.ping()
24-
super().ping()
25-
self.pong()
44+
def pong(self):
45+
print(f'{self}.pong() in A')
2646
super().pong()
27-
C.pong(self)
47+
48+
49+
class B(Root): # <3>
50+
def ping(self):
51+
print(f'{self}.ping() in B')
52+
super().ping()
53+
54+
def pong(self):
55+
print(f'{self}.pong() in B')
56+
57+
58+
class Leaf(A, B): # <4>
59+
def ping(self):
60+
print(f'{self}.ping() in Leaf')
61+
super().ping()
62+
# end::DIAMOND_CLASSES[]

‎14-inheritance/diamond2.py‎

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""
2+
unrelated.py: examples with ``super()`` in a sibling class.
3+
4+
``U`` is unrelated (does not subclass ``Root``)
5+
6+
Calling ``ping`` on an instance of ``U`` fails::
7+
8+
# tag::UNRELATED_DEMO_1[]
9+
>>> u = U()
10+
>>> u.ping()
11+
Traceback (most recent call last):
12+
...
13+
AttributeError: 'super' object has no attribute 'ping'
14+
15+
# end::UNRELATED_DEMO_1[]
16+
17+
18+
But if ``U`` is part of a cooperative arrangement of base classes,
19+
its ``ping`` method works::
20+
21+
# tag::UNRELATED_DEMO_2[]
22+
23+
>>> leaf2 = LeafUA()
24+
>>> leaf2.ping()
25+
<instance of LeafUA>.ping() in LeafUA
26+
<instance of LeafUA>.ping() in U
27+
<instance of LeafUA>.ping() in A
28+
<instance of LeafUA>.ping() in Root
29+
>>> LeafUA.__mro__ # doctest:+NORMALIZE_WHITESPACE
30+
(<class 'diamond2.LeafUA'>, <class 'diamond2.U'>,
31+
<class 'diamond.A'>, <class 'diamond.Root'>, <class 'object'>)
32+
33+
# end::UNRELATED_DEMO_2[]
34+
35+
36+
Here ``U.ping`` is never called because ``Root.ping`` does not call ``super``.
37+
38+
>>> o6 = LeafAU()
39+
>>> o6.ping()
40+
<instance of LeafAU>.ping() in LeafAU
41+
<instance of LeafAU>.ping() in A
42+
<instance of LeafAU>.ping() in Root
43+
>>> LeafAU.__mro__ # doctest:+NORMALIZE_WHITESPACE
44+
(<class 'diamond2.LeafAU'>, <class 'diamond.A'>, <class 'diamond.Root'>,
45+
<class 'diamond2.U'>, <class 'object'>)
46+
47+
"""
48+
49+
# tag::DIAMOND_CLASSES[]
50+
from diamond import A # <1>
51+
52+
class U(): # <2>
53+
def ping(self):
54+
print(f'{self}.ping() in U')
55+
super().ping() # <3>
56+
57+
class LeafUA(U, A): # <4>
58+
def ping(self):
59+
print(f'{self}.ping() in LeafUA')
60+
super().ping()
61+
# end::DIAMOND_CLASSES[]
62+
63+
class LeafAU(A, U):
64+
def ping(self):
65+
print(f'{self}.ping() in LeafAU')
66+
super().ping()
67+

‎14-inheritance/uppermixin.py‎

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
"""UpperDict uppercases all string keys.
2+
3+
Test for initializer. `str` keys are uppercased::
4+
5+
>>> d = UpperDict([('a', 'letter A'), ('B', 'letter B'), (2, 'digit two')])
6+
>>> list(d.keys())
7+
['A', 'B', 2]
8+
9+
Tests for item retrieval using `d[key]` notation::
10+
11+
>>> d['A']
12+
'letter A'
13+
>>> d['b']
14+
'letter B'
15+
>>> d[2]
16+
'digit two'
17+
18+
19+
Tests for missing key::
20+
21+
>>> d['z']
22+
Traceback (most recent call last):
23+
...
24+
KeyError: 'Z'
25+
>>> d[99]
26+
Traceback (most recent call last):
27+
...
28+
KeyError: 99
29+
30+
31+
Tests for item retrieval using `d.get(key)` notation::
32+
33+
>>> d.get('a')
34+
'letter A'
35+
>>> d.get('B')
36+
'letter B'
37+
>>> d.get(2)
38+
'digit two'
39+
>>> d.get('z', '(not found)')
40+
'(not found)'
41+
42+
Tests for the `in` operator::
43+
44+
>>> ('a' in d, 'B' in d, 'z' in d)
45+
(True, True, False)
46+
47+
Test for item assignment using lowercase key::
48+
49+
>>> d['c'] = 'letter C'
50+
>>> d['C']
51+
'letter C'
52+
53+
Tests for update using a `dict` or a sequence of pairs::
54+
55+
>>> d.update({'D': 'letter D', 'e': 'letter E'})
56+
>>> list(d.keys())
57+
['A', 'B', 2, 'C', 'D', 'E']
58+
>>> d.update([('f', 'letter F'), ('G', 'letter G')])
59+
>>> list(d.keys())
60+
['A', 'B', 2, 'C', 'D', 'E', 'F', 'G']
61+
>>> d # doctest:+NORMALIZE_WHITESPACE
62+
{'A': 'letter A', 'B': 'letter B', 2: 'digit two',
63+
'C': 'letter C', 'D': 'letter D', 'E': 'letter E',
64+
'F': 'letter F', 'G': 'letter G'}
65+
66+
UpperCounter uppercases all `str` keys.
67+
68+
Test for initializer: keys are uppercased.
69+
70+
>>> d = UpperCounter('AbracAdaBrA')
71+
>>> sorted(d.keys())
72+
['A', 'B', 'C', 'D', 'R']
73+
74+
Tests for count retrieval using `d[key]` notation::
75+
76+
>>> d['a']
77+
5
78+
>>> d['z']
79+
0
80+
81+
"""
82+
# tag::UPPERCASE_MIXIN[]
83+
import collections
84+
85+
86+
def _upper(key): # <1>
87+
try:
88+
return key.upper()
89+
except AttributeError:
90+
return key
91+
92+
93+
class UpperCaseMixin: # <2>
94+
def __setitem__(self, key, item):
95+
super().__setitem__(_upper(key), item)
96+
97+
def __getitem__(self, key):
98+
return super().__getitem__(_upper(key))
99+
100+
def get(self, key, default=None):
101+
return super().get(_upper(key), default)
102+
103+
def __contains__(self, key):
104+
return super().__contains__(_upper(key))
105+
# end::UPPERCASE_MIXIN[]
106+
107+
# tag::UPPERDICT[]
108+
class UpperDict(UpperCaseMixin, collections.UserDict): # <1>
109+
pass
110+
111+
112+
class UpperCounter(UpperCaseMixin, collections.Counter): # <2>
113+
"""Specialized 'Counter' that uppercases string keys""" # <3>
114+
115+
# end::UPPERDICT[]

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /