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)
15.0
"""
@ -39,7 +38,7 @@ class Vector:
self.y = y
def __repr__(self):
return 'Vector(%r, %r)' % (self.x, self.y)
return f'Vector({self.x!r}, {self.y!r})'
def __abs__(self):
return hypot(self.x, self.y)

View File

@ -59,7 +59,7 @@ if __name__ == '__main__':
bisect_fn = bisect.bisect
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)
# END BISECT_DEMO

View File

@ -7,6 +7,6 @@ random.seed(1729)
my_list = []
for i in range(SIZE):
new_item = random.randrange(SIZE*2)
new_item = random.randrange(SIZE * 2)
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):
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 + func :', '[ord(s) for s in symbols if non_ascii(ord(s))]')

View File

@ -20,11 +20,10 @@ metro_areas = [
]
def main():
print('{:15} | {:^9} | {:^9}'.format('', 'lat.', 'long.'))
fmt = '{:15} | {:9.4f} | {:9.4f}'
print(f'{"":15} | {"lat.":^9} | {"long.":^9}')
for name, cc, pop, (latitude, longitude) in metro_areas: # <2>
if longitude <= 0: # <3>
print(fmt.format(name, latitude, longitude))
print(f'{name:15} | {latitude:9.4f} | {longitude:9.4f}')
if __name__ == '__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 match in WORD_RE.finditer(line):
word = match.group()
column_no = match.start()+1
column_no = match.start() + 1
location = (line_no, column_no)
index[word].append(location) # <2>

View File

@ -41,15 +41,15 @@ def test(container_type, verbose):
size=size, verbose=verbose)
test = TEST.format(verbose=verbose)
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:
sys.argv.remove('-v')
verbose = True
else:
verbose = False
if len(sys.argv) != 2:
print('Usage: %s <container_type>' % sys.argv[0])
print(f'Usage: {sys.argv[0]} <container_type>')
else:
test(sys.argv[1], verbose)

View File

@ -2,8 +2,8 @@
Generate data for container performance test
"""
import random
import array
import random
MAX_EXPONENT = 7
HAYSTACK_LEN = 10 ** MAX_EXPONENT
@ -12,26 +12,26 @@ SAMPLE_LEN = HAYSTACK_LEN + NEEDLES_LEN // 2
needles = array.array('d')
sample = {1/random.random() for i in range(SAMPLE_LEN)}
print('initial sample: %d elements' % len(sample))
sample = {1 / random.random() for i in range(SAMPLE_LEN)}
print(f'initial sample: {len(sample)} elements')
# complete sample, in case duplicate random numbers were discarded
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)
random.shuffle(sample)
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')
with open('not_selected.arr', 'wb') as fp:
not_selected.tofile(fp)
selected = sample[NEEDLES_LEN // 2:]
print('selected: %d samples' % len(selected))
print(f'selected: {len(selected)} samples')
print(' writing selected.arr')
with open('selected.arr', 'wb') as fp:
selected.tofile(fp)

View File

@ -1,17 +1,17 @@
import sys
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):
h1 = '{:>0{}b}'.format(hash(o1), MAX_BITS)
h2 = '{:>0{}b}'.format(hash(o2), MAX_BITS)
h1 = f'{hash(o1):>0{MAX_BITS}b}'
h2 = f'{hash(o2):>0{MAX_BITS}b}'
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)
sep = '-' * (width * 2 + MAX_BITS)
return '{!r:{width}} {}\n{:{width}} {} {}\n{!r:{width}} {}\n{}'.format(
o1, h1, ' ' * width, diff, count, o2, h2, sep, width=width)
return (f'{o1!r:{width}} {h1}\n{" ":{width}} {diff} {count}\n'
f'{o2!r:{width}} {h2}\n{sep}')
if __name__ == '__main__':
print(hash_diff(1, 1.0))

View File

