Skip to content

Commit 7a49b49

Browse files
committed
Add more code samples
1 parent b3e8fe7 commit 7a49b49

File tree

9 files changed

+971
-0
lines changed

9 files changed

+971
-0
lines changed

source-code/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@ was used to develop it.
88

99
1. `context-manager`: illustrates how to write your own context managers.
1010
1. `coroutines`: illustrates how to write coroutines in Python.
11+
1. `decorators`: illustrates how to write decorators in Python.
12+
1. `descriptors`: illustrates how to write descriptors in Python.
1113
1. `design-patterns`: illustrates some common design patterns in Python.
1214
1. `functional-programming`: illustrates some concepts of functional
1315
programming in Python.
16+
1. `introspection`: illustration of how to implement introspection in
17+
Python.
1418
1. `object-orientation`: illustrates some concepts of object-oriented
1519
programming in Python.
1620
1. `operators-functools`: illustrates some applications of the `operator`

source-code/decorators/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Decorators
2+
==========
3+
4+
Python supports decorators, i.e., function wrapping to add functionality
5+
before and/or after the function's invocation. Python comes with a number
6+
of standard decorators, but it is easy to define one's own.
7+
8+
What is it?
9+
-----------
10+
1. `decorators.py`: two decorators are defined to check a wrapped
11+
function's arguments. The first, `check_min` throws an exception
12+
when the argument is negative, the second, `check_max`, throws another
13+
exception when the function is called with an argument that is too
14+
large. The decorated function in this example is the factorial.
15+
Also it illustrates `functools` wrap decorator to retain the wrapped
16+
function's name, docstring, etc.
17+
1. `memoize.py`: an example of adding a cache to a function using a simple
18+
custom decorator, as well as `functools`'s `lru_cache` decorator.

source-code/decorators/decorator.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/usr/bin/env python
2+
3+
from functools import wraps
4+
5+
6+
class NegArgError(Exception):
7+
def __init__(self, name, n):
8+
super(NegArgError, self).__init__()
9+
self.message = 'argument {0} for {1} negative'.format(n, name)
10+
11+
12+
class TooLargeArgError(Exception):
13+
def __init__(self, name, n):
14+
super(TooLargeArgError, self).__init__()
15+
self.message = 'argument {0} for {1} too large'.format(n, name)
16+
17+
18+
def check_min(f):
19+
@wraps(f)
20+
def wrapped(n):
21+
if n < 0:
22+
raise NegArgError(f.__name__, n)
23+
return f(n)
24+
return wrapped
25+
26+
27+
def check_max(f):
28+
@wraps(f)
29+
def wrapped(n):
30+
if n > 12:
31+
raise TooLargeArgError(f.__name__, n)
32+
return f(n)
33+
return wrapped
34+
35+
36+
@check_max
37+
@check_min
38+
def fact(n):
39+
'''compute factorial of given number'''
40+
if n == 0:
41+
return 1
42+
else:
43+
return n*fact(n - 1)
44+
45+
if __name__ == '__main__':
46+
import sys
47+
for n in [3, 7, 22, -1]:
48+
try:
49+
print('{0}! = {1}'.format(n, fact(n)))
50+
except Exception as error:
51+
sys.stderr.write('### error: {0}\n'.format(error))
52+
print('function name: {0}'.format(fact.__name__))
53+
print('function docs: {0}'.format(fact.__doc__))

