Merge pull request #3 from eumiro/py36plus

Modernize code to Python 3.6+ and some cleanup
This commit is contained in:
Luciano Ramalho 2021-02-12 23:10:59 -03:00 committed by GitHub
commit 33f73a18a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
86 changed files with 153 additions and 189 deletions

View File

@ -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)

View File

@ -11,11 +11,11 @@ Demonstration of ``bisect.bisect``::
23 @ 11 | | | | | | | | | | |23 23 @ 11 | | | | | | | | | | |23
22 @ 9 | | | | | | | | |22 22 @ 9 | | | | | | | | |22
10 @ 5 | | | | |10 10 @ 5 | | | | |10
8 @ 5 | | | | |8 8 @ 5 | | | | |8
5 @ 3 | | |5 5 @ 3 | | |5
2 @ 1 |2 2 @ 1 |2
1 @ 1 |1 1 @ 1 |1
0 @ 0 0 0 @ 0 0
Demonstration of ``bisect.bisect_left``:: Demonstration of ``bisect.bisect_left``::
@ -27,11 +27,11 @@ Demonstration of ``bisect.bisect_left``::
23 @ 9 | | | | | | | | |23 23 @ 9 | | | | | | | | |23
22 @ 9 | | | | | | | | |22 22 @ 9 | | | | | | | | |22
10 @ 5 | | | | |10 10 @ 5 | | | | |10
8 @ 4 | | | |8 8 @ 4 | | | |8
5 @ 2 | |5 5 @ 2 | |5
2 @ 1 |2 2 @ 1 |2
1 @ 0 1 1 @ 0 1
0 @ 0 0 0 @ 0 0
""" """
@ -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

View File

@ -7,6 +7,6 @@ random.seed(1729)
my_list = [] 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)

View File

@ -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))]')

View File

@ -4,7 +4,7 @@ metro_lat_long.py
Demonstration of nested tuple unpacking:: Demonstration of nested tuple unpacking::
>>> main() >>> main()
| lat. | long. | lat. | long.
Mexico City | 19.4333 | -99.1333 Mexico City | 19.4333 | -99.1333
New York-Newark | 40.8086 | -74.0204 New York-Newark | 40.8086 | -74.0204
Sao Paulo | -23.5478 | -46.6358 Sao Paulo | -23.5478 | -46.6358
@ -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()

View File

@ -16,7 +16,7 @@ with open(sys.argv[1], encoding='utf-8') as fp:
for line_no, line in enumerate(fp, 1): for line_no, line in enumerate(fp, 1):
for match in WORD_RE.finditer(line): for match in WORD_RE.finditer(line):
word = match.group() word = match.group()
column_no = match.start()+1 column_no = match.start() + 1
location = (line_no, column_no) location = (line_no, column_no)
index[word].append(location) # <2> index[word].append(location) # <2>

View File

@ -41,15 +41,15 @@ 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:
sys.argv.remove('-v') sys.argv.remove('-v')
verbose = True verbose = True
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)

View File

@ -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
@ -12,26 +12,26 @@ 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)

View File

@ -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))

View File

@ -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))

View File

@ -8,7 +8,7 @@ FIRST, LAST = ord(' '), sys.maxunicode # <1>
def find(*query_words, first=FIRST, last=LAST): # <2> def find(*query_words, first=FIRST, last=LAST): # <2>
query = {w.upper() for w in query_words} # <3> query = {w.upper() for w in query_words} # <3>
count = 0 count = 0
for code in range(first, last + 1): for code in range(first, last + 1):
char = chr(code) # <4> char = chr(code) # <4>
name = unicodedata.name(char, None) # <5> name = unicodedata.name(char, None) # <5>
if name and query.issubset(name.split()): # <6> if name and query.issubset(name.split()): # <6>

View File

@ -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}')

View File

@ -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[]

View File

@ -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>

View File

@ -1,4 +1,3 @@
""" """
Radical folding and text sanitizing. Radical folding and text sanitizing.

View File

@ -16,7 +16,7 @@ class Coordinate:
lat: float lat: float
long: float long: float
def __str__(self): def __str__(self):
ns = 'N' if self.lat >= 0 else 'S' ns = 'N' if self.lat >= 0 else 'S'
we = 'E' if self.long >= 0 else 'W' we = 'E' if self.long >= 0 else 'W'

View File

@ -30,7 +30,7 @@ To fix, ``leo2`` must be created with an explicit ``handle``::
# tag::HACKERCLUB[] # tag::HACKERCLUB[]
from dataclasses import dataclass from dataclasses import dataclass
from club import ClubMember from club import ClubMember
@dataclass @dataclass
class HackerClubMember(ClubMember): # <1> class HackerClubMember(ClubMember): # <1>

View File

@ -31,7 +31,7 @@ To fix, ``leo2`` must be created with an explicit ``handle``::
# tag::HACKERCLUB[] # tag::HACKERCLUB[]
from dataclasses import dataclass from dataclasses import dataclass
from typing import ClassVar, Set from typing import ClassVar, Set
from club import ClubMember from club import ClubMember
@dataclass @dataclass
class HackerClubMember(ClubMember): class HackerClubMember(ClubMember):