@ -17,7 +17,7 @@ _sentinel = object()
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.
>>> d = TransformDict(str.lower)
@ -26,18 +26,18 @@ class TransformDict(MutableMapping):
True
>>> set(d.keys())
{'Foo'}
'''
"""
__slots__ = ('_transform', '_original', '_data')
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
dict constructor.
'''
"""
if not callable(transform):
msg = 'expected a callable, got %r'
raise TypeError(msg % transform.__class__)
raise TypeError(
f'expected a callable, got {transform.__class__!r}')
self._transform = transform
# transformed => original
self._original = {}
@ -48,7 +48,7 @@ class TransformDict(MutableMapping):
self.update(kwargs)
def getitem(self, key):
'D.getitem(key) -> (stored key, value)'
"""D.getitem(key) -> (stored key, value)"""
transformed = self._transform(key)
original = self._original[transformed]
value = self._data[transformed]
@ -56,7 +56,7 @@ class TransformDict(MutableMapping):
@property
def transform_func(self):
"This TransformDict's transformation function"
"""This TransformDict's transformation function"""
return self._transform
# Minimum set of methods required for MutableMapping
@ -83,7 +83,7 @@ class TransformDict(MutableMapping):
# Methods overridden to mitigate the performance overhead.
def clear(self):
'D.clear() -> None. Remove all items from D.'
"""D.clear() -> None. Remove all items from D."""
self._data.clear()
self._original.clear()
@ -91,14 +91,14 @@ class TransformDict(MutableMapping):
return self._transform(key) in self._data
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)
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
KeyError is raised.
'''
"""
transformed = self._transform(key)
if default is _sentinel:
del self._original[transformed]
@ -108,16 +108,16 @@ class TransformDict(MutableMapping):
return self._data.pop(transformed, default)
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.
'''
"""
transformed, value = self._data.popitem()
return self._original.pop(transformed), value
# Other methods
def copy(self):
'D.copy() -> a shallow copy of D'
"""D.copy() -> a shallow copy of D"""
other = self.__class__(self._transform)
other._original = self._original.copy()
other._data = self._data.copy()
@ -137,5 +137,4 @@ class TransformDict(MutableMapping):
except TypeError:
# Some keys are unhashable, fall back on .items()
equiv = list(self.items())
return '%s(%r, %s)' % (self.__class__.__name__,
self._transform, repr(equiv))
return f'{self.__class__.__name__}({self._transform!r}, {equiv!r})'

View File

@ -18,4 +18,4 @@ my_file = open('dummy', 'w')
for expression in expressions.split():
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'
for char in sample:
print('U+%04x' % ord(char), # <1>
print(f'U+{ord(char):04x}', # <1>
char.center(6), # <2>
're_dig' if re_digit.match(char) else '-', # <3>
'isdig' if char.isdigit() else '-', # <4>
'isnum' if char.isnumeric() else '-', # <5>
format(unicodedata.numeric(char), '5.2f'), # <6>
f'{unicodedata.numeric(char):5.2f}', # <6>
unicodedata.name(char), # <7>
sep='\t')
# 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>
print('Text', repr(text_str), sep='\n ')
print(f'Text\n {text_str!r}')
print('Numbers')
print(' str :', re_numbers_str.findall(text_str)) # <6>
print(' bytes:', re_numbers_bytes.findall(text_bytes)) # <7>

View File

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

View File

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

View File

@ -2,7 +2,7 @@
>>> import weakref
>>> stock = weakref.WeakValueDictionary()
>>> catalog = [Cheese('Red Leicester'), Cheese('Tilsit'),
... Cheese('Brie'), Cheese('Parmesan')]
... Cheese('Brie'), Cheese('Parmesan')]
...
>>> for cheese in catalog:
... stock[cheese.kind] = cheese
@ -24,5 +24,5 @@ class Cheese:
self.kind = kind
def __repr__(self):
return 'Cheese(%r)' % self.kind
return f'Cheese({self.kind!r})'
# end::CHEESE_CLASS[]

View File

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

View File

@ -2,7 +2,7 @@
import sys
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]] = {

View File

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

View File

@ -17,7 +17,7 @@ import re
import unicodedata
from typing import Dict, Set, Iterator
RE_WORD = re.compile('\w+')
RE_WORD = re.compile(r'\w+')
STOP_CODE = sys.maxunicode + 1
def tokenize(text: str) -> Iterator[str]: # <1>

View File

@ -19,7 +19,7 @@
# 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
"""
end = None

View File

