Merge pull request #3 from eumiro/py36plus
Modernize code to Python 3.6+ and some cleanup
This commit is contained in:
@@ -26,7 +26,6 @@ Scalar multiplication::
|
|||||||
>>> abs(v * 3)
|
>>> abs(v * 3)
|
||||||
15.0
|
15.0
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -39,7 +38,7 @@ class Vector:
|
|||||||
self.y = y
|
self.y = y
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'Vector(%r, %r)' % (self.x, self.y)
|
return f'Vector({self.x!r}, {self.y!r})'
|
||||||
|
|
||||||
def __abs__(self):
|
def __abs__(self):
|
||||||
return hypot(self.x, self.y)
|
return hypot(self.x, self.y)
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ if __name__ == '__main__':
|
|||||||
bisect_fn = bisect.bisect
|
bisect_fn = bisect.bisect
|
||||||
|
|
||||||
print('DEMO:', bisect_fn.__name__) # <5>
|
print('DEMO:', bisect_fn.__name__) # <5>
|
||||||
print('haystack ->', ' '.join('%2d' % n for n in HAYSTACK))
|
print('haystack ->', ' '.join(f'{n:2}' for n in HAYSTACK))
|
||||||
demo(bisect_fn)
|
demo(bisect_fn)
|
||||||
|
|
||||||
# END BISECT_DEMO
|
# END BISECT_DEMO
|
||||||
|
|||||||
@@ -9,4 +9,4 @@ my_list = []
|
|||||||
for i in range(SIZE):
|
for i in range(SIZE):
|
||||||
new_item = random.randrange(SIZE * 2)
|
new_item = random.randrange(SIZE * 2)
|
||||||
bisect.insort(my_list, new_item)
|
bisect.insort(my_list, new_item)
|
||||||
print('%2d ->' % new_item, my_list)
|
print(f'{new_item:2} ->', my_list)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ def non_ascii(c):
|
|||||||
|
|
||||||
def clock(label, cmd):
|
def clock(label, cmd):
|
||||||
res = timeit.repeat(cmd, setup=SETUP, number=TIMES)
|
res = timeit.repeat(cmd, setup=SETUP, number=TIMES)
|
||||||
print(label, *('{:.3f}'.format(x) for x in res))
|
print(label, *(f'{x:.3f}' for x in res))
|
||||||
|
|
||||||
clock('listcomp :', '[ord(s) for s in symbols if ord(s) > 127]')
|
clock('listcomp :', '[ord(s) for s in symbols if ord(s) > 127]')
|
||||||
clock('listcomp + func :', '[ord(s) for s in symbols if non_ascii(ord(s))]')
|
clock('listcomp + func :', '[ord(s) for s in symbols if non_ascii(ord(s))]')
|
||||||
|
|||||||
@@ -20,11 +20,10 @@ metro_areas = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print('{:15} | {:^9} | {:^9}'.format('', 'lat.', 'long.'))
|
print(f'{"":15} | {"lat.":^9} | {"long.":^9}')
|
||||||
fmt = '{:15} | {:9.4f} | {:9.4f}'
|
|
||||||
for name, cc, pop, (latitude, longitude) in metro_areas: # <2>
|
for name, cc, pop, (latitude, longitude) in metro_areas: # <2>
|
||||||
if longitude <= 0: # <3>
|
if longitude <= 0: # <3>
|
||||||
print(fmt.format(name, latitude, longitude))
|
print(f'{name:15} | {latitude:9.4f} | {longitude:9.4f}')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ def test(container_type, verbose):
|
|||||||
size=size, verbose=verbose)
|
size=size, verbose=verbose)
|
||||||
test = TEST.format(verbose=verbose)
|
test = TEST.format(verbose=verbose)
|
||||||
tt = timeit.repeat(stmt=test, setup=setup, repeat=5, number=1)
|
tt = timeit.repeat(stmt=test, setup=setup, repeat=5, number=1)
|
||||||
print('|{:{}d}|{:f}'.format(size, MAX_EXPONENT + 1, min(tt)))
|
print(f'|{size:{MAX_EXPONENT + 1}d}|{min(tt):f}')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if '-v' in sys.argv:
|
if '-v' in sys.argv:
|
||||||
@@ -50,6 +50,6 @@ if __name__=='__main__':
|
|||||||
else:
|
else:
|
||||||
verbose = False
|
verbose = False
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) != 2:
|
||||||
print('Usage: %s <container_type>' % sys.argv[0])
|
print(f'Usage: {sys.argv[0]} <container_type>')
|
||||||
else:
|
else:
|
||||||
test(sys.argv[1], verbose)
|
test(sys.argv[1], verbose)
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
Generate data for container performance test
|
Generate data for container performance test
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import random
|
|
||||||
import array
|
import array
|
||||||
|
import random
|
||||||
|
|
||||||
MAX_EXPONENT = 7
|
MAX_EXPONENT = 7
|
||||||
HAYSTACK_LEN = 10 ** MAX_EXPONENT
|
HAYSTACK_LEN = 10 ** MAX_EXPONENT
|
||||||
@@ -13,25 +13,25 @@ SAMPLE_LEN = HAYSTACK_LEN + NEEDLES_LEN // 2
|
|||||||
needles = array.array('d')
|
needles = array.array('d')
|
||||||
|
|
||||||
sample = {1 / random.random() for i in range(SAMPLE_LEN)}
|
sample = {1 / random.random() for i in range(SAMPLE_LEN)}
|
||||||
print('initial sample: %d elements' % len(sample))
|
print(f'initial sample: {len(sample)} elements')
|
||||||
|
|
||||||
# complete sample, in case duplicate random numbers were discarded
|
# complete sample, in case duplicate random numbers were discarded
|
||||||
while len(sample) < SAMPLE_LEN:
|
while len(sample) < SAMPLE_LEN:
|
||||||
sample.add(1 / random.random())
|
sample.add(1 / random.random())
|
||||||
|
|
||||||
print('complete sample: %d elements' % len(sample))
|
print(f'complete sample: {len(sample)} elements')
|
||||||
|
|
||||||
sample = array.array('d', sample)
|
sample = array.array('d', sample)
|
||||||
random.shuffle(sample)
|
random.shuffle(sample)
|
||||||
|
|
||||||
not_selected = sample[:NEEDLES_LEN // 2]
|
not_selected = sample[:NEEDLES_LEN // 2]
|
||||||
print('not selected: %d samples' % len(not_selected))
|
print(f'not selected: {len(not_selected)} samples')
|
||||||
print(' writing not_selected.arr')
|
print(' writing not_selected.arr')
|
||||||
with open('not_selected.arr', 'wb') as fp:
|
with open('not_selected.arr', 'wb') as fp:
|
||||||
not_selected.tofile(fp)
|
not_selected.tofile(fp)
|
||||||
|
|
||||||
selected = sample[NEEDLES_LEN // 2:]
|
selected = sample[NEEDLES_LEN // 2:]
|
||||||
print('selected: %d samples' % len(selected))
|
print(f'selected: {len(selected)} samples')
|
||||||
print(' writing selected.arr')
|
print(' writing selected.arr')
|
||||||
with open('selected.arr', 'wb') as fp:
|
with open('selected.arr', 'wb') as fp:
|
||||||
selected.tofile(fp)
|
selected.tofile(fp)
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
MAX_BITS = len(format(sys.maxsize, 'b'))
|
MAX_BITS = len(format(sys.maxsize, 'b'))
|
||||||
print('%s-bit Python build' % (MAX_BITS + 1))
|
print(f'{MAX_BITS + 1}-bit Python build')
|
||||||
|
|
||||||
def hash_diff(o1, o2):
|
def hash_diff(o1, o2):
|
||||||
h1 = '{:>0{}b}'.format(hash(o1), MAX_BITS)
|
h1 = f'{hash(o1):>0{MAX_BITS}b}'
|
||||||
h2 = '{:>0{}b}'.format(hash(o2), MAX_BITS)
|
h2 = f'{hash(o2):>0{MAX_BITS}b}'
|
||||||
diff = ''.join('!' if b1 != b2 else ' ' for b1, b2 in zip(h1, h2))
|
diff = ''.join('!' if b1 != b2 else ' ' for b1, b2 in zip(h1, h2))
|
||||||
count = '!= {}'.format(diff.count('!'))
|
count = f'!= {diff.count("!")}'
|
||||||
width = max(len(repr(o1)), len(repr(o2)), 8)
|
width = max(len(repr(o1)), len(repr(o2)), 8)
|
||||||
sep = '-' * (width * 2 + MAX_BITS)
|
sep = '-' * (width * 2 + MAX_BITS)
|
||||||
return '{!r:{width}} {}\n{:{width}} {} {}\n{!r:{width}} {}\n{}'.format(
|
return (f'{o1!r:{width}} {h1}\n{" ":{width}} {diff} {count}\n'
|
||||||
o1, h1, ' ' * width, diff, count, o2, h2, sep, width=width)
|
f'{o2!r:{width}} {h2}\n{sep}')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print(hash_diff(1, 1.0))
|
print(hash_diff(1, 1.0))
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ _sentinel = object()
|
|||||||
|
|
||||||
|
|
||||||
class TransformDict(MutableMapping):
|
class TransformDict(MutableMapping):
|
||||||
'''Dictionary that calls a transformation function when looking
|
"""Dictionary that calls a transformation function when looking
|
||||||
up keys, but preserves the original keys.
|
up keys, but preserves the original keys.
|
||||||
|
|
||||||
>>> d = TransformDict(str.lower)
|
>>> d = TransformDict(str.lower)
|
||||||
@@ -26,18 +26,18 @@ class TransformDict(MutableMapping):
|
|||||||
True
|
True
|
||||||
>>> set(d.keys())
|
>>> set(d.keys())
|
||||||
{'Foo'}
|
{'Foo'}
|
||||||
'''
|
"""
|
||||||
|
|
||||||
__slots__ = ('_transform', '_original', '_data')
|
__slots__ = ('_transform', '_original', '_data')
|
||||||
|
|
||||||
def __init__(self, transform, init_dict=None, **kwargs):
|
def __init__(self, transform, init_dict=None, **kwargs):
|
||||||
'''Create a new TransformDict with the given *transform* function.
|
"""Create a new TransformDict with the given *transform* function.
|
||||||
*init_dict* and *kwargs* are optional initializers, as in the
|
*init_dict* and *kwargs* are optional initializers, as in the
|
||||||
dict constructor.
|
dict constructor.
|
||||||
'''
|
"""
|
||||||
if not callable(transform):
|
if not callable(transform):
|
||||||
msg = 'expected a callable, got %r'
|
raise TypeError(
|
||||||
raise TypeError(msg % transform.__class__)
|
f'expected a callable, got {transform.__class__!r}')
|
||||||
self._transform = transform
|
self._transform = transform
|
||||||
# transformed => original
|
# transformed => original
|
||||||
self._original = {}
|
self._original = {}
|
||||||
@@ -48,7 +48,7 @@ class TransformDict(MutableMapping):
|
|||||||
self.update(kwargs)
|
self.update(kwargs)
|
||||||
|
|
||||||
def getitem(self, key):
|
def getitem(self, key):
|
||||||
'D.getitem(key) -> (stored key, value)'
|
"""D.getitem(key) -> (stored key, value)"""
|
||||||
transformed = self._transform(key)
|
transformed = self._transform(key)
|
||||||
original = self._original[transformed]
|
original = self._original[transformed]
|
||||||
value = self._data[transformed]
|
value = self._data[transformed]
|
||||||
@@ -56,7 +56,7 @@ class TransformDict(MutableMapping):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def transform_func(self):
|
def transform_func(self):
|
||||||
"This TransformDict's transformation function"
|
"""This TransformDict's transformation function"""
|
||||||
return self._transform
|
return self._transform
|
||||||
|
|
||||||
# Minimum set of methods required for MutableMapping
|
# Minimum set of methods required for MutableMapping
|
||||||
@@ -83,7 +83,7 @@ class TransformDict(MutableMapping):
|
|||||||
# Methods overridden to mitigate the performance overhead.
|
# Methods overridden to mitigate the performance overhead.
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
'D.clear() -> None. Remove all items from D.'
|
"""D.clear() -> None. Remove all items from D."""
|
||||||
self._data.clear()
|
self._data.clear()
|
||||||
self._original.clear()
|
self._original.clear()
|
||||||
|
|
||||||
@@ -91,14 +91,14 @@ class TransformDict(MutableMapping):
|
|||||||
return self._transform(key) in self._data
|
return self._transform(key) in self._data
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
'D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.'
|
"""D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None."""
|
||||||
return self._data.get(self._transform(key), default)
|
return self._data.get(self._transform(key), default)
|
||||||
|
|
||||||
def pop(self, key, default=_sentinel):
|
def pop(self, key, default=_sentinel):
|
||||||
'''D.pop(k[,d]) -> v, remove key and return corresponding value.
|
"""D.pop(k[,d]) -> v, remove key and return corresponding value.
|
||||||
If key is not found, d is returned if given, otherwise
|
If key is not found, d is returned if given, otherwise
|
||||||
KeyError is raised.
|
KeyError is raised.
|
||||||
'''
|
"""
|
||||||
transformed = self._transform(key)
|
transformed = self._transform(key)
|
||||||
if default is _sentinel:
|
if default is _sentinel:
|
||||||
del self._original[transformed]
|
del self._original[transformed]
|
||||||
@@ -108,16 +108,16 @@ class TransformDict(MutableMapping):
|
|||||||
return self._data.pop(transformed, default)
|
return self._data.pop(transformed, default)
|
||||||
|
|
||||||
def popitem(self):
|
def popitem(self):
|
||||||
'''D.popitem() -> (k, v), remove and return some (key, value) pair
|
"""D.popitem() -> (k, v), remove and return some (key, value) pair
|
||||||
as a 2-tuple; but raise KeyError if D is empty.
|
as a 2-tuple; but raise KeyError if D is empty.
|
||||||
'''
|
"""
|
||||||
transformed, value = self._data.popitem()
|
transformed, value = self._data.popitem()
|
||||||
return self._original.pop(transformed), value
|
return self._original.pop(transformed), value
|
||||||
|
|
||||||
# Other methods
|
# Other methods
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
'D.copy() -> a shallow copy of D'
|
"""D.copy() -> a shallow copy of D"""
|
||||||
other = self.__class__(self._transform)
|
other = self.__class__(self._transform)
|
||||||
other._original = self._original.copy()
|
other._original = self._original.copy()
|
||||||
other._data = self._data.copy()
|
other._data = self._data.copy()
|
||||||
@@ -137,5 +137,4 @@ class TransformDict(MutableMapping):
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
# Some keys are unhashable, fall back on .items()
|
# Some keys are unhashable, fall back on .items()
|
||||||
equiv = list(self.items())
|
equiv = list(self.items())
|
||||||
return '%s(%r, %s)' % (self.__class__.__name__,
|
return f'{self.__class__.__name__}({self._transform!r}, {equiv!r})'
|
||||||
self._transform, repr(equiv))
|
|
||||||
|
|||||||
@@ -18,4 +18,4 @@ my_file = open('dummy', 'w')
|
|||||||
|
|
||||||
for expression in expressions.split():
|
for expression in expressions.split():
|
||||||
value = eval(expression)
|
value = eval(expression)
|
||||||
print(expression.rjust(30), '->', repr(value))
|
print(f'{expression:>30} -> {value!r}')
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ re_digit = re.compile(r'\d')
|
|||||||
sample = '1\xbc\xb2\u0969\u136b\u216b\u2466\u2480\u3285'
|
sample = '1\xbc\xb2\u0969\u136b\u216b\u2466\u2480\u3285'
|
||||||
|
|
||||||
for char in sample:
|
for char in sample:
|
||||||
print('U+%04x' % ord(char), # <1>
|
print(f'U+{ord(char):04x}', # <1>
|
||||||
char.center(6), # <2>
|
char.center(6), # <2>
|
||||||
're_dig' if re_digit.match(char) else '-', # <3>
|
're_dig' if re_digit.match(char) else '-', # <3>
|
||||||
'isdig' if char.isdigit() else '-', # <4>
|
'isdig' if char.isdigit() else '-', # <4>
|
||||||
'isnum' if char.isnumeric() else '-', # <5>
|
'isnum' if char.isnumeric() else '-', # <5>
|
||||||
format(unicodedata.numeric(char), '5.2f'), # <6>
|
f'{unicodedata.numeric(char):5.2f}', # <6>
|
||||||
unicodedata.name(char), # <7>
|
unicodedata.name(char), # <7>
|
||||||
sep='\t')
|
sep='\t')
|
||||||
# end::NUMERICS_DEMO[]
|
# end::NUMERICS_DEMO[]
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ text_str = ("Ramanujan saw \u0be7\u0bed\u0be8\u0bef" # <3>
|
|||||||
|
|
||||||
text_bytes = text_str.encode('utf_8') # <5>
|
text_bytes = text_str.encode('utf_8') # <5>
|
||||||
|
|
||||||
print('Text', repr(text_str), sep='\n ')
|
print(f'Text\n {text_str!r}')
|
||||||
print('Numbers')
|
print('Numbers')
|
||||||
print(' str :', re_numbers_str.findall(text_str)) # <6>
|
print(' str :', re_numbers_str.findall(text_str)) # <6>
|
||||||
print(' bytes:', re_numbers_bytes.findall(text_bytes)) # <7>
|
print(' bytes:', re_numbers_bytes.findall(text_bytes)) # <7>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
Radical folding and text sanitizing.
|
Radical folding and text sanitizing.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
>>> import copy
|
>>> import copy
|
||||||
>>> bus1 = Bus(['Alice', 'Bill', 'Claire', 'David'])
|
>>> bus1 = Bus(['Alice', 'Bill', 'Claire', 'David'])
|
||||||
|
|||||||
@@ -24,5 +24,5 @@ class Cheese:
|
|||||||
self.kind = kind
|
self.kind = kind
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'Cheese(%r)' % self.kind
|
return f'Cheese({self.kind!r})'
|
||||||
# end::CHEESE_CLASS[]
|
# end::CHEESE_CLASS[]
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# tag::TAG_DEMO[]
|
# tag::TAG_DEMO[]
|
||||||
>>> tag('br') # <1>
|
>>> tag('br') # <1>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
from array import array
|
from array import array
|
||||||
from typing import Mapping, MutableSequence, Callable, Iterable, Sequence, Union, Any
|
from typing import Mapping, MutableSequence, Callable, Iterable, Union, Any
|
||||||
|
|
||||||
|
|
||||||
OPERATORS: Mapping[str, Callable[[float, float], float]] = {
|
OPERATORS: Mapping[str, Callable[[float, float], float]] = {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
>>> import copy
|
>>> import copy
|
||||||
>>> bus1 = Bus(['Alice', 'Bill', 'Claire', 'David'])
|
>>> bus1 = Bus(['Alice', 'Bill', 'Claire', 'David'])
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import re
|
|||||||
import unicodedata
|
import unicodedata
|
||||||
from typing import Dict, Set, Iterator
|
from typing import Dict, Set, Iterator
|
||||||
|
|
||||||
RE_WORD = re.compile('\w+')
|
RE_WORD = re.compile(r'\w+')
|
||||||
STOP_CODE = sys.maxunicode + 1
|
STOP_CODE = sys.maxunicode + 1
|
||||||
|
|
||||||
def tokenize(text: str) -> Iterator[str]: # <1>
|
def tokenize(text: str) -> Iterator[str]: # <1>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ def test_columnize_8_in_3():
|
|||||||
|
|
||||||
def test_columnize_8_in_5():
|
def test_columnize_8_in_5():
|
||||||
# Not the right number of columns, but the right number of rows.
|
# Not the right number of columns, but the right number of rows.
|
||||||
# This acually looks better, so it's OK!
|
# This actually looks better, so it's OK!
|
||||||
sequence = 'ABCDEFGH'
|
sequence = 'ABCDEFGH'
|
||||||
expected = [
|
expected = [
|
||||||
('A', 'C', 'E', 'G'),
|
('A', 'C', 'E', 'G'),
|
||||||
@@ -60,7 +60,7 @@ def test_columnize_8_in_5():
|
|||||||
|
|
||||||
def test_columnize_7_in_5():
|
def test_columnize_7_in_5():
|
||||||
# Not the right number of columns, but the right number of rows.
|
# Not the right number of columns, but the right number of rows.
|
||||||
# This acually looks better, so it's OK!
|
# This actually looks better, so it's OK!
|
||||||
sequence = 'ABCDEFG'
|
sequence = 'ABCDEFG'
|
||||||
expected = [
|
expected = [
|
||||||
('A', 'C', 'E', 'G'),
|
('A', 'C', 'E', 'G'),
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ from geolib import geohash as gh # type: ignore
|
|||||||
|
|
||||||
PRECISION = 9
|
PRECISION = 9
|
||||||
|
|
||||||
def geohash(lat_lon = Tuple[float, float]) -> str:
|
def geohash(lat_lon: Tuple[float, float]) -> str:
|
||||||
return gh.encode(*lat_lon, PRECISION)
|
return gh.encode(*lat_lon, PRECISION)
|
||||||
# end::GEOHASH[]
|
# end::GEOHASH[]
|
||||||
@@ -13,7 +13,7 @@ def mode(data: Iterable[NumberT]) -> NumberT:
|
|||||||
|
|
||||||
|
|
||||||
def demo() -> None:
|
def demo() -> None:
|
||||||
from typing import List, Set, TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
pop = [Fraction(1, 2), Fraction(1, 3), Fraction(1, 4), Fraction(1, 2)]
|
pop = [Fraction(1, 2), Fraction(1, 3), Fraction(1, 4), Fraction(1, 2)]
|
||||||
m = mode(pop)
|
m = mode(pop)
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ def load_hash() -> Tuple[bytes, bytes]:
|
|||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
salt, stored_hash = salted_hash.split(b':')
|
salt, stored_hash = salted_hash.split(b':')
|
||||||
return (b64decode(salt), b64decode(stored_hash))
|
return b64decode(salt), b64decode(stored_hash)
|
||||||
|
|
||||||
|
|
||||||
def practice() -> None:
|
def practice() -> None:
|
||||||
@@ -83,8 +83,7 @@ def practice() -> None:
|
|||||||
print(f' {answer}\thits={correct}\tmisses={turn-correct}')
|
print(f' {answer}\thits={correct}\tmisses={turn-correct}')
|
||||||
|
|
||||||
if turn:
|
if turn:
|
||||||
pct = correct / turn * 100
|
print(f'\n{turn} turns. {correct / turn:.1%} correct.')
|
||||||
print(f'\n{turn} turns. {pct:0.1f}% correct.')
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv: Sequence[str]) -> None:
|
def main(argv: Sequence[str]) -> None:
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
import json
|
|
||||||
from typing import cast
|
|
||||||
|
|
||||||
from books import BookDict, to_xml
|
from books import BookDict, to_xml
|
||||||
|
|
||||||
XML_SAMPLE = """
|
XML_SAMPLE = """
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Averager():
|
class Averager:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.series = []
|
self.series = []
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5), # <2>
|
>>> cart = [LineItem('banana', 4, .5), # <2>
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, FidelityPromo()) # <3>
|
>>> Order(joe, cart, FidelityPromo()) # <3>
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, FidelityPromo()) # <4>
|
>>> Order(ann, cart, FidelityPromo()) # <4>
|
||||||
@@ -72,8 +72,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
|
|
||||||
class Promotion(ABC): # the Strategy: an abstract base class
|
class Promotion(ABC): # the Strategy: an abstract base class
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ def cart_plain() -> List[LineItem]:
|
|||||||
return [
|
return [
|
||||||
LineItem('banana', 4, 0.5),
|
LineItem('banana', 4, 0.5),
|
||||||
LineItem('apple', 10, 1.5),
|
LineItem('apple', 10, 1.5),
|
||||||
LineItem('watermellon', 5, 5.0),
|
LineItem('watermelon', 5, 5.0),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5), # <2>
|
>>> cart = [LineItem('banana', 4, .5), # <2>
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, FidelityPromo()) # <3>
|
>>> Order(joe, cart, FidelityPromo()) # <3>
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, FidelityPromo()) # <4>
|
>>> Order(ann, cart, FidelityPromo()) # <4>
|
||||||
@@ -29,7 +29,6 @@
|
|||||||
# tag::CLASSIC_STRATEGY[]
|
# tag::CLASSIC_STRATEGY[]
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from collections import namedtuple
|
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
|
||||||
@@ -69,8 +68,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
|
|
||||||
class Promotion(ABC): # the Strategy: an abstract base class
|
class Promotion(ABC): # the Strategy: an abstract base class
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ def customer_fidelity_1100() -> Customer:
|
|||||||
def cart_plain() -> List[LineItem]:
|
def cart_plain() -> List[LineItem]:
|
||||||
return [LineItem('banana', 4, .5),
|
return [LineItem('banana', 4, .5),
|
||||||
LineItem('apple', 10, 1.5),
|
LineItem('apple', 10, 1.5),
|
||||||
LineItem('watermellon', 5, 5.0)]
|
LineItem('watermelon', 5, 5.0)]
|
||||||
|
|
||||||
|
|
||||||
def test_fidelity_promo_no_discount(customer_fidelity_0, cart_plain) -> None:
|
def test_fidelity_promo_no_discount(customer_fidelity_0, cart_plain) -> None:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5), # <2>
|
>>> cart = [LineItem('banana', 4, .5), # <2>
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, FidelityPromo()) # <3>
|
>>> Order(joe, cart, FidelityPromo()) # <3>
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, FidelityPromo()) # <4>
|
>>> Order(ann, cart, FidelityPromo()) # <4>
|
||||||
@@ -29,7 +29,6 @@
|
|||||||
# tag::CLASSIC_STRATEGY[]
|
# tag::CLASSIC_STRATEGY[]
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from collections import namedtuple
|
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from pytypes import typelogged
|
from pytypes import typelogged
|
||||||
@@ -71,8 +70,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
|
|
||||||
@typelogged
|
@typelogged
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ def customer_fidelity_1100() -> Customer:
|
|||||||
def cart_plain() -> List[LineItem]:
|
def cart_plain() -> List[LineItem]:
|
||||||
return [LineItem('banana', 4, .5),
|
return [LineItem('banana', 4, .5),
|
||||||
LineItem('apple', 10, 1.5),
|
LineItem('apple', 10, 1.5),
|
||||||
LineItem('watermellon', 5, 5.0)]
|
LineItem('watermelon', 5, 5.0)]
|
||||||
|
|
||||||
|
|
||||||
def test_fidelity_promo_no_discount(customer_fidelity_0, cart_plain) -> None:
|
def test_fidelity_promo_no_discount(customer_fidelity_0, cart_plain) -> None:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5),
|
>>> cart = [LineItem('banana', 4, .5),
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, fidelity_promo) # <2>
|
>>> Order(joe, cart, fidelity_promo) # <2>
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, fidelity_promo)
|
>>> Order(ann, cart, fidelity_promo)
|
||||||
@@ -71,8 +71,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
|
|
||||||
# <2>
|
# <2>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5),
|
>>> cart = [LineItem('banana', 4, .5),
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> banana_cart = [LineItem('banana', 30, .5),
|
>>> banana_cart = [LineItem('banana', 30, .5),
|
||||||
... LineItem('apple', 10, 1.5)]
|
... LineItem('apple', 10, 1.5)]
|
||||||
>>> big_cart = [LineItem(str(item_code), 1, 1.0)
|
>>> big_cart = [LineItem(str(item_code), 1, 1.0)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5),
|
>>> cart = [LineItem('banana', 4, .5),
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, fidelity_promo)
|
>>> Order(joe, cart, fidelity_promo)
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, fidelity_promo)
|
>>> Order(ann, cart, fidelity_promo)
|
||||||
@@ -69,8 +69,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
|
|
||||||
def fidelity_promo(order):
|
def fidelity_promo(order):
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5),
|
>>> cart = [LineItem('banana', 4, .5),
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, fidelity_promo)
|
>>> Order(joe, cart, fidelity_promo)
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, fidelity_promo)
|
>>> Order(ann, cart, fidelity_promo)
|
||||||
@@ -73,8 +73,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
|
|
||||||
# tag::STRATEGY_BEST3[]
|
# tag::STRATEGY_BEST3[]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5),
|
>>> cart = [LineItem('banana', 4, .5),
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, fidelity)
|
>>> Order(joe, cart, fidelity)
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, fidelity)
|
>>> Order(ann, cart, fidelity)
|
||||||
@@ -71,8 +71,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
|
|
||||||
# tag::STRATEGY_BEST4[]
|
# tag::STRATEGY_BEST4[]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5),
|
>>> cart = [LineItem('banana', 4, .5),
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, fidelity_promo(10))
|
>>> Order(joe, cart, fidelity_promo(10))
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, fidelity_promo(10))
|
>>> Order(ann, cart, fidelity_promo(10))
|
||||||
@@ -73,8 +73,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
|
|
||||||
# tag::STRATEGY_PARAM[]
|
# tag::STRATEGY_PARAM[]
|
||||||
@@ -85,7 +84,7 @@ Promotion = Callable[[Order], float] # <2>
|
|||||||
def fidelity_promo(percent: float) -> Promotion:
|
def fidelity_promo(percent: float) -> Promotion:
|
||||||
"""discount for customers with 1000 or more fidelity points"""
|
"""discount for customers with 1000 or more fidelity points"""
|
||||||
return lambda order: (
|
return lambda order: (
|
||||||
order.total() * percent / 100.0 if order.customer.fidelity >= 1000 else 0
|
order.total() * percent / 100 if order.customer.fidelity >= 1000 else 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -96,7 +95,7 @@ def bulk_item_promo(percent: float) -> Promotion:
|
|||||||
discount = 0
|
discount = 0
|
||||||
for item in order.cart:
|
for item in order.cart:
|
||||||
if item.quantity >= 20:
|
if item.quantity >= 20:
|
||||||
discount += item.total() * percent / 100.0
|
discount += item.total() * percent / 100
|
||||||
return discount
|
return discount
|
||||||
|
|
||||||
return discounter
|
return discounter
|
||||||
@@ -111,13 +110,13 @@ class LargeOrderPromo:
|
|||||||
def __call__(self, order: Order) -> float:
|
def __call__(self, order: Order) -> float:
|
||||||
distinct_items = {item.product for item in order.cart}
|
distinct_items = {item.product for item in order.cart}
|
||||||
if len(distinct_items) >= 10:
|
if len(distinct_items) >= 10:
|
||||||
return order.total() * self.percent / 100.0
|
return order.total() * self.percent / 100
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def general_discount(percent: float, order: Order) -> float:
|
def general_discount(percent: float, order: Order) -> float:
|
||||||
"""unrestricted discount; usage: ``partial(general_discount, 5)``"""
|
"""unrestricted discount; usage: ``partial(general_discount, 5)``"""
|
||||||
return order.total() * percent / 100.0
|
return order.total() * percent / 100
|
||||||
|
|
||||||
|
|
||||||
# end::STRATEGY[]
|
# end::STRATEGY[]
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ def cart_plain() -> List[LineItem]:
|
|||||||
return [
|
return [
|
||||||
LineItem('banana', 4, 0.5),
|
LineItem('banana', 4, 0.5),
|
||||||
LineItem('apple', 10, 1.5),
|
LineItem('apple', 10, 1.5),
|
||||||
LineItem('watermellon', 5, 5.0),
|
LineItem('watermelon', 5, 5.0),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ def cart_plain() -> List[LineItem]:
|
|||||||
return [
|
return [
|
||||||
LineItem('banana', 4, 0.5),
|
LineItem('banana', 4, 0.5),
|
||||||
LineItem('apple', 10, 1.5),
|
LineItem('apple', 10, 1.5),
|
||||||
LineItem('watermellon', 5, 5.0),
|
LineItem('watermelon', 5, 5.0),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5), # <2>
|
>>> cart = [LineItem('banana', 4, .5), # <2>
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, FidelityPromo()) # <3>
|
>>> Order(joe, cart, FidelityPromo()) # <3>
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, FidelityPromo()) # <4>
|
>>> Order(ann, cart, FidelityPromo()) # <4>
|
||||||
@@ -65,8 +65,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
|
|
||||||
class Promotion(ABC): # the Strategy: an abstract base class
|
class Promotion(ABC): # the Strategy: an abstract base class
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
def fidelity_promo(order):
|
def fidelity_promo(order):
|
||||||
"""5% discount for customers with 1000 or more fidelity points"""
|
"""5% discount for customers with 1000 or more fidelity points"""
|
||||||
return order.total() * .05 if order.customer.fidelity >= 1000 else 0
|
return order.total() * .05 if order.customer.fidelity >= 1000 else 0
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5),
|
>>> cart = [LineItem('banana', 4, .5),
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, fidelity_promo) # <2>
|
>>> Order(joe, cart, fidelity_promo) # <2>
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, fidelity_promo)
|
>>> Order(ann, cart, fidelity_promo)
|
||||||
@@ -64,8 +64,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
# <2>
|
# <2>
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5),
|
>>> cart = [LineItem('banana', 4, .5),
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, fidelity_promo)
|
>>> Order(joe, cart, fidelity_promo)
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, fidelity_promo)
|
>>> Order(ann, cart, fidelity_promo)
|
||||||
@@ -71,8 +71,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
|
|
||||||
def fidelity_promo(order):
|
def fidelity_promo(order):
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5),
|
>>> cart = [LineItem('banana', 4, .5),
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, fidelity_promo)
|
>>> Order(joe, cart, fidelity_promo)
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, fidelity_promo)
|
>>> Order(ann, cart, fidelity_promo)
|
||||||
@@ -71,8 +71,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
|
|
||||||
def fidelity_promo(order):
|
def fidelity_promo(order):
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5),
|
>>> cart = [LineItem('banana', 4, .5),
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, fidelity_promo)
|
>>> Order(joe, cart, fidelity_promo)
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, fidelity_promo)
|
>>> Order(ann, cart, fidelity_promo)
|
||||||
@@ -75,8 +75,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
# tag::STRATEGY_BEST3[]
|
# tag::STRATEGY_BEST3[]
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5),
|
>>> cart = [LineItem('banana', 4, .5),
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, fidelity)
|
>>> Order(joe, cart, fidelity)
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, fidelity)
|
>>> Order(ann, cart, fidelity)
|
||||||
@@ -72,8 +72,7 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
# tag::STRATEGY_BEST4[]
|
# tag::STRATEGY_BEST4[]
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5),
|
>>> cart = [LineItem('banana', 4, .5),
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, fidelity_promo(10))
|
>>> Order(joe, cart, fidelity_promo(10))
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, fidelity_promo(10))
|
>>> Order(ann, cart, fidelity_promo(10))
|
||||||
@@ -60,13 +60,12 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
|
|
||||||
def fidelity_promo(percent):
|
def fidelity_promo(percent):
|
||||||
"""discount for customers with 1000 or more fidelity points"""
|
"""discount for customers with 1000 or more fidelity points"""
|
||||||
return lambda order: (order.total() * percent/100.0
|
return lambda order: (order.total() * percent / 100
|
||||||
if order.customer.fidelity >= 1000 else 0)
|
if order.customer.fidelity >= 1000 else 0)
|
||||||
|
|
||||||
|
|
||||||
@@ -76,7 +75,7 @@ def bulk_item_promo(percent):
|
|||||||
discount = 0
|
discount = 0
|
||||||
for item in order.cart:
|
for item in order.cart:
|
||||||
if item.quantity >= 20:
|
if item.quantity >= 20:
|
||||||
discount += item.total() * percent/100.0
|
discount += item.total() * percent / 100
|
||||||
return discount
|
return discount
|
||||||
return discounter
|
return discounter
|
||||||
|
|
||||||
@@ -86,6 +85,6 @@ def large_order_promo(percent):
|
|||||||
def discounter(order):
|
def discounter(order):
|
||||||
distinct_items = {item.product for item in order.cart}
|
distinct_items = {item.product for item in order.cart}
|
||||||
if len(distinct_items) >= 10:
|
if len(distinct_items) >= 10:
|
||||||
return order.total() * percent / 100.0
|
return order.total() * percent / 100
|
||||||
return 0
|
return 0
|
||||||
return discounter
|
return discounter
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
>>> ann = Customer('Ann Smith', 1100)
|
>>> ann = Customer('Ann Smith', 1100)
|
||||||
>>> cart = [LineItem('banana', 4, .5),
|
>>> cart = [LineItem('banana', 4, .5),
|
||||||
... LineItem('apple', 10, 1.5),
|
... LineItem('apple', 10, 1.5),
|
||||||
... LineItem('watermellon', 5, 5.0)]
|
... LineItem('watermelon', 5, 5.0)]
|
||||||
>>> Order(joe, cart, FidelityPromo(10))
|
>>> Order(joe, cart, FidelityPromo(10))
|
||||||
<Order total: 42.00 due: 42.00>
|
<Order total: 42.00 due: 42.00>
|
||||||
>>> Order(ann, cart, FidelityPromo(10))
|
>>> Order(ann, cart, FidelityPromo(10))
|
||||||
@@ -60,11 +60,10 @@ class Order: # the Context
|
|||||||
return self.total() - discount
|
return self.total() - discount
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
|
||||||
return fmt.format(self.total(), self.due())
|
|
||||||
|
|
||||||
|
|
||||||
class Promotion():
|
class Promotion:
|
||||||
"""compute discount for order"""
|
"""compute discount for order"""
|
||||||
|
|
||||||
def __init__(self, percent):
|
def __init__(self, percent):
|
||||||
@@ -79,7 +78,7 @@ class FidelityPromo(Promotion):
|
|||||||
|
|
||||||
def __call__(self, order):
|
def __call__(self, order):
|
||||||
if order.customer.fidelity >= 1000:
|
if order.customer.fidelity >= 1000:
|
||||||
return order.total() * self.percent/100.0
|
return order.total() * self.percent / 100
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
@@ -90,7 +89,7 @@ class BulkItemPromo(Promotion):
|
|||||||
discount = 0
|
discount = 0
|
||||||
for item in order.cart:
|
for item in order.cart:
|
||||||
if item.quantity >= 20:
|
if item.quantity >= 20:
|
||||||
discount += item.total() * self.percent/100.0
|
discount += item.total() * self.percent / 100
|
||||||
return discount
|
return discount
|
||||||
|
|
||||||
|
|
||||||
@@ -100,5 +99,5 @@ class LargeOrderPromo(Promotion):
|
|||||||
def __call__(self, order):
|
def __call__(self, order):
|
||||||
distinct_items = {item.product for item in order.cart}
|
distinct_items = {item.product for item in order.cart}
|
||||||
if len(distinct_items) >= 10:
|
if len(distinct_items) >= 10:
|
||||||
return order.total() * self.percent / 100.0
|
return order.total() * self.percent / 100
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -8,17 +8,17 @@ if len(sys.argv) == 2:
|
|||||||
module_name = sys.argv[1].replace('.py', '')
|
module_name = sys.argv[1].replace('.py', '')
|
||||||
module = importlib.import_module(module_name)
|
module = importlib.import_module(module_name)
|
||||||
else:
|
else:
|
||||||
print('Usage: {} <vector-module-to-test>'.format())
|
print(f'Usage: {sys.argv[0]} <vector-module-to-test>')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
fmt = 'Selected Vector2d type: {.__name__}.{.__name__}'
|
fmt = 'Selected Vector2d type: {.__name__}.{.__name__}'
|
||||||
print(fmt.format(module, module.Vector2d))
|
print(fmt.format(module, module.Vector2d))
|
||||||
|
|
||||||
mem_init = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
|
mem_init = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
|
||||||
print('Creating {:,} Vector2d instances'.format(NUM_VECTORS))
|
print(f'Creating {NUM_VECTORS:,} Vector2d instances')
|
||||||
|
|
||||||
vectors = [module.Vector2d(3.0, 4.0) for i in range(NUM_VECTORS)]
|
vectors = [module.Vector2d(3.0, 4.0) for i in range(NUM_VECTORS)]
|
||||||
|
|
||||||
mem_final = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
|
mem_final = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
|
||||||
print('Initial RAM usage: {:14,}'.format(mem_init))
|
print(f'Initial RAM usage: {mem_init:14,}')
|
||||||
print(' Final RAM usage: {:14,}'.format(mem_final))
|
print(f' Final RAM usage: {mem_final:14,}')
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class Expose {
|
|||||||
System.out.println("message.secret = " + wasHidden);
|
System.out.println("message.secret = " + wasHidden);
|
||||||
}
|
}
|
||||||
catch (IllegalAccessException e) {
|
catch (IllegalAccessException e) {
|
||||||
// this will not happen after setAcessible(true)
|
// this will not happen after setAccessible(true)
|
||||||
System.err.println(e);
|
System.err.println(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ import Confidential
|
|||||||
message = Confidential('top secret text')
|
message = Confidential('top secret text')
|
||||||
secret_field = Confidential.getDeclaredField('secret')
|
secret_field = Confidential.getDeclaredField('secret')
|
||||||
secret_field.setAccessible(True) # break the lock!
|
secret_field.setAccessible(True) # break the lock!
|
||||||
print 'message.secret =', secret_field.get(message)
|
print('message.secret =', secret_field.get(message))
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ for field in fields:
|
|||||||
# list private fields only
|
# list private fields only
|
||||||
if Modifier.isPrivate(field.getModifiers()):
|
if Modifier.isPrivate(field.getModifiers()):
|
||||||
field.setAccessible(True) # break the lock
|
field.setAccessible(True) # break the lock
|
||||||
print 'field:', field
|
print('field:', field)
|
||||||
print '\t', field.getName(), '=', field.get(message)
|
print('\t', field.getName(), '=', field.get(message))
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
In the Jython registry file there is this line:
|
In the Jython registry file there is this line:
|
||||||
|
|
||||||
@@ -14,4 +13,4 @@ message = Confidential('top secret text')
|
|||||||
for name in dir(message):
|
for name in dir(message):
|
||||||
attr = getattr(message, name)
|
attr = getattr(message, name)
|
||||||
if not callable(attr): # non-methods only
|
if not callable(attr): # non-methods only
|
||||||
print name + '\t=', attr
|
print(name + '\t=', attr)
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ Tests of hashing:
|
|||||||
>>> v2 = Vector2d(3.1, 4.2)
|
>>> v2 = Vector2d(3.1, 4.2)
|
||||||
>>> hash(v1), hash(v2)
|
>>> hash(v1), hash(v2)
|
||||||
(7, 384307168202284039)
|
(7, 384307168202284039)
|
||||||
>>> len(set([v1, v2]))
|
>>> len({v1, v2})
|
||||||
2
|
2
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ Tests of hashing:
|
|||||||
>>> v2 = Vector2d(3.1, 4.2)
|
>>> v2 = Vector2d(3.1, 4.2)
|
||||||
>>> hash(v1), hash(v2)
|
>>> hash(v1), hash(v2)
|
||||||
(7, 384307168202284039)
|
(7, 384307168202284039)
|
||||||
>>> len(set([v1, v2]))
|
>>> len({v1, v2})
|
||||||
2
|
2
|
||||||
|
|
||||||
# end::VECTOR2D_V3_DEMO[]
|
# end::VECTOR2D_V3_DEMO[]
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ Tests of hashing:
|
|||||||
>>> v2 = Vector2d(3.1, 4.2)
|
>>> v2 = Vector2d(3.1, 4.2)
|
||||||
>>> hash(v1), hash(v2)
|
>>> hash(v1), hash(v2)
|
||||||
(7, 384307168202284039)
|
(7, 384307168202284039)
|
||||||
>>> len(set([v1, v2]))
|
>>> len({v1, v2})
|
||||||
2
|
2
|
||||||
|
|
||||||
# end::VECTOR2D_V3_DEMO[]
|
# end::VECTOR2D_V3_DEMO[]
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import math
|
import math
|
||||||
import itertools
|
|
||||||
|
|
||||||
|
|
||||||
PRIME_FIXTURE = [
|
PRIME_FIXTURE = [
|
||||||
@@ -36,7 +35,7 @@ def is_prime(n) -> bool:
|
|||||||
if n % 2 == 0:
|
if n % 2 == 0:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
root = int(math.floor(math.sqrt(n)))
|
root = math.floor(math.sqrt(n))
|
||||||
for i in range(3, root + 1, 2):
|
for i in range(3, root + 1, 2):
|
||||||
if n % i == 0:
|
if n % i == 0:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ def main() -> None:
|
|||||||
label = 'P' if prime else ' '
|
label = 'P' if prime else ' '
|
||||||
print(f'{n:16} {label} {elapsed:9.6f}s')
|
print(f'{n:16} {label} {elapsed:9.6f}s')
|
||||||
|
|
||||||
|
|
||||||
time = perf_counter() - t0
|
time = perf_counter() - t0
|
||||||
print('Total time:', f'{time:0.2f}s')
|
print('Total time:', f'{time:0.2f}s')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
# end::PRIMES_PROC_MAIN[]
|
# end::PRIMES_PROC_MAIN[]
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ async def is_prime(n):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
sleep = asyncio.sleep # <1>
|
sleep = asyncio.sleep # <1>
|
||||||
root = int(math.floor(math.sqrt(n)))
|
root = math.floor(math.sqrt(n))
|
||||||
for i in range(3, root + 1, 2):
|
for i in range(3, root + 1, 2):
|
||||||
if n % i == 0:
|
if n % i == 0:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ async def is_prime(n):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
sleep = asyncio.sleep # <1>
|
sleep = asyncio.sleep # <1>
|
||||||
root = int(math.floor(math.sqrt(n)))
|
root = math.floor(math.sqrt(n))
|
||||||
for i in range(3, root + 1, 2):
|
for i in range(3, root + 1, 2):
|
||||||
if n % i == 0:
|
if n % i == 0:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
from multiprocessing import Process, Event
|
from multiprocessing import Process, Event
|
||||||
from multiprocessing import synchronize
|
from multiprocessing import synchronize
|
||||||
import itertools
|
import itertools
|
||||||
import time
|
|
||||||
|
|
||||||
from primes import is_prime
|
from primes import is_prime
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
from threading import Thread, Event
|
from threading import Thread, Event
|
||||||
import itertools
|
import itertools
|
||||||
import time
|
|
||||||
|
|
||||||
from primes import is_prime
|
from primes import is_prime
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
# tag::SPINNER_THREAD_TOP[]
|
# tag::SPINNER_THREAD_TOP[]
|
||||||
from threading import Thread, Event
|
from threading import Thread, Event
|
||||||
import itertools
|
import itertools
|
||||||
import time
|
|
||||||
|
|
||||||
from primes import is_prime
|
from primes import is_prime
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from time import perf_counter
|
from time import perf_counter
|
||||||
from typing import Tuple, List, NamedTuple
|
from typing import List, NamedTuple
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from queue import SimpleQueue
|
from queue import SimpleQueue
|
||||||
|
|
||||||
|
|||||||
@@ -49,4 +49,4 @@ Part / Chapter #|Title|Directory|Notebook|1<sup>st</sup> ed. Chapter #
|
|||||||
**VI – Metaprogramming**|
|
**VI – Metaprogramming**|
|
||||||
22|Dynamic Attributes and Properties|[22-dyn-attr-prop](22-dyn-attr-prop)||19
|
22|Dynamic Attributes and Properties|[22-dyn-attr-prop](22-dyn-attr-prop)||19
|
||||||
23|Attribute Descriptors|[23-descriptor](23-descriptor)||20
|
23|Attribute Descriptors|[23-descriptor](23-descriptor)||20
|
||||||
24|Class Metapgrogramming|[24-class-metaprog](24-class-metaprog)||21
|
24|Class Metaprogramming|[24-class-metaprog](24-class-metaprog)||21
|
||||||
|
|||||||
Reference in New Issue
Block a user