Skip to content

Commit

Permalink
Add more code samples
Browse files Browse the repository at this point in the history
  • Loading branch information
gjbex committed Dec 6, 2019
1 parent b3e8fe7 commit 7a49b49
Show file tree
Hide file tree
Showing 9 changed files with 971 additions and 0 deletions.
4 changes: 4 additions & 0 deletions source-code/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ was used to develop it.

1. `context-manager`: illustrates how to write your own context managers.
1. `coroutines`: illustrates how to write coroutines in Python.
1. `decorators`: illustrates how to write decorators in Python.
1. `descriptors`: illustrates how to write descriptors in Python.
1. `design-patterns`: illustrates some common design patterns in Python.
1. `functional-programming`: illustrates some concepts of functional
programming in Python.
1. `introspection`: illustration of how to implement introspection in
Python.
1. `object-orientation`: illustrates some concepts of object-oriented
programming in Python.
1. `operators-functools`: illustrates some applications of the `operator`
Expand Down
18 changes: 18 additions & 0 deletions source-code/decorators/README.md
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.
53 changes: 53 additions & 0 deletions source-code/decorators/decorator.py
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__))
65 changes: 65 additions & 0 deletions source-code/decorators/memoize.py
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))
10 changes: 10 additions & 0 deletions source-code/descriptors/README.md
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
59 changes: 59 additions & 0 deletions source-code/descriptors/typed_property.py
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)
11 changes: 11 additions & 0 deletions source-code/introspection/README.md
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.

Loading

0 comments on commit 7a49b49

Please sign in to comment.