@ -48,7 +48,7 @@ def test_columnize_8_in_3():
def test_columnize_8_in_5():
# 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'
expected = [
('A', 'C', 'E', 'G'),
@ -60,7 +60,7 @@ def test_columnize_8_in_5():
def test_columnize_7_in_5():
# 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'
expected = [
('A', 'C', 'E', 'G'),

View File

@ -14,6 +14,6 @@ from geolib import geohash as gh # type: ignore
PRECISION = 9
def geohash(lat_lon = Tuple[float, float]) -> str:
def geohash(lat_lon: Tuple[float, float]) -> str:
return gh.encode(*lat_lon, PRECISION)
# end::GEOHASH[]

View File

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

View File

@ -13,7 +13,7 @@ def mode(data: Iterable[NumberT]) -> NumberT:
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)]
m = mode(pop)
if TYPE_CHECKING:

View File

@ -57,7 +57,7 @@ def load_hash() -> Tuple[bytes, bytes]:
sys.exit(2)
salt, stored_hash = salted_hash.split(b':')
return (b64decode(salt), b64decode(stored_hash))
return b64decode(salt), b64decode(stored_hash)
def practice() -> None:
@ -83,8 +83,7 @@ def practice() -> None:
print(f' {answer}\thits={correct}\tmisses={turn-correct}')
if turn:
pct = correct / turn * 100
print(f'\n{turn} turns. {pct:0.1f}% correct.')
print(f'\n{turn} turns. {correct / turn:.1%} correct.')
def main(argv: Sequence[str]) -> None:

View File

@ -1,6 +1,3 @@
import json
from typing import cast
from books import BookDict, to_xml
XML_SAMPLE = """

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5), # <2>
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, FidelityPromo()) # <3>
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, FidelityPromo()) # <4>
@ -72,8 +72,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
class Promotion(ABC): # the Strategy: an abstract base class

View File

@ -21,7 +21,7 @@ def cart_plain() -> List[LineItem]:
return [
LineItem('banana', 4, 0.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)
>>> cart = [LineItem('banana', 4, .5), # <2>
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, FidelityPromo()) # <3>
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, FidelityPromo()) # <4>
@ -29,7 +29,6 @@
# tag::CLASSIC_STRATEGY[]
from abc import ABC, abstractmethod
from collections import namedtuple
import typing
@ -69,8 +68,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
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]:
return [LineItem('banana', 4, .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:

View File

@ -8,7 +8,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5), # <2>
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, FidelityPromo()) # <3>
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, FidelityPromo()) # <4>
@ -29,7 +29,6 @@
# tag::CLASSIC_STRATEGY[]
from abc import ABC, abstractmethod
from collections import namedtuple
import typing
from pytypes import typelogged
@ -71,8 +70,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
@typelogged

View File

@ -20,7 +20,7 @@ def customer_fidelity_1100() -> Customer:
def cart_plain() -> List[LineItem]:
return [LineItem('banana', 4, .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:

View File

@ -8,7 +8,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5),
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, fidelity_promo) # <2>
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, fidelity_promo)
@ -71,8 +71,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
# <2>

View File

@ -7,7 +7,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5),
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> banana_cart = [LineItem('banana', 30, .5),
... LineItem('apple', 10, 1.5)]
>>> big_cart = [LineItem(str(item_code), 1, 1.0)

View File

@ -7,7 +7,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5),
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, fidelity_promo)
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, fidelity_promo)
@ -69,8 +69,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
def fidelity_promo(order):

View File

@ -8,7 +8,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5),
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, fidelity_promo)
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, fidelity_promo)
@ -73,8 +73,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
# tag::STRATEGY_BEST3[]

View File

@ -8,7 +8,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5),
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, fidelity)
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, fidelity)
@ -71,8 +71,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
# tag::STRATEGY_BEST4[]

View File

@ -6,7 +6,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5),
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, fidelity_promo(10))
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, fidelity_promo(10))
@ -73,8 +73,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
# tag::STRATEGY_PARAM[]
@ -85,7 +84,7 @@ Promotion = Callable[[Order], float] # <2>
def fidelity_promo(percent: float) -> Promotion:
"""discount for customers with 1000 or more fidelity points"""
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
for item in order.cart:
if item.quantity >= 20:
discount += item.total() * percent / 100.0
discount += item.total() * percent / 100
return discount
return discounter
@ -111,13 +110,13 @@ class LargeOrderPromo:
def __call__(self, order: Order) -> float:
distinct_items = {item.product for item in order.cart}
if len(distinct_items) >= 10:
return order.total() * self.percent / 100.0
return order.total() * self.percent / 100
return 0
def general_discount(percent: float, order: Order) -> float:
"""unrestricted discount; usage: ``partial(general_discount, 5)``"""
return order.total() * percent / 100.0
return order.total() * percent / 100
# end::STRATEGY[]

View File

@ -23,7 +23,7 @@ def cart_plain() -> List[LineItem]:
return [
LineItem('banana', 4, 0.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 [
LineItem('banana', 4, 0.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)
>>> cart = [LineItem('banana', 4, .5), # <2>
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, FidelityPromo()) # <3>
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, FidelityPromo()) # <4>
@ -65,8 +65,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
class Promotion(ABC): # the Strategy: an abstract base class

View File

@ -1,4 +1,3 @@
def fidelity_promo(order):
"""5% discount for customers with 1000 or more fidelity points"""
return order.total() * .05 if order.customer.fidelity >= 1000 else 0

View File

@ -8,7 +8,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5),
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, fidelity_promo) # <2>
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, fidelity_promo)
@ -64,8 +64,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
# <2>

View File

@ -7,7 +7,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5),
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, fidelity_promo)
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, fidelity_promo)
@ -71,8 +71,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
def fidelity_promo(order):

View File

@ -7,7 +7,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5),
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, fidelity_promo)
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, fidelity_promo)
@ -71,8 +71,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
def fidelity_promo(order):

View File

@ -8,7 +8,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5),
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, fidelity_promo)
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, fidelity_promo)
@ -75,8 +75,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
# tag::STRATEGY_BEST3[]

View File

@ -8,7 +8,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5),
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, fidelity)
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, fidelity)
@ -72,8 +72,7 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
# tag::STRATEGY_BEST4[]

View File

@ -6,7 +6,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5),
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, fidelity_promo(10))
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, fidelity_promo(10))
@ -60,13 +60,12 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
def fidelity_promo(percent):
"""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)
@ -76,7 +75,7 @@ def bulk_item_promo(percent):
discount = 0
for item in order.cart:
if item.quantity >= 20:
discount += item.total() * percent/100.0
discount += item.total() * percent / 100
return discount
return discounter
@ -86,6 +85,6 @@ def large_order_promo(percent):
def discounter(order):
distinct_items = {item.product for item in order.cart}
if len(distinct_items) >= 10:
return order.total() * percent / 100.0
return order.total() * percent / 100
return 0
return discounter