source-code/decorators/memoize.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env python
2+
3+
from functools import lru_cache
4+
5+
6+
def memoize(f):
7+
cache = {}
8+
9+
def wrapper(n):
10+
if n not in cache:
11+
cache[n] = f(n)
12+
return cache[n]
13+
wrapper.__name__ = f.__name__
14+
return wrapper
15+
16+
17+
@memoize
18+
def fib_memoized(n):
19+
if n < 2:
20+
return 1
21+
else:
22+
return fib_memoized(n - 1) + fib_memoized(n - 2)
23+
24+
25+
@lru_cache(100)
26+
def fib_lru_cache(n):
27+
if n < 2:
28+
return 1
29+
else:
30+
return fib_lru_cache(n - 1) + fib_lru_cache(n - 2)
31+
32+
33+
def fib(n):
34+
if n < 2:
35+
return 1
36+
else:
37+
return fib(n - 1) + fib(n - 2)
38+
39+
40+
def execute(func, n_max):
41+
values = []
42+
start = datetime.now()
43+
for n in range(n_max):
44+
values.append(func(n))
45+
delta = datetime.now() - start
46+
for n in range(n_max):
47+
print('{0}({1}) = {2}'.format(func.__name__, n, values[n]))
48+
delta_time = float(delta.seconds) + 1.0e-6*float(delta.microseconds)
49+
print('{0}: {1:.6f} s'.format(func.__name__, delta_time))
50+
return delta_time
51+
52+
if __name__ == '__main__':
53+
from argparse import ArgumentParser
54+
from datetime import datetime
55+
56+
arg_parser = ArgumentParser(description='compare memoized versus '
57+
'non-memooized')
58+
arg_parser.add_argument('n_max', type=int, help='maximum n value')
59+
options = arg_parser.parse_args()
60+
delta_fib = execute(fib, options.n_max)
61+
delta_fib_memoized = execute(fib_memoized, options.n_max)
62+
delta_fib_lru_cache = execute(fib_lru_cache, options.n_max)
63+
print('non-memoized:\t\t{0:.6f} s'.format(delta_fib))
64+
print('memoized:\t\t{0:.6f} s'.format(delta_fib_memoized))
65+
print('lru_cache:\t\t{0:.6f} s'.format(delta_fib_lru_cache))

source-code/descriptors/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Descriptors
2+
===========
3+
4+
Python supports descriptors, i.e., the generic object class supports the
5+
`__get__`, `__set__`, and `__delete__` methods that allow to implement
6+
accessor methods.
7+
8+
What is it?
9+
-----------
10+
`typed_property.py`: implements typed properties
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env python
2+
3+
4+
class TypedProperty(object):
5+
6+
def __init__(self, name, type, default=None):
7+
self._name = '-' + name
8+
self._type = type
9+
self._default = default if default else type()
10+
11+
def __get__(self, instance, cls):
12+
return getattr(instance, self._name, self._default)
13+
14+
def __set__(self, instance, value):
15+
if not isinstance(value, self._type):
16+
raise TypeError('value {0} is not of {1}'.format(value,
17+
self._type))
18+
setattr(instance, self._name, value)
19+
20+
def __delete__(self, instance, cls):
21+
raise AttributeError('can not delete attribute')
22+
23+
24+
class Book(object):
25+
26+
title = TypedProperty('title', str)
27+
author = TypedProperty('author', str)
28+
year = TypedProperty('year', int)
29+
30+
def __init__(self, title=None, author=None, year=None):
31+
if title:
32+
self.title = title
33+
if author:
34+
self.author = author
35+
if year:
36+
self.year = year
37+
38+
def __str__(self):
39+
return '{0}\n {1}, {2}'.format(self.title, self.author, self.year)
40+
41+
42+
if __name__ == '__main__':
43+
import sys
44+
45+
book1 = Book()
46+
print('showing defaults:')
47+
print(str(book1) + '\n')
48+
book1.title = 'Animal farm'
49+
book1.author = 'George Orwell'
50+
book1.year = 1945
51+
print(str(book1) + '\n')
52+
book2 = Book('Alice in Wonderland', 'Lewis Carroll', 1865)
53+
print(str(book2) + '\n')
54+
try:
55+
book3 = Book(1984, 'George Orwell', 1948)
56+
except TypeError as error:
57+
sys.stderr.write('### error: {0}\n'.format(error))
58+
sys.exit(1)
59+
sys.exit(0)

source-code/introspection/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Introspection
2+
Illustration of implementing `__getattr__` and `__setattr__` in a mix-in
3+
class to provide introspection into parameters in derived classes.
4+
5+
## What is it?
6+
1. `parameterized.py`: Python module implementing a class representing
7+
parameters, a mix-in class adding parameter introspection capabilities
8+
to a derived class, and exception classes.
9+
1. `parameter_introspection.ipynb`: Jupyter notebook illustrating the use
10+
of the `Parameterized` mix-in class.
11+

0 commit comments

Comments
 (0)