View File

@ -14,7 +14,7 @@ A complete resource record:
>>> description = 'Improving the design of existing code' >>> description = 'Improving the design of existing code'
>>> book = Resource('978-0-13-475759-9', 'Refactoring, 2nd Edition', >>> book = Resource('978-0-13-475759-9', 'Refactoring, 2nd Edition',
... ['Martin Fowler', 'Kent Beck'], date(2018, 11, 19), ... ['Martin Fowler', 'Kent Beck'], date(2018, 11, 19),
... ResourceType.BOOK, description, 'EN', ... ResourceType.BOOK, description, 'EN',
... ['computer programming', 'OOP']) ... ['computer programming', 'OOP'])
>>> book # doctest: +NORMALIZE_WHITESPACE >>> book # doctest: +NORMALIZE_WHITESPACE
Resource(identifier='978-0-13-475759-9', title='Refactoring, 2nd Edition', Resource(identifier='978-0-13-475759-9', title='Refactoring, 2nd Edition',

View File

@ -21,7 +21,7 @@ A complete resource record:
>>> description = 'Improving the design of existing code' >>> description = 'Improving the design of existing code'
>>> book = Resource('978-0-13-475759-9', 'Refactoring, 2nd Edition', >>> book = Resource('978-0-13-475759-9', 'Refactoring, 2nd Edition',
... ['Martin Fowler', 'Kent Beck'], date(2018, 11, 19), ... ['Martin Fowler', 'Kent Beck'], date(2018, 11, 19),
... ResourceType.BOOK, description, 'EN', ... ResourceType.BOOK, description, 'EN',
... ['computer programming', 'OOP']) ... ['computer programming', 'OOP'])
# tag::DOCTEST[] # tag::DOCTEST[]

View File

@ -14,7 +14,7 @@ class Coordinate(NamedTuple):
lat: float lat: float
long: float long: float
def __str__(self): def __str__(self):
ns = 'N' if self.lat >= 0 else 'S' ns = 'N' if self.lat >= 0 else 'S'
we = 'E' if self.long >= 0 else 'W' we = 'E' if self.long >= 0 else 'W'

View File

@ -6,4 +6,4 @@ class Coordinate(typing.NamedTuple):
long: float long: float
trash = Coordinate('foo', None) # <1> trash = Coordinate('foo', None) # <1>
print(trash) print(trash)

View File

@ -1,4 +1,3 @@
""" """
>>> import copy >>> import copy
>>> bus1 = Bus(['Alice', 'Bill', 'Claire', 'David']) >>> bus1 = Bus(['Alice', 'Bill', 'Claire', 'David'])

View File

@ -2,7 +2,7 @@
>>> import weakref >>> import weakref
>>> stock = weakref.WeakValueDictionary() >>> stock = weakref.WeakValueDictionary()
>>> catalog = [Cheese('Red Leicester'), Cheese('Tilsit'), >>> catalog = [Cheese('Red Leicester'), Cheese('Tilsit'),
... Cheese('Brie'), Cheese('Parmesan')] ... Cheese('Brie'), Cheese('Parmesan')]
... ...
>>> for cheese in catalog: >>> for cheese in catalog:
... stock[cheese.kind] = cheese ... stock[cheese.kind] = cheese
@ -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[]

View File

@ -1,5 +1,3 @@
""" """
# tag::TAG_DEMO[] # tag::TAG_DEMO[]
>>> tag('br') # <1> >>> tag('br') # <1>

View File

@ -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]] = {

View File

@ -1,4 +1,3 @@
""" """
>>> import copy >>> import copy
>>> bus1 = Bus(['Alice', 'Bill', 'Claire', 'David']) >>> bus1 = Bus(['Alice', 'Bill', 'Claire', 'David'])

View File

@ -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>

View File

@ -19,7 +19,7 @@
# tag::CLIP_ANNOT[] # tag::CLIP_ANNOT[]
def clip(text:str, max_len:'int > 0'=80) -> str: # <1> def clip(text: str, max_len: 'int > 0'=80) -> str: # <1>
"""Return text clipped at the last space before or after max_len """Return text clipped at the last space before or after max_len
""" """
end = None end = None

View File

@ -21,7 +21,7 @@ NAMES = {
def rgb2hex(color=Tuple[int, int, int]) -> str: def rgb2hex(color=Tuple[int, int, int]) -> str:
if any(c not in range(256) for c in color): if any(c not in range(256) for c in color):
raise ValueError('Color components must be in range(256)') raise ValueError('Color components must be in range(256)')
values = (f'{n % 256:02x}' for n in color) values = (f'{n % 256:02x}' for n in color)
return '#' + ''.join(values) return '#' + ''.join(values)

View File

@ -31,7 +31,7 @@ def demo() -> None:
print(f'{cell:5}', end='') print(f'{cell:5}', end='')
print() print()
print() print()
if __name__ == '__main__': if __name__ == '__main__':
demo() demo()

View File

@ -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'),

View File

@ -24,7 +24,7 @@ def max(__iterable: Iterable[_CT], *, key: None = ...) -> _CT:
def max(__iterable: Iterable[_T], *, key: Callable[[_T], _CT]) -> _T: def max(__iterable: Iterable[_T], *, key: Callable[[_T], _CT]) -> _T:
... ...
@overload @overload
def max(__iterable: Iterable[_CT], *, key: None = ..., def max(__iterable: Iterable[_CT], *, key: None = ...,
default: _DT) -> Union[_CT, _DT]: default: _DT) -> Union[_CT, _DT]:
... ...
@overload @overload

View File

@ -8,7 +8,7 @@ Example:
>>> l = 'mango pear apple kiwi banana'.split() >>> l = 'mango pear apple kiwi banana'.split()
>>> top(l, 3) >>> top(l, 3)
['pear', 'mango', 'kiwi'] ['pear', 'mango', 'kiwi']
>>> >>>
>>> l2 = [(len(s), s) for s in l] >>> l2 = [(len(s), s) for s in l]
>>> l2 >>> l2
[(5, 'mango'), (4, 'pear'), (5, 'apple'), (4, 'kiwi'), (6, 'banana')] [(5, 'mango'), (4, 'pear'), (5, 'apple'), (4, 'kiwi'), (6, 'banana')]

View File

@ -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[]

View File

@ -13,7 +13,7 @@ def mode(data: Iterable[T]) -> T:
def demo() -> None: def demo() -> None:
from typing import List, Set, TYPE_CHECKING from typing import List, Set, TYPE_CHECKING
pop:List[Set] = [set(), set()] pop: List[Set] = [set(), set()]
m = mode(pop) m = mode(pop)
if TYPE_CHECKING: if TYPE_CHECKING:
reveal_type(pop) reveal_type(pop)

View File

@ -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:

View File

@ -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:

View File

@ -30,7 +30,7 @@ def demo() -> None:
l33t = [(p[0], p[1]) for p in 'a4 e3 i1 o0'.split()] l33t = [(p[0], p[1]) for p in 'a4 e3 i1 o0'.split()]
text = 'mad skilled noob powned leet' text = 'mad skilled noob powned leet'
print(zip_replace(text, l33t)) print(zip_replace(text, l33t))
if __name__ == '__main__': if __name__ == '__main__':
demo() demo()

View File

@ -33,7 +33,7 @@ def demo() -> None:
l33t = [FromTo(*p) for p in 'a4 e3 i1 o0'.split()] l33t = [FromTo(*p) for p in 'a4 e3 i1 o0'.split()]
text = 'mad skilled noob powned leet' text = 'mad skilled noob powned leet'
print(zip_replace(text, l33t)) print(zip_replace(text, l33t))
if __name__ == '__main__': if __name__ == '__main__':
demo() demo()

View File

@ -17,7 +17,7 @@ def to_xml(book: BookDict) -> str: # <1>
for key, value in book.items(): for key, value in book.items():
if isinstance(value, list): # <3> if isinstance(value, list): # <3>
elements.extend(AUTHOR_EL.format(n) elements.extend(AUTHOR_EL.format(n)
for n in value) for n in value)
else: else:
tag = key.upper() tag = key.upper()
elements.append(f'<{tag}>{value}</{tag}>') elements.append(f'<{tag}>{value}</{tag}>')

View File

@ -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 = """

View File

@ -28,6 +28,6 @@ def make_averager():
def averager(new_value): def averager(new_value):
series.append(new_value) series.append(new_value)
total = sum(series) total = sum(series)
return total/len(series) return total / len(series)
return averager return averager

View File

@ -10,7 +10,7 @@
""" """
class Averager(): class Averager:
def __init__(self): def __init__(self):
self.series = [] self.series = []

View File

@ -5,7 +5,7 @@ from clockdeco import clock
def fibonacci(n): def fibonacci(n):
if n < 2: if n < 2:
return n return n
return fibonacci(n-2) + fibonacci(n-1) return fibonacci(n - 2) + fibonacci(n - 1)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -8,7 +8,7 @@ from clockdeco import clock
def fibonacci(n): def fibonacci(n):
if n < 2: if n < 2:
return n return n
return fibonacci(n-2) + fibonacci(n-1) return fibonacci(n - 2) + fibonacci(n - 1)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -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

View File

@ -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),
] ]

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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>

View File

@ -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)

View File

@ -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):

View File

@ -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[]

View File

@ -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[]

View File

@ -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[]

View File

@ -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),
] ]

View File

@ -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),
] ]

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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):

View File

@ -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):

View File

@ -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[]

View File

@ -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[]

View File

@ -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

View File

@ -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

View File

@ -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,}')

View File

@ -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);
} }
} }

View File

@ -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))

View File

@ -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))

View File

@ -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)

View File

@ -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
""" """

View File

@ -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[]

View File

@ -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[]

View File

@ -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

View File

@ -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[]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -49,4 +49,4 @@ Part / Chapter #|Title|Directory|Notebook|1<sup>st</sup> ed. Chapter&nbsp;#
**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