View File

@ -6,7 +6,7 @@
>>> ann = Customer('Ann Smith', 1100)
>>> cart = [LineItem('banana', 4, .5),
... LineItem('apple', 10, 1.5),
... LineItem('watermellon', 5, 5.0)]
... LineItem('watermelon', 5, 5.0)]
>>> Order(joe, cart, FidelityPromo(10))
<Order total: 42.00 due: 42.00>
>>> Order(ann, cart, FidelityPromo(10))
@ -60,11 +60,10 @@ class Order: # the Context
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
return f'<Order total: {self.total():.2f} due: {self.due():.2f}>'
class Promotion():
class Promotion:
"""compute discount for order"""
def __init__(self, percent):
@ -79,7 +78,7 @@ class FidelityPromo(Promotion):
def __call__(self, order):
if order.customer.fidelity >= 1000:
return order.total() * self.percent/100.0
return order.total() * self.percent / 100
return 0
@ -90,7 +89,7 @@ class BulkItemPromo(Promotion):
discount = 0
for item in order.cart:
if item.quantity >= 20:
discount += item.total() * self.percent/100.0
discount += item.total() * self.percent / 100
return discount
@ -100,5 +99,5 @@ class LargeOrderPromo(Promotion):
def __call__(self, order):
distinct_items = {item.product for item in order.cart}
if len(distinct_items) >= 10:
return order.total() * self.percent / 100.0
return order.total() * self.percent / 100
return 0

View File

