forked from gjbex/Python-software-engineering
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
971 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
Decorators | ||
========== | ||
|
||
Python supports decorators, i.e., function wrapping to add functionality | ||
before and/or after the function's invocation. Python comes with a number | ||
of standard decorators, but it is easy to define one's own. | ||
|
||
What is it? | ||
----------- | ||
1. `decorators.py`: two decorators are defined to check a wrapped | ||
function's arguments. The first, `check_min` throws an exception | ||
when the argument is negative, the second, `check_max`, throws another | ||
exception when the function is called with an argument that is too | ||
large. The decorated function in this example is the factorial. | ||
Also it illustrates `functools` wrap decorator to retain the wrapped | ||
function's name, docstring, etc. | ||
1. `memoize.py`: an example of adding a cache to a function using a simple | ||
custom decorator, as well as `functools`'s `lru_cache` decorator. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#!/usr/bin/env python | ||
|
||
from functools import wraps | ||
|
||
|
||
class NegArgError(Exception): | ||
def __init__(self, name, n): | ||
super(NegArgError, self).__init__() | ||
self.message = 'argument {0} for {1} negative'.format(n, name) | ||
|
||
|
||
class TooLargeArgError(Exception): | ||
def __init__(self, name, n): | ||
super(TooLargeArgError, self).__init__() | ||
self.message = 'argument {0} for {1} too large'.format(n, name) | ||
|
||
|
||
def check_min(f): | ||
@wraps(f) | ||
def wrapped(n): | ||
if n < 0: | ||
raise NegArgError(f.__name__, n) | ||
return f(n) | ||
return wrapped | ||
|
||
|
||
def check_max(f): | ||
@wraps(f) | ||
def wrapped(n): | ||
if n > 12: | ||
raise TooLargeArgError(f.__name__, n) | ||
return f(n) | ||
return wrapped | ||
|
||
|
||
@check_max | ||
@check_min | ||
def fact(n): | ||
'''compute factorial of given number''' | ||
if n == 0: | ||
return 1 | ||
else: | ||
return n*fact(n - 1) | ||
|
||
if __name__ == '__main__': | ||
import sys | ||
for n in [3, 7, 22, -1]: | ||
try: | ||
print('{0}! = {1}'.format(n, fact(n))) | ||
except Exception as error: | ||
sys.stderr.write('### error: {0}\n'.format(error)) | ||
print('function name: {0}'.format(fact.__name__)) | ||
print('function docs: {0}'.format(fact.__doc__)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
#!/usr/bin/env python | ||
|
||
from functools import lru_cache | ||
|
||
|
||
def memoize(f): | ||
cache = {} | ||
|
||
def wrapper(n): | ||
if n not in cache: | ||
cache[n] = f(n) | ||
return cache[n] | ||
wrapper.__name__ = f.__name__ | ||
return wrapper | ||
|
||
|
||
@memoize | ||
def fib_memoized(n): | ||
if n < 2: | ||
return 1 | ||
else: | ||
return fib_memoized(n - 1) + fib_memoized(n - 2) | ||
|
||
|
||
@lru_cache(100) | ||
def fib_lru_cache(n): | ||
if n < 2: | ||
return 1 | ||
else: | ||
return fib_lru_cache(n - 1) + fib_lru_cache(n - 2) | ||
|
||
|
||
def fib(n): | ||
if n < 2: | ||
return 1 | ||
else: | ||
return fib(n - 1) + fib(n - 2) | ||
|
||
|
||
def execute(func, n_max): | ||
values = [] | ||
start = datetime.now() | ||
for n in range(n_max): | ||
values.append(func(n)) | ||
delta = datetime.now() - start | ||
for n in range(n_max): | ||
print('{0}({1}) = {2}'.format(func.__name__, n, values[n])) | ||
delta_time = float(delta.seconds) + 1.0e-6*float(delta.microseconds) | ||
print('{0}: {1:.6f} s'.format(func.__name__, delta_time)) | ||
return delta_time | ||
|
||
if __name__ == '__main__': | ||
from argparse import ArgumentParser | ||
from datetime import datetime | ||
|
||
arg_parser = ArgumentParser(description='compare memoized versus ' | ||
'non-memooized') | ||
arg_parser.add_argument('n_max', type=int, help='maximum n value') | ||
options = arg_parser.parse_args() | ||
delta_fib = execute(fib, options.n_max) | ||
delta_fib_memoized = execute(fib_memoized, options.n_max) | ||
delta_fib_lru_cache = execute(fib_lru_cache, options.n_max) | ||
print('non-memoized:\t\t{0:.6f} s'.format(delta_fib)) | ||
print('memoized:\t\t{0:.6f} s'.format(delta_fib_memoized)) | ||
print('lru_cache:\t\t{0:.6f} s'.format(delta_fib_lru_cache)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
Descriptors | ||
=========== | ||
|
||
Python supports descriptors, i.e., the generic object class supports the | ||
`__get__`, `__set__`, and `__delete__` methods that allow to implement | ||
accessor methods. | ||
|
||
What is it? | ||
----------- | ||
`typed_property.py`: implements typed properties |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
#!/usr/bin/env python | ||
|
||
|
||
class TypedProperty(object): | ||
|
||
def __init__(self, name, type, default=None): | ||
self._name = '-' + name | ||
self._type = type | ||
self._default = default if default else type() | ||
|
||
def __get__(self, instance, cls): | ||
return getattr(instance, self._name, self._default) | ||
|
||
def __set__(self, instance, value): | ||
if not isinstance(value, self._type): | ||
raise TypeError('value {0} is not of {1}'.format(value, | ||
self._type)) | ||
setattr(instance, self._name, value) | ||
|
||
def __delete__(self, instance, cls): | ||
raise AttributeError('can not delete attribute') | ||
|
||
|
||
class Book(object): | ||
|
||
title = TypedProperty('title', str) | ||
author = TypedProperty('author', str) | ||
year = TypedProperty('year', int) | ||
|
||
def __init__(self, title=None, author=None, year=None): | ||
if title: | ||
self.title = title | ||
if author: | ||
self.author = author | ||
if year: | ||
self.year = year | ||
|
||
def __str__(self): | ||
return '{0}\n {1}, {2}'.format(self.title, self.author, self.year) | ||
|
||
|
||
if __name__ == '__main__': | ||
import sys | ||
|
||
book1 = Book() | ||
print('showing defaults:') | ||
print(str(book1) + '\n') | ||
book1.title = 'Animal farm' | ||
book1.author = 'George Orwell' | ||
book1.year = 1945 | ||
print(str(book1) + '\n') | ||
book2 = Book('Alice in Wonderland', 'Lewis Carroll', 1865) | ||
print(str(book2) + '\n') | ||
try: | ||
book3 = Book(1984, 'George Orwell', 1948) | ||
except TypeError as error: | ||
sys.stderr.write('### error: {0}\n'.format(error)) | ||
sys.exit(1) | ||
sys.exit(0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Introspection | ||
Illustration of implementing `__getattr__` and `__setattr__` in a mix-in | ||
class to provide introspection into parameters in derived classes. | ||
|
||
## What is it? | ||
1. `parameterized.py`: Python module implementing a class representing | ||
parameters, a mix-in class adding parameter introspection capabilities | ||
to a derived class, and exception classes. | ||
1. `parameter_introspection.ipynb`: Jupyter notebook illustrating the use | ||
of the `Parameterized` mix-in class. | ||
|
Oops, something went wrong.