Mastering Python Second Edition Release Code
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
Chapter 4, Functional Programming
|
||||
##############################################################################
|
||||
|
||||
| Readability versus Brevity covers the functional programming techniques such as list/dict/set comprehensions and lambda statements that are available in Python. Additionally, it illustrates the similarities to the mathematical principles involved.
|
||||
@@ -0,0 +1,17 @@
|
||||
>>> def add_value_functional(items, value):
|
||||
... return items + [value]
|
||||
|
||||
>>> items = [1, 2, 3]
|
||||
>>> add_value_functional(items, 5)
|
||||
[1, 2, 3, 5]
|
||||
>>> items
|
||||
[1, 2, 3]
|
||||
|
||||
>>> def add_value_regular(items, value):
|
||||
... items.append(value)
|
||||
... return items
|
||||
|
||||
>>> add_value_regular(items, 5)
|
||||
[1, 2, 3, 5]
|
||||
>>> items
|
||||
[1, 2, 3, 5]
|
||||
@@ -0,0 +1,129 @@
|
||||
>>> squares = [x ** 2 for x in range(10)]
|
||||
>>> squares
|
||||
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> odd_squares = [x ** 2 for x in range(10) if x % 2]
|
||||
>>> odd_squares
|
||||
[1, 9, 25, 49, 81]
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> def square(x):
|
||||
... return x ** 2
|
||||
|
||||
>>> def odd(x):
|
||||
... return x % 2
|
||||
|
||||
>>> squares = list(map(square, range(10)))
|
||||
>>> squares
|
||||
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
|
||||
|
||||
>>> odd_squares = list(filter(odd, map(square, range(10))))
|
||||
>>> odd_squares
|
||||
[1, 9, 25, 49, 81]
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> import os
|
||||
|
||||
>>> directories = filter(os.path.isdir, os.listdir('.'))
|
||||
|
||||
# Versus:
|
||||
|
||||
>>> directories = [x for x in os.listdir('.') if os.path.isdir(x)]
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> odd_squares = []
|
||||
>>> for x in range(10):
|
||||
... if x % 2:
|
||||
... odd_squares.append(x ** 2)
|
||||
|
||||
>>> odd_squares
|
||||
[1, 9, 25, 49, 81]
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
# List comprehension
|
||||
|
||||
>>> [x // 2 for x in range(3)]
|
||||
[0, 0, 1]
|
||||
|
||||
# Set comprehension
|
||||
|
||||
>>> numbers = {x // 2 for x in range(3)}
|
||||
>>> sorted(numbers)
|
||||
[0, 1]
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> import random
|
||||
|
||||
>>> [random.random() for _ in range(10) if random.random() >= 0.5]
|
||||
... # doctest: +SKIP
|
||||
[0.5211948104577864, 0.650010512129705, 0.021427316545174158]
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> import random
|
||||
|
||||
>>> numbers = [random.random() for _ in range(10)] # doctest: +SKIP
|
||||
|
||||
>>> [x for x in numbers if x >= 0.5] # doctest: +SKIP
|
||||
[0.715510247827078, 0.8426277505519564, 0.5071133900377911]
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> import random
|
||||
|
||||
>>> [x for x in [random.random() for _ in range(10)] if x >= 0.5]
|
||||
... # doctest: +SKIP
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> import random
|
||||
|
||||
>>> [x for _ in range(10) for x in [random.random()] if x >= 0.5]
|
||||
... # doctest: +SKIP
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> [(x, y) for x in range(3) for y in range(3, 5)]
|
||||
[(0, 3), (0, 4), (1, 3), (1, 4), (2, 3), (2, 4)]
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> results = []
|
||||
>>> for x in range(3):
|
||||
... for y in range(3, 5):
|
||||
... results.append((x, y))
|
||||
...
|
||||
>>> results
|
||||
[(0, 3), (0, 4), (1, 3), (1, 4), (2, 3), (2, 4)]
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> matrix = [
|
||||
... [1, 2, 3, 4],
|
||||
... [5, 6, 7, 8],
|
||||
... [9, 10, 11, 12],
|
||||
... ]
|
||||
|
||||
>>> reshaped_matrix = [
|
||||
... [
|
||||
... [y for x in matrix for y in x][i * len(matrix) + j]
|
||||
... for j in range(len(matrix))
|
||||
... ]
|
||||
... for i in range(len(matrix[0]))
|
||||
... ]
|
||||
|
||||
>>> import pprint
|
||||
|
||||
>>> pprint.pprint(reshaped_matrix, width=40)
|
||||
[[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8, 9],
|
||||
[10, 11, 12]]
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
>>> {x: x ** 2 for x in range(6)}
|
||||
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
|
||||
|
||||
>>> {x: x ** 2 for x in range(6) if x % 2}
|
||||
{1: 1, 3: 9, 5: 25}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> {x ** 2: [y for y in range(x)] for x in range(5)}
|
||||
{0: [], 1: [0], 4: [0, 1], 9: [0, 1, 2], 16: [0, 1, 2, 3]}
|
||||
@@ -0,0 +1,5 @@
|
||||
>>> [x*y for x in range(3) for y in range(3)]
|
||||
[0, 0, 0, 0, 1, 2, 0, 2, 4]
|
||||
|
||||
>>> {x*y for x in range(3) for y in range(3)}
|
||||
{0, 1, 2, 4}
|
||||
@@ -0,0 +1,25 @@
|
||||
>>> import operator
|
||||
|
||||
>>> values = dict(one=1, two=2, three=3)
|
||||
>>> sorted(values.items())
|
||||
[('one', 1), ('three', 3), ('two', 2)]
|
||||
>>> sorted(values.items(), key=lambda item: item[1])
|
||||
[('one', 1), ('two', 2), ('three', 3)]
|
||||
|
||||
>>> get_value = operator.itemgetter(1)
|
||||
>>> sorted(values.items(), key=get_value)
|
||||
[('one', 1), ('two', 2), ('three', 3)]
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> key = lambda item: item[1]
|
||||
|
||||
>>> def key(item):
|
||||
... return item[1]
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> def key(spam): return spam.value
|
||||
|
||||
>>> key = lambda spam: spam.value
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
::
|
||||
|
||||
Y = lambda f: lambda *args: f(Y(f))(*args)
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
def Y(f):
|
||||
def y(*args):
|
||||
y_function = f(Y(f))
|
||||
return y_function(*args)
|
||||
return y
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> Y = lambda f: lambda *args: f(Y(f))(*args)
|
||||
|
||||
>>> def factorial(combinator):
|
||||
... def _factorial(n):
|
||||
... if n:
|
||||
... return n * combinator(n - 1)
|
||||
... else:
|
||||
... return 1
|
||||
... return _factorial
|
||||
>>> Y(factorial)(5)
|
||||
120
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> Y = lambda f: lambda *args: f(Y(f))(*args)
|
||||
|
||||
>>> Y(lambda c: lambda n: n and n * c(n - 1) or 1)(5)
|
||||
120
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> Y = lambda f: lambda *args: f(Y(f))(*args)
|
||||
|
||||
>>> Y(lambda c: lambda n: n * c(n - 1) if n else 1)(5)
|
||||
120
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> quicksort = Y(lambda f:
|
||||
... lambda x: (
|
||||
... f([item for item in x if item < x[0]])
|
||||
... + [y for y in x if x[0] == y]
|
||||
... + f([item for item in x if item > x[0]])
|
||||
... ) if x else [])
|
||||
|
||||
>>> quicksort([1, 3, 5, 4, 1, 3, 2])
|
||||
[1, 1, 2, 3, 3, 4, 5]
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
>>> import heapq
|
||||
|
||||
>>> heap = []
|
||||
>>> heapq.heappush(heap, 1)
|
||||
>>> heapq.heappush(heap, 3)
|
||||
>>> heapq.heappush(heap, 5)
|
||||
>>> heapq.heappush(heap, 2)
|
||||
>>> heapq.heappush(heap, 4)
|
||||
>>> heapq.nsmallest(3, heap)
|
||||
[1, 2, 3]
|
||||
|
||||
------------------------------------------------------------------
|
||||
|
||||
>>> def push(*args, **kwargs):
|
||||
... return heapq.heappush(heap, *args, **kwargs)
|
||||
|
||||
------------------------------------------------------------------
|
||||
|
||||
>>> import functools
|
||||
>>> import heapq
|
||||
|
||||
>>> heap = []
|
||||
>>> push = functools.partial(heapq.heappush, heap)
|
||||
>>> smallest = functools.partial(heapq.nsmallest, iterable=heap)
|
||||
|
||||
>>> push(1)
|
||||
>>> push(3)
|
||||
>>> push(5)
|
||||
>>> push(2)
|
||||
>>> push(4)
|
||||
>>> smallest(3)
|
||||
[1, 2, 3]
|
||||
|
||||
------------------------------------------------------------------
|
||||
|
||||
>>> lambda_push = lambda x: heapq.heappush(heap, x)
|
||||
|
||||
>>> heapq.heappush
|
||||
<built-in function heappush>
|
||||
>>> push
|
||||
functools.partial(<built-in function heappush>, [1, 2, 5, 3, 4])
|
||||
>>> lambda_push
|
||||
<function <lambda> at ...>
|
||||
|
||||
>>> heapq.heappush.__doc__
|
||||
'Push item onto heap, maintaining the heap invariant.'
|
||||
>>> push.__doc__
|
||||
'partial(func, *args, **keywords) - new function ...'
|
||||
>>> lambda_push.__doc__
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
>>> import operator
|
||||
>>> import functools
|
||||
|
||||
>>> functools.reduce(operator.mul, range(1, 5))
|
||||
24
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> from operator import mul
|
||||
|
||||
>>> mul(mul(mul(1, 2), 3), 4)
|
||||
24
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> import operator
|
||||
|
||||
>>> def reduce(function, iterable):
|
||||
... print(f'iterable={iterable}')
|
||||
... # Fetch the first item to prime `result`
|
||||
... result, *iterable = iterable
|
||||
...
|
||||
... for item in iterable:
|
||||
... old_result = result
|
||||
... result = function(result, item)
|
||||
... print(f'{old_result} * {item} = {result}')
|
||||
...
|
||||
... return result
|
||||
|
||||
>>> iterable = list(range(1, 5))
|
||||
>>> iterable
|
||||
[1, 2, 3, 4]
|
||||
|
||||
>>> reduce(operator.mul, iterable)
|
||||
iterable=[1, 2, 3, 4]
|
||||
1 * 2 = 2
|
||||
2 * 3 = 6
|
||||
6 * 4 = 24
|
||||
24
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> import operator
|
||||
|
||||
>>> iterable = range(1, 5)
|
||||
|
||||
# The initial values:
|
||||
|
||||
>>> a, b, *iterable = iterable
|
||||
>>> a, b, iterable
|
||||
(1, 2, [3, 4])
|
||||
|
||||
# First run
|
||||
|
||||
>>> a = operator.mul(a, b)
|
||||
>>> b, *iterable = iterable
|
||||
>>> a, b, iterable
|
||||
(2, 3, [4])
|
||||
|
||||
# Second run
|
||||
|
||||
>>> a = operator.mul(a, b)
|
||||
>>> b, *iterable = iterable
|
||||
>>> a, b, iterable
|
||||
(6, 4, [])
|
||||
|
||||
# Third and last run
|
||||
|
||||
>>> a = operator.mul (a, b)
|
||||
>>> a
|
||||
24
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> import operator
|
||||
>>> import collections
|
||||
|
||||
>>> iterable = collections.deque(range(1, 5))
|
||||
|
||||
>>> value = iterable.popleft()
|
||||
>>> while iterable:
|
||||
... value = operator.mul(value, iterable.popleft())
|
||||
|
||||
>>> value
|
||||
24
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
>>> import json
|
||||
>>> import functools
|
||||
>>> import collections
|
||||
|
||||
>>> def tree():
|
||||
... return collections.defaultdict(tree)
|
||||
|
||||
# Build the tree:
|
||||
|
||||
>>> taxonomy = tree()
|
||||
>>> reptilia = taxonomy['Chordata']['Vertebrata']['Reptilia']
|
||||
>>> reptilia['Squamata']['Serpentes']['Pythonidae'] = [
|
||||
... 'Liasis', 'Morelia', 'Python']
|
||||
|
||||
# The actual contents of the tree
|
||||
|
||||
>>> print(json.dumps(taxonomy, indent=4))
|
||||
{
|
||||
"Chordata": {
|
||||
"Vertebrata": {
|
||||
"Reptilia": {
|
||||
"Squamata": {
|
||||
"Serpentes": {
|
||||
"Pythonidae": [
|
||||
"Liasis",
|
||||
"Morelia",
|
||||
"Python"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Let's build the lookup function
|
||||
|
||||
>>> import operator
|
||||
|
||||
>>> def lookup(tree, path):
|
||||
... # Split the path for easier access
|
||||
... path = path.split('.')
|
||||
...
|
||||
... # Use `operator.getitem(a, b)` to get `a[b]`
|
||||
... # And use reduce to recursively fetch the items
|
||||
... return functools.reduce(operator.getitem, path, tree)
|
||||
|
||||
|
||||
>>> path = 'Chordata.Vertebrata.Reptilia.Squamata.Serpentes'
|
||||
>>> dict(lookup(taxonomy, path))
|
||||
{'Pythonidae': ['Liasis', 'Morelia', 'Python']}
|
||||
|
||||
# The path we wish to get
|
||||
|
||||
>>> path = 'Chordata.Vertebrata.Reptilia.Squamata'
|
||||
>>> lookup(taxonomy, path).keys()
|
||||
dict_keys(['Serpentes'])
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> fold_left = lambda iterable, initializer=None: functools.reduce(
|
||||
... lambda x, y: function(x, y),
|
||||
... iterable,
|
||||
... initializer,
|
||||
... )
|
||||
|
||||
>>> fold_right = lambda iterable, initializer=None: functools.reduce(
|
||||
... lambda x, y: function(y, x),
|
||||
... reversed(iterable),
|
||||
... initializer,
|
||||
... )
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
>>> import operator
|
||||
>>> import itertools
|
||||
|
||||
# Sales per month
|
||||
|
||||
>>> months = [10, 8, 5, 7, 12, 10, 5, 8, 15, 3, 4, 2]
|
||||
>>> list(itertools.accumulate(months, operator.add))
|
||||
[10, 18, 23, 30, 42, 52, 57, 65, 80, 83, 87, 89]
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
>>> import itertools
|
||||
|
||||
>>> a = range(3)
|
||||
>>> b = range(5)
|
||||
>>> list(itertools.chain(a, b))
|
||||
[0, 1, 2, 0, 1, 2, 3, 4]
|
||||
|
||||
|
||||
>>> import itertools
|
||||
|
||||
>>> iterables = [range(3), range(5)]
|
||||
>>> list(itertools.chain.from_iterable(iterables))
|
||||
[0, 1, 2, 0, 1, 2, 3, 4]
|
||||
@@ -0,0 +1,24 @@
|
||||
>>> import itertools
|
||||
|
||||
>>> list(itertools.compress(range(1000), [0, 1, 1, 1, 0, 1]))
|
||||
[1, 2, 3, 5]
|
||||
|
||||
|
||||
>>> primes = [0, 0, 1, 1, 0, 1, 0, 1]
|
||||
>>> odd = [0, 1, 0, 1, 0, 1, 0, 1]
|
||||
>>> numbers = ['zero', 'one', 'two', 'three', 'four', 'five']
|
||||
|
||||
# Primes:
|
||||
|
||||
>>> list(itertools.compress(numbers, primes))
|
||||
['two', 'three', 'five']
|
||||
|
||||
# Odd numbers
|
||||
|
||||
>>> list(itertools.compress(numbers, odd))
|
||||
['one', 'three', 'five']
|
||||
|
||||
# Odd primes
|
||||
|
||||
>>> list(itertools.compress(numbers, map(all, zip(odd, primes))))
|
||||
['three', 'five']
|
||||
@@ -0,0 +1,9 @@
|
||||
>>> import itertools
|
||||
|
||||
>>> list(itertools.dropwhile(lambda x: x <= 3, [1, 3, 5, 4, 2]))
|
||||
[5, 4, 2]
|
||||
|
||||
>>> import itertools
|
||||
|
||||
>>> list(itertools.takewhile(lambda x: x <= 3, [1, 3, 5, 4, 2]))
|
||||
[1, 3]
|
||||
@@ -0,0 +1,11 @@
|
||||
>>> import itertools
|
||||
|
||||
>>> list(itertools.islice(itertools.count(), 10))
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
>>> list(itertools.islice(itertools.count(), 5, 10, 2))
|
||||
[5, 7, 9]
|
||||
|
||||
>>> list(itertools.islice(itertools.count(10, 2.5), 5))
|
||||
[10, 12.5, 15.0, 17.5, 20.0]
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
>>> import operator
|
||||
>>> import itertools
|
||||
|
||||
>>> words = ['aa', 'ab', 'ba', 'bb', 'ca', 'cb', 'cc']
|
||||
|
||||
# Gets the first element from the iterable
|
||||
|
||||
>>> getter = operator.itemgetter(0)
|
||||
|
||||
>>> for group, items in itertools.groupby(words, key=getter):
|
||||
... print(f'group: {group}, items: {list(items)}')
|
||||
group: a, items: ['aa', 'ab']
|
||||
group: b, items: ['ba', 'bb']
|
||||
group: c, items: ['ca', 'cb', 'cc']
|
||||
|
||||
------------------------------------------------------------
|
||||
|
||||
>>> import operator
|
||||
>>> import itertools
|
||||
|
||||
>>> words = ['aa', 'bb', 'ca', 'ab', 'ba', 'cb', 'cc']
|
||||
|
||||
# Gets the first element from the iterable
|
||||
|
||||
>>> getter = operator.itemgetter(0)
|
||||
|
||||
>>> for group, items in itertools.groupby(words, key=getter):
|
||||
... print(f'group: {group}, items: {list(items)}')
|
||||
group: a, items: ['aa']
|
||||
group: b, items: ['bb']
|
||||
group: c, items: ['ca']
|
||||
group: a, items: ['ab']
|
||||
group: b, items: ['ba']
|
||||
group: c, items: ['cb', 'cc']
|
||||
Reference in New Issue
Block a user