@ -8,17 +8,17 @@ if len(sys.argv) == 2:
module_name = sys.argv[1].replace('.py', '')
module = importlib.import_module(module_name)
else:
print('Usage: {} <vector-module-to-test>'.format())
print(f'Usage: {sys.argv[0]} <vector-module-to-test>')
sys.exit(1)
fmt = 'Selected Vector2d type: {.__name__}.{.__name__}'
print(fmt.format(module, module.Vector2d))
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)]
mem_final = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
print('Initial RAM usage: {:14,}'.format(mem_init))
print(' Final RAM usage: {:14,}'.format(mem_final))
print(f'Initial RAM usage: {mem_init:14,}')
print(f' Final RAM usage: {mem_final:14,}')

View File

@ -18,7 +18,7 @@ public class Expose {
System.out.println("message.secret = " + wasHidden);
}
catch (IllegalAccessException e) {
// this will not happen after setAcessible(true)
// this will not happen after setAccessible(true)
System.err.println(e);
}
}

View File

@ -3,4 +3,4 @@ import Confidential
message = Confidential('top secret text')
secret_field = Confidential.getDeclaredField('secret')
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
if Modifier.isPrivate(field.getModifiers()):
field.setAccessible(True) # break the lock
print 'field:', field
print '\t', field.getName(), '=', field.get(message)
print('field:', field)
print('\t', field.getName(), '=', field.get(message))

View File

@ -1,4 +1,3 @@
"""
In the Jython registry file there is this line:
@ -14,4 +13,4 @@ message = Confidential('top secret text')
for name in dir(message):
attr = getattr(message, name)
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)
>>> hash(v1), hash(v2)
(7, 384307168202284039)
>>> len(set([v1, v2]))
>>> len({v1, v2})
2
"""

View File

@ -83,7 +83,7 @@ Tests of hashing:
>>> v2 = Vector2d(3.1, 4.2)
>>> hash(v1), hash(v2)
(7, 384307168202284039)
>>> len(set([v1, v2]))
>>> len({v1, v2})
2
# end::VECTOR2D_V3_DEMO[]

View File

@ -80,7 +80,7 @@ Tests of hashing:
>>> v2 = Vector2d(3.1, 4.2)
>>> hash(v1), hash(v2)
(7, 384307168202284039)
>>> len(set([v1, v2]))
>>> len({v1, v2})
2
# end::VECTOR2D_V3_DEMO[]

View File

@ -1,5 +1,4 @@
import math
import itertools
PRIME_FIXTURE = [
@ -36,7 +35,7 @@ def is_prime(n) -> bool:
if n % 2 == 0:
return False
root = int(math.floor(math.sqrt(n)))
root = math.floor(math.sqrt(n))
for i in range(3, root + 1, 2):
if n % i == 0:
return False

View File

@ -34,10 +34,10 @@ def main() -> None:
label = 'P' if prime else ' '
print(f'{n:16} {label} {elapsed:9.6f}s')
time = perf_counter() - t0
print('Total time:', f'{time:0.2f}s')
if __name__ == '__main__':
main()
# end::PRIMES_PROC_MAIN[]

View File

@ -18,7 +18,7 @@ async def is_prime(n):
return False
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):
if n % i == 0:
return False

View File

@ -18,7 +18,7 @@ async def is_prime(n):
return False
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):
if n % i == 0:
return False

View File

@ -7,7 +7,6 @@
from multiprocessing import Process, Event
from multiprocessing import synchronize
import itertools
import time
from primes import is_prime

View File

@ -6,7 +6,6 @@
from threading import Thread, Event
import itertools
import time
from primes import is_prime

View File

@ -7,7 +7,6 @@
# tag::SPINNER_THREAD_TOP[]
from threading import Thread, Event
import itertools
import time
from primes import is_prime

View File

@ -1,5 +1,5 @@
from time import perf_counter
from typing import Tuple, List, NamedTuple
from typing import List, NamedTuple
from threading import Thread
from queue import SimpleQueue

View File

@ -49,4 +49,4 @@ Part / Chapter #|Title|Directory|Notebook|1<sup>st</sup> ed. Chapter&nbsp;#
**VI Metaprogramming**|
22|Dynamic Attributes and Properties|[22-dyn-attr-prop](22-dyn-attr-prop)||19
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