ch17: update from book draft
This commit is contained in:
@@ -17,7 +17,8 @@ class ArithmeticProgression:
|
||||
self.end = end # None -> "infinite" series
|
||||
|
||||
def __iter__(self):
|
||||
result = type(self.begin + self.step)(self.begin)
|
||||
result_type = type(self.begin + self.step)
|
||||
result = result_type(self.begin)
|
||||
forever = self.end is None
|
||||
while forever or result < self.end:
|
||||
yield result
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
Arithmetic progression class
|
||||
|
||||
# BEGIN ARITPROG_CLASS_DEMO
|
||||
# tag::ARITPROG_CLASS_DEMO[]
|
||||
|
||||
>>> ap = ArithmeticProgression(0, 1, 3)
|
||||
>>> list(ap)
|
||||
@@ -21,24 +21,25 @@ Arithmetic progression class
|
||||
>>> list(ap)
|
||||
[Decimal('0.0'), Decimal('0.1'), Decimal('0.2')]
|
||||
|
||||
# END ARITPROG_CLASS_DEMO
|
||||
# end::ARITPROG_CLASS_DEMO[]
|
||||
"""
|
||||
|
||||
|
||||
# BEGIN ARITPROG_CLASS
|
||||
# tag::ARITPROG_CLASS[]
|
||||
class ArithmeticProgression:
|
||||
|
||||
def __init__(self, begin, step, end=None): # <1>
|
||||
def __init__(self, begin, step, end=None): # <1>
|
||||
self.begin = begin
|
||||
self.step = step
|
||||
self.end = end # None -> "infinite" series
|
||||
|
||||
def __iter__(self):
|
||||
result = type(self.begin + self.step)(self.begin) # <2>
|
||||
forever = self.end is None # <3>
|
||||
result_type = type(self.begin + self.step) # <2>
|
||||
result = result_type(self.begin) # <3>
|
||||
forever = self.end is None # <4>
|
||||
index = 0
|
||||
while forever or result < self.end: # <4>
|
||||
yield result # <5>
|
||||
while forever or result < self.end: # <5>
|
||||
yield result # <6>
|
||||
index += 1
|
||||
result = self.begin + self.step * index # <6>
|
||||
# END ARITPROG_CLASS
|
||||
result = self.begin + self.step * index # <7>
|
||||
# end::ARITPROG_CLASS[]
|
||||
|
||||
@@ -19,7 +19,7 @@ Arithmetic progression generator function::
|
||||
"""
|
||||
|
||||
|
||||
# BEGIN ARITPROG_GENFUNC
|
||||
# tag::ARITPROG_GENFUNC[]
|
||||
def aritprog_gen(begin, step, end=None):
|
||||
result = type(begin + step)(begin)
|
||||
forever = end is None
|
||||
@@ -28,4 +28,4 @@ def aritprog_gen(begin, step, end=None):
|
||||
yield result
|
||||
index += 1
|
||||
result = begin + step * index
|
||||
# END ARITPROG_GENFUNC
|
||||
# end::ARITPROG_GENFUNC[]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# BEGIN ARITPROG_ITERTOOLS
|
||||
# tag::ARITPROG_ITERTOOLS[]
|
||||
import itertools
|
||||
|
||||
|
||||
@@ -8,4 +8,4 @@ def aritprog_gen(begin, step, end=None):
|
||||
if end is not None:
|
||||
ap_gen = itertools.takewhile(lambda n: n < end, ap_gen)
|
||||
return ap_gen
|
||||
# END ARITPROG_ITERTOOLS
|
||||
# end::ARITPROG_ITERTOOLS[]
|
||||
|
||||
@@ -8,7 +8,7 @@ Fibonacci generator implemented "by hand" without generator objects
|
||||
"""
|
||||
|
||||
|
||||
# BEGIN FIBO_BY_HAND
|
||||
# tag::FIBO_BY_HAND[]
|
||||
class Fibonacci:
|
||||
|
||||
def __iter__(self):
|
||||
@@ -28,7 +28,7 @@ class FibonacciGenerator:
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
# END FIBO_BY_HAND
|
||||
# end::FIBO_BY_HAND[]
|
||||
|
||||
# for comparison, this is the usual implementation of a Fibonacci
|
||||
# generator in Python:
|
||||
|
||||
@@ -200,11 +200,12 @@ def main(): # <4>
|
||||
' for bulk insert to CouchDB via POST to db/_bulk_docs')
|
||||
parser.add_argument(
|
||||
'-m', '--mongo', action='store_true',
|
||||
help='output individual records as separate JSON dictionaries,'
|
||||
' one per line for bulk insert to MongoDB via mongoimport utility')
|
||||
help='output individual records as separate JSON dictionaries, one'
|
||||
' per line for bulk insert to MongoDB via mongoimport utility')
|
||||
parser.add_argument(
|
||||
'-t', '--type', type=int, metavar='ISIS_JSON_TYPE', default=1,
|
||||
help='ISIS-JSON type, sets field structure: 1=string, 2=alist, 3=dict (default=1)')
|
||||
help='ISIS-JSON type, sets field structure: 1=string, 2=alist,'
|
||||
' 3=dict (default=1)')
|
||||
parser.add_argument(
|
||||
'-q', '--qty', type=int, default=DEFAULT_QTY,
|
||||
help='maximum quantity of records to read (default=ALL)')
|
||||
@@ -220,7 +221,8 @@ def main(): # <4>
|
||||
help='generate an "_id" with a random UUID for each record')
|
||||
parser.add_argument(
|
||||
'-p', '--prefix', type=str, metavar='PREFIX', default='',
|
||||
help='concatenate prefix to every numeric field tag (ex. 99 becomes "v99")')
|
||||
help='concatenate prefix to every numeric field tag'
|
||||
' (ex. 99 becomes "v99")')
|
||||
parser.add_argument(
|
||||
'-n', '--mfn', action='store_true',
|
||||
help='generate an "_id" from the MFN of each record'
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
"""
|
||||
Sentence: access words by index
|
||||
|
||||
>>> text = 'To be, or not to be, that is the question'
|
||||
>>> s = Sentence(text)
|
||||
>>> len(s)
|
||||
10
|
||||
>>> s[1], s[5]
|
||||
('be', 'be')
|
||||
>>> s
|
||||
Sentence('To be, or no... the question')
|
||||
|
||||
"""
|
||||
|
||||
# tag::SENTENCE_SEQ[]
|
||||
import re
|
||||
import reprlib
|
||||
|
||||
@@ -17,8 +28,10 @@ class Sentence:
|
||||
def __getitem__(self, index):
|
||||
return self.words[index] # <2>
|
||||
|
||||
def __len__(self, index): # <3>
|
||||
def __len__(self): # <3>
|
||||
return len(self.words)
|
||||
|
||||
def __repr__(self):
|
||||
return 'Sentence(%s)' % reprlib.repr(self.text) # <4>
|
||||
|
||||
# end::SENTENCE_SEQ[]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Sentence: iterate over words using a generator function
|
||||
"""
|
||||
|
||||
# tag::SENTENCE_GEN[]
|
||||
import re
|
||||
import reprlib
|
||||
|
||||
@@ -23,3 +24,5 @@ class Sentence:
|
||||
return # <3>
|
||||
|
||||
# done! <4>
|
||||
|
||||
# end::SENTENCE_GEN[]
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
Sentence: iterate over words using a generator function
|
||||
"""
|
||||
|
||||
# tag::SENTENCE_GEN2[]
|
||||
import re
|
||||
import reprlib
|
||||
|
||||
RE_WORD = re.compile(r'\w+')
|
||||
RE_WORD = re.compile('r\w+')
|
||||
|
||||
|
||||
class Sentence:
|
||||
@@ -19,3 +20,5 @@ class Sentence:
|
||||
def __iter__(self):
|
||||
for match in RE_WORD.finditer(self.text): # <2>
|
||||
yield match.group() # <3>
|
||||
|
||||
# end::SENTENCE_GEN2[]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Sentence: iterate over words using a generator expression
|
||||
"""
|
||||
|
||||
# BEGIN SENTENCE_GENEXP
|
||||
# tag::SENTENCE_GENEXP[]
|
||||
import re
|
||||
import reprlib
|
||||
|
||||
@@ -19,7 +19,7 @@ class Sentence:
|
||||
|
||||
def __iter__(self):
|
||||
return (match.group() for match in RE_WORD.finditer(self.text))
|
||||
# END SENTENCE_GENEXP
|
||||
# end::SENTENCE_GENEXP[]
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -5,7 +5,7 @@ WARNING: the Iterator Pattern is much simpler in idiomatic Python;
|
||||
see: sentence_gen*.py.
|
||||
"""
|
||||
|
||||
# BEGIN SENTENCE_ITER
|
||||
# tag::SENTENCE_ITER[]
|
||||
import re
|
||||
import reprlib
|
||||
|
||||
@@ -41,7 +41,7 @@ class SentenceIterator:
|
||||
|
||||
def __iter__(self): # <9>
|
||||
return self
|
||||
# END SENTENCE_ITER
|
||||
# end::SENTENCE_ITER[]
|
||||
|
||||
def main():
|
||||
import sys
|
||||
|
||||
7
17-it-generator/tree/4steps/tree_step0.py
Normal file
7
17-it-generator/tree/4steps/tree_step0.py
Normal file
@@ -0,0 +1,7 @@
|
||||
def tree(cls):
|
||||
yield cls.__name__
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for cls_name in tree(BaseException):
|
||||
print(cls_name)
|
||||
10
17-it-generator/tree/4steps/tree_step1.py
Normal file
10
17-it-generator/tree/4steps/tree_step1.py
Normal file
@@ -0,0 +1,10 @@
|
||||
def tree(cls):
|
||||
yield cls.__name__, 0
|
||||
for sub_cls in cls.__subclasses__():
|
||||
yield sub_cls.__name__, 1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for cls_name, level in tree(BaseException):
|
||||
indent = ' ' * 4 * level
|
||||
print(f'{indent}{cls_name}')
|
||||
12
17-it-generator/tree/4steps/tree_step2.py
Normal file
12
17-it-generator/tree/4steps/tree_step2.py
Normal file
@@ -0,0 +1,12 @@
|
||||
def tree(cls):
|
||||
yield cls.__name__, 0
|
||||
for sub_cls in cls.__subclasses__():
|
||||
yield sub_cls.__name__, 1
|
||||
for sub_sub_cls in sub_cls.__subclasses__():
|
||||
yield sub_sub_cls.__name__, 2
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for cls_name, level in tree(BaseException):
|
||||
indent = ' ' * 4 * level
|
||||
print(f'{indent}{cls_name}')
|
||||
10
17-it-generator/tree/4steps/tree_step3.py
Normal file
10
17-it-generator/tree/4steps/tree_step3.py
Normal file
@@ -0,0 +1,10 @@
|
||||
def tree(cls, level=0):
|
||||
yield cls.__name__, level
|
||||
for sub_cls in cls.__subclasses__():
|
||||
yield from tree(sub_cls, level + 1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for cls_name, level in tree(BaseException):
|
||||
indent = ' ' * 4 * level
|
||||
print(f'{indent}{cls_name}')
|
||||
31
17-it-generator/tree/extra/pretty_tree.py
Normal file
31
17-it-generator/tree/extra/pretty_tree.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from tree import tree
|
||||
|
||||
SPACES = ' ' * 4
|
||||
HLINE = '\u2500' # ─ BOX DRAWINGS LIGHT HORIZONTAL
|
||||
HLINE2 = HLINE * 2
|
||||
ELBOW = f'\u2514{HLINE2} ' # └ BOX DRAWINGS LIGHT UP AND RIGHT
|
||||
TEE = f'\u251C{HLINE2} ' # ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT
|
||||
PIPE = f'\u2502 ' # │ BOX DRAWINGS LIGHT VERTICAL
|
||||
|
||||
|
||||
def render_lines(tree_iter):
|
||||
name, _, _ = next(tree_iter)
|
||||
yield name
|
||||
prefix = ''
|
||||
|
||||
for name, level, last in tree_iter:
|
||||
if last:
|
||||
connector = ELBOW
|
||||
else:
|
||||
connector = TEE
|
||||
|
||||
prefix = prefix[:4 * (level-1)]
|
||||
prefix = prefix.replace(TEE, PIPE).replace(ELBOW, SPACES)
|
||||
prefix += connector
|
||||
|
||||
yield prefix + name
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for line in render_lines(tree(BaseException)):
|
||||
print(line)
|
||||
105
17-it-generator/tree/extra/test_pretty_tree.py
Normal file
105
17-it-generator/tree/extra/test_pretty_tree.py
Normal file
@@ -0,0 +1,105 @@
|
||||
import pytest
|
||||
|
||||
from pretty_tree import tree, render_lines
|
||||
|
||||
def test_1_level():
|
||||
result = list(render_lines(tree(BrokenPipeError)))
|
||||
expected = [
|
||||
'BrokenPipeError',
|
||||
]
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_2_levels_1_leaf():
|
||||
result = list(render_lines(tree(IndentationError)))
|
||||
expected = [
|
||||
'IndentationError',
|
||||
'└── TabError',
|
||||
]
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_3_levels_1_leaf():
|
||||
class X: pass
|
||||
class Y(X): pass
|
||||
class Z(Y): pass
|
||||
result = list(render_lines(tree(X)))
|
||||
expected = [
|
||||
'X',
|
||||
'└── Y',
|
||||
' └── Z',
|
||||
]
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_4_levels_1_leaf():
|
||||
class Level0: pass
|
||||
class Level1(Level0): pass
|
||||
class Level2(Level1): pass
|
||||
class Level3(Level2): pass
|
||||
|
||||
result = list(render_lines(tree(Level0)))
|
||||
expected = [
|
||||
'Level0',
|
||||
'└── Level1',
|
||||
' └── Level2',
|
||||
' └── Level3',
|
||||
]
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_2_levels_4_leaves():
|
||||
class Branch: pass
|
||||
class Leaf1(Branch): pass
|
||||
class Leaf2(Branch): pass
|
||||
class Leaf3(Branch): pass
|
||||
class Leaf4(Branch): pass
|
||||
result = list(render_lines(tree(Branch)))
|
||||
expected = [
|
||||
'Branch',
|
||||
'├── Leaf1',
|
||||
'├── Leaf2',
|
||||
'├── Leaf3',
|
||||
'└── Leaf4',
|
||||
]
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_3_levels_2_leaves():
|
||||
class A: pass
|
||||
class B(A): pass
|
||||
class C(B): pass
|
||||
class D(A): pass
|
||||
class E(D): pass
|
||||
|
||||
result = list(render_lines(tree(A)))
|
||||
expected = [
|
||||
'A',
|
||||
'├── B',
|
||||
'│ └── C',
|
||||
'└── D',
|
||||
' └── E',
|
||||
]
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_4_levels_4_leaves():
|
||||
class A: pass
|
||||
class B1(A): pass
|
||||
class C1(B1): pass
|
||||
class D1(C1): pass
|
||||
class D2(C1): pass
|
||||
class C2(B1): pass
|
||||
class B2(A): pass
|
||||
expected = [
|
||||
'A',
|
||||
'├── B1',
|
||||
'│ ├── C1',
|
||||
'│ │ ├── D1',
|
||||
'│ │ └── D2',
|
||||
'│ └── C2',
|
||||
'└── B2',
|
||||
]
|
||||
|
||||
result = list(render_lines(tree(A)))
|
||||
assert expected == result
|
||||
94
17-it-generator/tree/extra/test_tree.py
Normal file
94
17-it-generator/tree/extra/test_tree.py
Normal file
@@ -0,0 +1,94 @@
|
||||
from tree import tree
|
||||
|
||||
|
||||
def test_1_level():
|
||||
class One: pass
|
||||
expected = [('One', 0, True)]
|
||||
result = list(tree(One))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_2_levels_4_leaves():
|
||||
class Branch: pass
|
||||
class Leaf1(Branch): pass
|
||||
class Leaf2(Branch): pass
|
||||
class Leaf3(Branch): pass
|
||||
class Leaf4(Branch): pass
|
||||
expected = [
|
||||
('Branch', 0, True),
|
||||
('Leaf1', 1, False),
|
||||
('Leaf2', 1, False),
|
||||
('Leaf3', 1, False),
|
||||
('Leaf4', 1, True),
|
||||
]
|
||||
result = list(tree(Branch))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_3_levels_1_leaf():
|
||||
class X: pass
|
||||
class Y(X): pass
|
||||
class Z(Y): pass
|
||||
expected = [
|
||||
('X', 0, True),
|
||||
('Y', 1, True),
|
||||
('Z', 2, True),
|
||||
]
|
||||
result = list(tree(X))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_4_levels_1_leaf():
|
||||
class Level0: pass
|
||||
class Level1(Level0): pass
|
||||
class Level2(Level1): pass
|
||||
class Level3(Level2): pass
|
||||
expected = [
|
||||
('Level0', 0, True),
|
||||
('Level1', 1, True),
|
||||
('Level2', 2, True),
|
||||
('Level3', 3, True),
|
||||
]
|
||||
|
||||
result = list(tree(Level0))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_4_levels_3_leaves():
|
||||
class A: pass
|
||||
class B1(A): pass
|
||||
class C1(B1): pass
|
||||
class D1(C1): pass
|
||||
class B2(A): pass
|
||||
class D2(C1): pass
|
||||
class C2(B2): pass
|
||||
expected = [
|
||||
('A', 0, True),
|
||||
('B1', 1, False),
|
||||
('C1', 2, True),
|
||||
('D1', 3, False),
|
||||
('D2', 3, True),
|
||||
('B2', 1, True),
|
||||
('C2', 2, True),
|
||||
]
|
||||
|
||||
result = list(tree(A))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_many_levels_1_leaf():
|
||||
class Root: pass
|
||||
level_count = 100
|
||||
expected = [('Root', 0, True)]
|
||||
parent = Root
|
||||
for level in range(1, level_count):
|
||||
name = f'Sub{level}'
|
||||
cls = type(name, (parent,), {})
|
||||
expected.append((name, level, True))
|
||||
parent = cls
|
||||
|
||||
result = list(tree(Root))
|
||||
assert len(result) == level_count
|
||||
assert result[0] == ('Root', 0, True)
|
||||
assert result[-1] == ('Sub99', 99, True)
|
||||
assert expected == result
|
||||
13
17-it-generator/tree/extra/tree.py
Normal file
13
17-it-generator/tree/extra/tree.py
Normal file
@@ -0,0 +1,13 @@
|
||||
def tree(cls, level=0, last_in_level=True):
|
||||
yield cls.__name__, level, last_in_level
|
||||
subclasses = cls.__subclasses__()
|
||||
if subclasses:
|
||||
last = subclasses[-1]
|
||||
for sub_cls in subclasses:
|
||||
yield from tree(sub_cls, level+1, sub_cls is last)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for cls_name, level, _ in tree(BaseException):
|
||||
indent = ' ' * 4 * level
|
||||
print(f'{indent}{cls_name}')
|
||||
8
17-it-generator/tree/step0/test_tree.py
Normal file
8
17-it-generator/tree/step0/test_tree.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from tree import tree
|
||||
|
||||
|
||||
def test_1_level():
|
||||
class One: pass
|
||||
expected = ['One']
|
||||
result = list(tree(One))
|
||||
assert expected == result
|
||||
7
17-it-generator/tree/step0/tree.py
Normal file
7
17-it-generator/tree/step0/tree.py
Normal file
@@ -0,0 +1,7 @@
|
||||
def tree(cls):
|
||||
yield cls.__name__
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for cls_name in tree(BaseException):
|
||||
print(cls_name)
|
||||
25
17-it-generator/tree/step1/test_tree.py
Normal file
25
17-it-generator/tree/step1/test_tree.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from tree import tree
|
||||
|
||||
|
||||
def test_1_level():
|
||||
class One: pass
|
||||
expected = [('One', 0)]
|
||||
result = list(tree(One))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_2_levels_4_leaves():
|
||||
class Branch: pass
|
||||
class Leaf1(Branch): pass
|
||||
class Leaf2(Branch): pass
|
||||
class Leaf3(Branch): pass
|
||||
class Leaf4(Branch): pass
|
||||
expected = [
|
||||
('Branch', 0),
|
||||
('Leaf1', 1),
|
||||
('Leaf2', 1),
|
||||
('Leaf3', 1),
|
||||
('Leaf4', 1),
|
||||
]
|
||||
result = list(tree(Branch))
|
||||
assert expected == result
|
||||
10
17-it-generator/tree/step1/tree.py
Normal file
10
17-it-generator/tree/step1/tree.py
Normal file
@@ -0,0 +1,10 @@
|
||||
def tree(cls):
|
||||
yield cls.__name__, 0 # <1>
|
||||
for sub_cls in cls.__subclasses__(): # <2>
|
||||
yield sub_cls.__name__, 1 # <3>
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for cls_name, level in tree(BaseException):
|
||||
indent = ' ' * 4 * level # <4>
|
||||
print(f'{indent}{cls_name}')
|
||||
25
17-it-generator/tree/step2/test_tree.py
Normal file
25
17-it-generator/tree/step2/test_tree.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from tree import tree
|
||||
|
||||
|
||||
def test_1_level():
|
||||
class One: pass
|
||||
expected = [('One', 0)]
|
||||
result = list(tree(One))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_2_levels_4_leaves():
|
||||
class Branch: pass
|
||||
class Leaf1(Branch): pass
|
||||
class Leaf2(Branch): pass
|
||||
class Leaf3(Branch): pass
|
||||
class Leaf4(Branch): pass
|
||||
expected = [
|
||||
('Branch', 0),
|
||||
('Leaf1', 1),
|
||||
('Leaf2', 1),
|
||||
('Leaf3', 1),
|
||||
('Leaf4', 1),
|
||||
]
|
||||
result = list(tree(Branch))
|
||||
assert expected == result
|
||||
14
17-it-generator/tree/step2/tree.py
Normal file
14
17-it-generator/tree/step2/tree.py
Normal file
@@ -0,0 +1,14 @@
|
||||
def tree(cls):
|
||||
yield cls.__name__, 0
|
||||
yield from sub_tree(cls) # <1>
|
||||
|
||||
|
||||
def sub_tree(cls):
|
||||
for sub_cls in cls.__subclasses__():
|
||||
yield sub_cls.__name__, 1 # <2>
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for cls_name, level in tree(BaseException):
|
||||
indent = ' ' * 4 * level
|
||||
print(f'{indent}{cls_name}')
|
||||
38
17-it-generator/tree/step3/test_tree.py
Normal file
38
17-it-generator/tree/step3/test_tree.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from tree import tree
|
||||
|
||||
|
||||
def test_1_level():
|
||||
class One: pass
|
||||
expected = [('One', 0)]
|
||||
result = list(tree(One))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_2_levels_4_leaves():
|
||||
class Branch: pass
|
||||
class Leaf1(Branch): pass
|
||||
class Leaf2(Branch): pass
|
||||
class Leaf3(Branch): pass
|
||||
class Leaf4(Branch): pass
|
||||
expected = [
|
||||
('Branch', 0),
|
||||
('Leaf1', 1),
|
||||
('Leaf2', 1),
|
||||
('Leaf3', 1),
|
||||
('Leaf4', 1),
|
||||
]
|
||||
result = list(tree(Branch))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_3_levels_1_leaf():
|
||||
class X: pass
|
||||
class Y(X): pass
|
||||
class Z(Y): pass
|
||||
expected = [
|
||||
('X', 0),
|
||||
('Y', 1),
|
||||
('Z', 2),
|
||||
]
|
||||
result = list(tree(X))
|
||||
assert expected == result
|
||||
16
17-it-generator/tree/step3/tree.py
Normal file
16
17-it-generator/tree/step3/tree.py
Normal file
@@ -0,0 +1,16 @@
|
||||
def tree(cls):
|
||||
yield cls.__name__, 0
|
||||
yield from sub_tree(cls)
|
||||
|
||||
|
||||
def sub_tree(cls):
|
||||
for sub_cls in cls.__subclasses__():
|
||||
yield sub_cls.__name__, 1
|
||||
for sub_sub_cls in sub_cls.__subclasses__():
|
||||
yield sub_sub_cls.__name__, 2
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for cls_name, level in tree(BaseException):
|
||||
indent = ' ' * 4 * level
|
||||
print(f'{indent}{cls_name}')
|
||||
76
17-it-generator/tree/step4/test_tree.py
Normal file
76
17-it-generator/tree/step4/test_tree.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from tree import tree
|
||||
|
||||
|
||||
def test_1_level():
|
||||
class One: pass
|
||||
expected = [('One', 0)]
|
||||
result = list(tree(One))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_2_levels_4_leaves():
|
||||
class Branch: pass
|
||||
class Leaf1(Branch): pass
|
||||
class Leaf2(Branch): pass
|
||||
class Leaf3(Branch): pass
|
||||
class Leaf4(Branch): pass
|
||||
expected = [
|
||||
('Branch', 0),
|
||||
('Leaf1', 1),
|
||||
('Leaf2', 1),
|
||||
('Leaf3', 1),
|
||||
('Leaf4', 1),
|
||||
]
|
||||
result = list(tree(Branch))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_3_levels_1_leaf():
|
||||
class X: pass
|
||||
class Y(X): pass
|
||||
class Z(Y): pass
|
||||
expected = [
|
||||
('X', 0),
|
||||
('Y', 1),
|
||||
('Z', 2),
|
||||
]
|
||||
result = list(tree(X))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_4_levels_1_leaf():
|
||||
class Level0: pass
|
||||
class Level1(Level0): pass
|
||||
class Level2(Level1): pass
|
||||
class Level3(Level2): pass
|
||||
expected = [
|
||||
('Level0', 0),
|
||||
('Level1', 1),
|
||||
('Level2', 2),
|
||||
('Level3', 3),
|
||||
]
|
||||
|
||||
result = list(tree(Level0))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_4_levels_3_leaves():
|
||||
class A: pass
|
||||
class B1(A): pass
|
||||
class C1(B1): pass
|
||||
class D1(C1): pass
|
||||
class B2(A): pass
|
||||
class D2(C1): pass
|
||||
class C2(B2): pass
|
||||
expected = [
|
||||
('A', 0),
|
||||
('B1', 1),
|
||||
('C1', 2),
|
||||
('D1', 3),
|
||||
('D2', 3),
|
||||
('B2', 1),
|
||||
('C2', 2),
|
||||
]
|
||||
|
||||
result = list(tree(A))
|
||||
assert expected == result
|
||||
20
17-it-generator/tree/step4/tree.py
Normal file
20
17-it-generator/tree/step4/tree.py
Normal file
@@ -0,0 +1,20 @@
|
||||
def tree(cls):
|
||||
yield cls.__name__, 0
|
||||
yield from sub_tree(cls)
|
||||
|
||||
|
||||
# tag::SUB_TREE[]
|
||||
def sub_tree(cls):
|
||||
for sub_cls in cls.__subclasses__():
|
||||
yield sub_cls.__name__, 1
|
||||
for sub_sub_cls in sub_cls.__subclasses__():
|
||||
yield sub_sub_cls.__name__, 2
|
||||
for sub_sub_sub_cls in sub_sub_cls.__subclasses__():
|
||||
yield sub_sub_sub_cls.__name__, 3
|
||||
# end::SUB_TREE[]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for cls_name, level in tree(BaseException):
|
||||
indent = ' ' * 4 * level
|
||||
print(f'{indent}{cls_name}')
|
||||
94
17-it-generator/tree/step5/test_tree.py
Normal file
94
17-it-generator/tree/step5/test_tree.py
Normal file
@@ -0,0 +1,94 @@
|
||||
from tree import tree
|
||||
|
||||
|
||||
def test_1_level():
|
||||
class One: pass
|
||||
expected = [('One', 0)]
|
||||
result = list(tree(One))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_2_levels_4_leaves():
|
||||
class Branch: pass
|
||||
class Leaf1(Branch): pass
|
||||
class Leaf2(Branch): pass
|
||||
class Leaf3(Branch): pass
|
||||
class Leaf4(Branch): pass
|
||||
expected = [
|
||||
('Branch', 0),
|
||||
('Leaf1', 1),
|
||||
('Leaf2', 1),
|
||||
('Leaf3', 1),
|
||||
('Leaf4', 1),
|
||||
]
|
||||
result = list(tree(Branch))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_3_levels_1_leaf():
|
||||
class X: pass
|
||||
class Y(X): pass
|
||||
class Z(Y): pass
|
||||
expected = [
|
||||
('X', 0),
|
||||
('Y', 1),
|
||||
('Z', 2),
|
||||
]
|
||||
result = list(tree(X))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_4_levels_1_leaf():
|
||||
class Level0: pass
|
||||
class Level1(Level0): pass
|
||||
class Level2(Level1): pass
|
||||
class Level3(Level2): pass
|
||||
expected = [
|
||||
('Level0', 0),
|
||||
('Level1', 1),
|
||||
('Level2', 2),
|
||||
('Level3', 3),
|
||||
]
|
||||
|
||||
result = list(tree(Level0))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_4_levels_3_leaves():
|
||||
class A: pass
|
||||
class B1(A): pass
|
||||
class C1(B1): pass
|
||||
class D1(C1): pass
|
||||
class B2(A): pass
|
||||
class D2(C1): pass
|
||||
class C2(B2): pass
|
||||
expected = [
|
||||
('A', 0),
|
||||
('B1', 1),
|
||||
('C1', 2),
|
||||
('D1', 3),
|
||||
('D2', 3),
|
||||
('B2', 1),
|
||||
('C2', 2),
|
||||
]
|
||||
|
||||
result = list(tree(A))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_many_levels_1_leaf():
|
||||
class Root: pass
|
||||
level_count = 100
|
||||
expected = [('Root', 0)]
|
||||
parent = Root
|
||||
for level in range(1, level_count):
|
||||
name = f'Sub{level}'
|
||||
cls = type(name, (parent,), {})
|
||||
expected.append((name, level))
|
||||
parent = cls
|
||||
|
||||
result = list(tree(Root))
|
||||
assert len(result) == level_count
|
||||
assert result[0] == ('Root', 0)
|
||||
assert result[-1] == ('Sub99', 99)
|
||||
assert expected == result
|
||||
15
17-it-generator/tree/step5/tree.py
Normal file
15
17-it-generator/tree/step5/tree.py
Normal file
@@ -0,0 +1,15 @@
|
||||
def tree(cls):
|
||||
yield cls.__name__, 0
|
||||
yield from sub_tree(cls, 1)
|
||||
|
||||
|
||||
def sub_tree(cls, level):
|
||||
for sub_cls in cls.__subclasses__():
|
||||
yield sub_cls.__name__, level
|
||||
yield from sub_tree(sub_cls, level+1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for cls_name, level in tree(BaseException):
|
||||
indent = ' ' * 4 * level
|
||||
print(f'{indent}{cls_name}')
|
||||
94
17-it-generator/tree/step6/test_tree.py
Normal file
94
17-it-generator/tree/step6/test_tree.py
Normal file
@@ -0,0 +1,94 @@
|
||||
from tree import tree
|
||||
|
||||
|
||||
def test_1_level():
|
||||
class One: pass
|
||||
expected = [('One', 0)]
|
||||
result = list(tree(One))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_2_levels_4_leaves():
|
||||
class Branch: pass
|
||||
class Leaf1(Branch): pass
|
||||
class Leaf2(Branch): pass
|
||||
class Leaf3(Branch): pass
|
||||
class Leaf4(Branch): pass
|
||||
expected = [
|
||||
('Branch', 0),
|
||||
('Leaf1', 1),
|
||||
('Leaf2', 1),
|
||||
('Leaf3', 1),
|
||||
('Leaf4', 1),
|
||||
]
|
||||
result = list(tree(Branch))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_3_levels_1_leaf():
|
||||
class X: pass
|
||||
class Y(X): pass
|
||||
class Z(Y): pass
|
||||
expected = [
|
||||
('X', 0),
|
||||
('Y', 1),
|
||||
('Z', 2),
|
||||
]
|
||||
result = list(tree(X))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_4_levels_1_leaf():
|
||||
class Level0: pass
|
||||
class Level1(Level0): pass
|
||||
class Level2(Level1): pass
|
||||
class Level3(Level2): pass
|
||||
expected = [
|
||||
('Level0', 0),
|
||||
('Level1', 1),
|
||||
('Level2', 2),
|
||||
('Level3', 3),
|
||||
]
|
||||
|
||||
result = list(tree(Level0))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_4_levels_3_leaves():
|
||||
class A: pass
|
||||
class B1(A): pass
|
||||
class C1(B1): pass
|
||||
class D1(C1): pass
|
||||
class B2(A): pass
|
||||
class D2(C1): pass
|
||||
class C2(B2): pass
|
||||
expected = [
|
||||
('A', 0),
|
||||
('B1', 1),
|
||||
('C1', 2),
|
||||
('D1', 3),
|
||||
('D2', 3),
|
||||
('B2', 1),
|
||||
('C2', 2),
|
||||
]
|
||||
|
||||
result = list(tree(A))
|
||||
assert expected == result
|
||||
|
||||
|
||||
def test_many_levels_1_leaf():
|
||||
class Root: pass
|
||||
level_count = 100
|
||||
expected = [('Root', 0)]
|
||||
parent = Root
|
||||
for level in range(1, level_count):
|
||||
name = f'Sub{level}'
|
||||
cls = type(name, (parent,), {})
|
||||
expected.append((name, level))
|
||||
parent = cls
|
||||
|
||||
result = list(tree(Root))
|
||||
assert len(result) == level_count
|
||||
assert result[0] == ('Root', 0)
|
||||
assert result[-1] == ('Sub99', 99)
|
||||
assert expected == result
|
||||
10
17-it-generator/tree/step6/tree.py
Normal file
10
17-it-generator/tree/step6/tree.py
Normal file
@@ -0,0 +1,10 @@
|
||||
def tree(cls, level=0):
|
||||
yield cls.__name__, level
|
||||
for sub_cls in cls.__subclasses__():
|
||||
yield from tree(sub_cls, level+1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for cls_name, level in tree(BaseException):
|
||||
indent = ' ' * 4 * level
|
||||
print(f'{indent}{cls_name}')
|
||||
@@ -14,7 +14,7 @@ Daniel Patterson, Junsong Li, Anand Chitipothu, and Shriram Krishnamurthi.
|
||||
DOI=10.1145/2544173.2509536 http://doi.acm.org/10.1145/2544173.2509536
|
||||
"""
|
||||
|
||||
# BEGIN YIELD_DELEGATE_FAIL
|
||||
# tag::YIELD_DELEGATE_FAIL[]
|
||||
def f():
|
||||
def do_yield(n):
|
||||
yield n
|
||||
@@ -22,7 +22,7 @@ def f():
|
||||
while True:
|
||||
x += 1
|
||||
do_yield(x)
|
||||
# END YIELD_DELEGATE_FAIL
|
||||
# end::YIELD_DELEGATE_FAIL[]
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('Invoking f() results in an infinite loop')
|
||||
|
||||
@@ -5,7 +5,7 @@ yielding.
|
||||
|
||||
"""
|
||||
|
||||
# BEGIN YIELD_DELEGATE_FIX
|
||||
# tag::YIELD_DELEGATE_FIX[]
|
||||
def f():
|
||||
def do_yield(n):
|
||||
yield n
|
||||
@@ -13,7 +13,7 @@ def f():
|
||||
while True:
|
||||
x += 1
|
||||
yield from do_yield(x)
|
||||
# END YIELD_DELEGATE_FIX
|
||||
# end::YIELD_DELEGATE_FIX[]
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('Invoking f() now produces a generator')
|
||||
|
||||
Reference in New Issue
Block a user