Python in Practice Flashcards
Abstract Factory Pattern
Diagram with Svg and Text
Designed for situations where we want to create complex objects that are composed of other objects and where the composed objects are all of one particular “family.”
some gui:
has abstact widget factory with three subclass factories.
- MacWidgetFactory
- XfceWidgetFactory
- WindowsWidgetFactory
provide methods for creating the same objects:
- make_button()
- make_spinbox(), etc…
we can create a generic create_dialog() function that takes a factory instance as an argument and produces a dialog with OS X, Xfce, or windows dialog.
“Abstract” usually means the base class also serves as a concrete class in its own right, with other classes inheriting from it.
This abstract class will often contain methods which call subclasses specific to each class that inherits it. make_button() above will call subclasses for windows, Xfce, and Mac OS.
steps:
- One top level function calls a factories
- Abstract factory has class methods that call inner classes (Diagram, Rectangle, Text).
- More complex factory inherits simple one. Methods on abstract class call inner classes and reference private constants, which do all the work.
Builder Pattern
HTML and Tkinter forms
Similar to Abstract Factory in that both patterns are designed to create complex objects composed of other objects
Builder is distinct in that it not only contains methods for building the object, it also holds the representation of the entire complex object itself.
top level calls use the same function, parameterized by appropriate builder object.
>>> tkForm = create_login(TkFormBuilder())
>>> htmlForm = create_login(HtmlFormBuilder())
Both inherit from an abstract base class, AbstractForm - has a bunch of abstract methods
class AbstractForm(metaclass=abc.ABCMeta):
__@abc.abstractmethod
__def form(self):
____pass
any class inheriting this must implement all the abstract methods.
giving a class metaclass=abc.ABCMeta means the class cannot be instantiated. Sets “__abstractmethod__” attribute to true, returns original function
Factory Method Pattern
gameboard
when we want subclasses to choose which subclass they should instantiate when an object is requested.
Good for lots of things, but also for when we can’t know the class in advance.
def make_new_method(char):
__def new(Class): # Can’t use super() or super(Piece, Class) b/c there is no instance/class context for super to access.
____return Piece.__new__(Class, char)
__return new
for code in itertools.chain((code1, code2), codes):
__char = chr(code)
__name = unicodedata.name(char).title().replace(“ “, “”)
__new = make_new_method(char)
__Class = type(name, (bases, ), dict(__slots__=(), __new__=new))
__setattr(sys.modules[__name__], name, Class)
or
example of nesting lambdas
what for?
new = (lambda char: lambda Class: Piece.__new__(Class, char))(char)
name is always ‘lambda’ - not good
new.__name__ = ‘__new__’
within the loop, char has meaning, but Class is a placeholder for when “__new__” is called on the class. We’ll create a new Piece class whos name is the name of the unicode character and who’s value is the characters representation. (game piece)
In the gameboard example, this allowed the dynamic creation of a function in a loop going through values to create classes for game pieces.
“new” was put in the __new__ slot of an attribute dict and called with the name and bases on “type”, then assigned to the global namespace.
Class = type(name, (Piece,), dict(__slots__=(), __new__=new))
globals()[name] = Class
Prototype Pattern:
7 ways to make a class instance
even when names are only known at runtime, Python provides a variety of ways of creating new objects.
class Point:
__ __slots__ = (“x”, “y”)
__def __init__(self, x, y):
____self.x = x
____self.y = y
def make_object(Class, *args, **kwargs):
__return Class(*args, **kwargs)
point1 = Point(1, 2)
point2 = eval(“{}({}, {})”.format(“Point”, 2, 4) #risky
point3 = getattr(sys.modules[__name__], “Point”)(3, 6)
point4 = globals()“Point”
point5 = make_object(Point, 5, 10)
point6 = copy.deepcopy(point5)
point6. x = 6
point6. y = 12
point7 = point1.__class__(7, 14) # any previous instance would work here.
Singleton Pattern
used when the class has only a single instance that is the one and only needed throughout the program.
create a module with the global state that’s needed kept in private variables and access provided by public functions:
ex.
_URL = “http://www.bankofcanada.ca/stats/assets/csv/fx-seven-day.csv”
def get(refresh=False):
__if refresh:
____get.rates = {}
__if get.rates:
____return get.rates
__with urllib.request.urlopen(_URL) as file:
____for line in file:
______line = line.rstrip().decode(“utf-8”)
______if not line or line.startswith((“#”, “Date”)):
________continue
______name, currency, *rest = re.split(r’\s*, \s*’, line)
______key = “{}({})”.format(name, currency)
______try:
________get.rates[key] = float(rest[-1])
______except ValueError as err:
________print(“error {}: {}”.format(err, line)
__return get.rates
###
This is in the currency/Rates.py module. the rates dictionary is an attribute of of the Rates get() function - a private value. When the public get() function is called, the get function either returns the rates or fetches them anew. No class needed.
Structural Design Patterns
in Python
Primary goal of structural design patterns is how objecst are composed together to form new, larger objects. Three themes stand out in structural design patterns:
adapting interfaces, adding functionality and handling collections of objects.
- Adapter pattern
- Bridge pattern
- Composite pattern
- Decorator pattern
- Facade pattern
- Flyweight pattern
- Proxy pattern
Just remember “A B C D F F P”!
Adapter pattern:
or “How to Duck Type”
Text and HTML rendering with a “Renderer” protocol
Technique for adapting an interface so one class can use another class (with an incompatible interface) without changing either of the classes being used.
a class need not know or care what the class of one of its arguments is, only that the given class provides the proper interface.
The page example: page class takes a “renderer” object that needs to inherit from class Renderer ( if not isinstance(renderer, Renderer)), which will mean it has the header, paragraph and footer methods. That’s all.
Duck typing solution (without requiring inheritance):
class Renderer(metaclass=abc.ABCMeta):
__@classmethod
__def __subclasshook__(Class, Subclass):
____if Class is Renderer:
______attributes = collections.ChainMap(*(Superclass.__dict__ for Superclass in Subclass.__mro__))
______methods = (“header”, “paragraph”, “footer”)
______if all(method in attributes for method in methods):
________return True
____return NotImplemented
**Explanation: **
isinstance(instance, Class) calls __subclasshook__ to see if the object given is a subclass of the second argument. So:
isinstance(renderer, Renderer) looks in Renderer for __subclasshook__, and determines if the stuff in the mro of the given renderer satisfies the criteria. The renderer need not actually subclass Renderer.
Qtrac.py has a has_methods(*methods) decorator that does this.
Likewise, you can inherit from Qtrac.requirer, an abstract base class
Bridge Pattern
create class for drawing barcharts, but use other classes for actual rendering of the barcharts
Separates an abstraction (an interface or algorithm) from how it is implemented.
Conventionally, we’d create one or more abstract base classes and subclass them several times for our concrete implementations.
Bridges create independent class hierarchies:
- Abstract: defines the operations (interface and algorithms)
- Concrete: provides implementations that will be called
Abstract class aggregates an instance of one of the concrete implementation classes - this instance serves as a bridge between the abstract interface and the concrete operations.
From the book, HtmlRenderer (has the header, paragraph and footer methods) could be said to have used the bridge pattern, it aggregated an HtmlWriter (which was more complex than TextRenderer, requiring this class) to provide its rendering
class BarRenderer(Qtrack.Requirer):
__required_methods={“initialize”, “draw”, …}
class BarCharter:
__def __init__(self, renderer):
____if not isinstance(renderer, BarRenderer):
…..
__def render(self, caption, pairs): # only method
….
class TextBarRenderer:
__def __init__(self, scaleFactor=40):
____self.scaleFactor = scaleFactor
** define above required functions
class ImageBarRenderer:
__COLORS = # defines colors
** __init__ specific to needs w/ above rendering methods defined.
Bridge Pattern Example
define a class that checks if the concrete class passed to it has the appropriate methods.
this is done with:
if not isinstance(concrete, Abstract) …
the @Qtrac.has_methods works well to define the Abstract Base Class
@Qtrac.has_methods(‘method1’, ‘method2’)
class AbstractClass(metaclass=abc.ABCMeta): pass
###
Your concrete classes (the bridge between the abstract base class and the implementer) now need to implement methods 1 and 2, but they’ll be called when passing the class to the bridge class - for example, in the bridge classes’ “render” method, it calls the initialize, draw_caption, draw_bar, and finalize methods of the TextBarRenderer and ImageBarRenderer classes - each of which are very different.
class BarCharter: # the implementer
class BarRenderer(Qtrac.Requirer): # abstract
__required_methods = …
class TextBarRenderer: # bridge 1
class ImageBarRenderer: # bridge 2
Qtrac.has_methods
class decorator
because it’s cool
def has_methods(*methods):
__def decorator(Base):
____def __subclasshook__(Class, Subclass):
______if Class is Base:
________attributes = collections.ChainMap(*(Superclass.__dict__ for Superclass in Subclass.__mro__))
________if all(method in attributes for method in methods):
__________return True
______return NotImplemented
____Base.__subclasshook__ = classmethod(__subclasshook__)
____return Base
__return decorator
Composite Pattern
describe general idea and example used in book
Designed to support the uniform treatment of objects in a hierarchy, whether they contain other objects or not.
Composite and noncomposite objects normally have the same core methods, with composite objects having additional methods to support adding, removing, and iterating their children.
Often used in drawing programs like Inkscape to support grouping or ungrouping.
book used Stationary as an example:
- each item had a name and a price.
- items can be grouped in sets, the price of which is the sum of the contents prices.
- These can be nested without limit.
Classic Composite/Noncomposite Hierarchy
Stationary example, 2 Abstract classes
composite is abstract, subclasses must implement
Abstract Item base class:
class AbstractItem(metaclass=abc.ABCMeta):
__@abc.abstractproperty
__def composite(self):
____pass
__def __iter__(self):
____return iter([])
class SimpleItem(AbstractItem):
__def __init__(self, name, price = 0.00):
____self.name = name
____self.price = price
__@property
__def composite(self):
____return False
class AbstractCompositeItem(AbstractItem):
__def __init__(self, *items):
____self.children = []
____if items:
______self.add(*items)
there is plenty more, check out stationary 1
Basic idea:
Noncomposite base abstract class is used for items, Abstract Composite Class inherits from it and adds some methods for dealing with items.
Composite items must declare @properties to handle the methods from both bases. (AbstractItem and AbstractCompositeItem)
Single Class for Composites
and Non-composites
no abstract class, bunch of classmethods and properties
decorate a couple class methods
create an Item class that can be either noncomposite or composite.
class Item:
def \_\_init\_\_(self, name, \*items, price=0.00): self.name = name self.price = price self.children = [] if items: self.add(\*items)
@classmethod
def create(Class, name, price):
__return Item(name, price=price)
@classmethod
def compose(Class, name, *items):
__return Item(name, *items)
@property
def composite(self):
__return bool(self.children) # True if exists.
@property
def price(self):
__return (sum(item.price for item in self) if self.children else self.__price
@price.setter #using a setter function
def price(self, price):
__self.__price = price
there’s more. Check the code.
Decorator Pattern
Decorators accept a function and return a function of the same name but with enhanced functionality.
classes, methods and functions can be decorated.
@functools.total_ordering:
class decorator that can be used on a class which implements __eq__() and __lt__() so it will have the full suite of comparison operators.
Class Decorators
ensuring values of attributes
one decorator, several attribute validations
this requires stacking loads of decorators on top of one another. not optimal.
def ensure(name, validate, doc=None):
__def decorator(Class):
____privateName = “__” + name
____def getter(self):
______return getattr(self, privateName)
____def setter(self, value):
______validate(name, value)
______setattr(self, privateName, value)
____setattr(Class, name, property(getter, setter, doc=doc))
____return Class
__return decorator
property(getter, setter, deleter, doc)
@ensure(“title”, is_valid_title)
@ensure(“isbn”, is_valid_isbn)
class Book:
__def __init__(self, title, isbn):
____self.title = title
____self.isbn = isbn
__#book now has title and isbn property validators, so they’ll both be checked upon assignment and when changed
Using a class decorator to add properties
one class handles attributes within class
decorator function accepts class and searches for attributes within class of a certain class.
@do_ensure
class Book:
__title = Ensure( is_non_empty_str)
__isbn = Ensure(is_valid_isbn)
__price = Ensure(is_in_range(1, 100000)
….
__def __init__(self, title, isbn, price,..)
etc.
class Ensure:
__def __init__(self, validate, doc=None):
____self.validate = validate
____self.doc = doc
def do_ensure(Class):
__def make_property(name, attribute):
____privateName = “__” + name
____def getter(self):
______return getattr(self, privateName)
____def setter(self):
______attribute.validate(name, value)
______setattr(self, privateName, value)
____return property(getter, setter, doc=attribute.doc)
__for name, attribute in Class.__dict__.items():
____if isinstance(attribute, Ensure):
______setattr(Class, name, make_property(name, attribute))
__return Class
Using a class decorator instead of subclassing
describe 4 classes:
Mediator, Mediated, Button, Text
change Mediated to decorator
- Mediator takes a tuple of widget-callable pairs. When a thing happens to a widget, the callable calls with the widget as an argument. The widget’s mediator is set to be this class - a dictionary of key=widget, val=callable
- Mediated is a class that sets itself with no mediator and an on_change function that calls its own mediator’s on_change function (if it has a mediator)
- Button and Text inherit from Mediated. When we click the button or change the text (via @text.setter), the inherited on_change method fires.
- on_change() just calls it’s mediator’s (Mediator) on_change() function, which looks up what to do in it’s dictionary.
mediator1.py and mediator1d.py
mediated as decorator:
def mediated(Class):
__setattr(Class, “mediator”, None)
__def on_change(self):
____if self.mediator is not None:
______self.mediator.on_change(self)
__setattr(Class, “on_change”, on_change)
__return Class
@mediated
class Button:
same code
Facade Pattern
pretty simple concept
Creates simplified interfaces on top of low level commands. Ideally the lower level interface will still be accessible, but we use the facade most of the time.
The example was a lengthy archive handler that dealt with .tar.gz, .tar.bz2, .tar.xc, and .zip files. It had a context manager:
def __enter__(self):
__return self
def __exit__(self, exc_type, exc_value, traceback):
__self.close()
and logic that forked flow according to the file extension, returning name methods (getnames for tar, namelist for zip), and appropriate file objects.
Similar to an adapter pattern in that they both provide simple interfaces, but a facade specifically masks a complicated interface, whereas the adapter is designed to create a unified interface on top of (not necessarily complicated) interfaces.
Flyweight pattern
making points
shelve module
Designed to handle large numbers of relatively small objects.
Each unique object is represented once and shared wherever needed.
A dictionary is a simple implementation of the pattern
With a large number of (not necessarily small) objects, reducing the memory footprint can be achieved with __slots__.
class Point:
__ __slots__ = (‘x’, ‘y’, ‘z’, ‘color’)
__def __init__(self, x=0, y=0, z=0, color=None):
____self.x = x
etc…
because of __slots__, no point has its own private dict (self.__dict__). No arbitrary attributes can be added to Point.
using a static __dbm (class-level) variable and shelve is much more memory efficient, but takes longer. Learn later.
class Point:
__ __slots__ = (‘x’, ‘y’, ‘z’, ‘color’)
__ __dbm = shelve.open(os.path.join(“tmp”, “point.db”)
__def __init__(self, x=0, y=0, z=0, color=None):
____self.x = x
__def __key(self, name):
____return “:{}”.format(id(self), name)
__def __getattr__(self, name):
____return Point.__dbm[self.__key(name)]
__def __setattr__(self, name, value):
____Point.__dbm[self.__key(name)] = value
__atexit.register(__dbm.close) # uses atexit module
Proxy Pattern
four examples with image processing
R, S, V, P
Used when we want one object to stand in for another.
- Remote proxy where a local object proxies a remote object (RPyC library)
- Smart reference that performs “additional actions when an object is accessed”.
- Virtual proxy that allows creation of lightweight objects instead of heavyweight, creating the latter if needed
- Protection proxy that provides different levels of access based on client access rights
Same coding approach can be used for all, but “Smart Reference” can be done with a @property decorator.
Also good for unit testing - ie. accessing resources that might not be available, or accessing incomplete class. Python 3 includes the unittest.mock library for creating mock objects and adding stubs in place of missing methods.
imageproxy1.py and imageproxy2.py
The Imageproxy class takes an Image.Image object with a specific interface and does not do the expensive rendering until it is saved or you ask it questions about the image (what’s the size, etc.)
commands are appended to self.commands in tuples of (function_name, *args)
so when it is time to execute, loop through self.commands like this:
for command in self.commands:
__command = self.commands.pop(0)
__func, *args = command
__image = func(*args)
__for command in self.commands:
____func, *args = command
____func(image, args)
__image.save(filename)
__return image
Chain of Responsibility Pattern
or
Decouples sender of request from the recipient that processes the request.
Each handler has a successor, all the way to Null handler. (Wrap all in debug handler if needed)
handler1 = TimerHandler(KeyHandler(MouseHandler(NullHandler())))
while True:
__event = Event.next()
__if event.kind == Event.TERMINATE
____break
__pipeline.send(event)
__handler1.handle(event)
class MouseHandler(NullHandler):
__def handle(self, event):
____if event.kind == Event.MOUSE:
______print(“Click: {}”.format(event))
____else:
______super().handle(event)
super() calls NullHandler’s handle method, which is the current handler’s argument (the successor), if the event matches, the handler does it’s thing.
coroutine decorator
def coroutine(function):
__@functools.wraps(function)
__def wrapper(*args, **kwargs):
____generator = function(*args, **kwargs)
____next(generator)
____return generator
__return wrapper
####
@coroutine
def key_handler(successor=None):
__while True:
____event = (yield)
____if event.kind == Event.KEYPRESS:
______print(“press: {}”.format(event))
____elif successor is not None:
______successor.send(event) ## dunno where send comes from
Name 11 Behavioral Patterns
- Chain of Responsibility - decouples sender of a request from the recipient
- Command - encapsulate commands as objects - handy for making things undoable
- Interpreter - formalizes two common requirements - means by which users enter non strings and program applications
- **Iterator **- sequentially acess items inside a collection without exposing any of the internals or the aggregate’s implementation
- Mediator - Provides means of creating an object - the mediator - that can encapsulate the interactions between other objects.
- Memento - Means of saving and restoring an object’s state without violating encapsulation.
- Observer - Supports many-to-many dependency relationships between objects. When one object changes state, all related objects are notified.
- State - Intended to provide objects whose behavior changes when their state changes - objects that have modes.
- Strategy - Provides means of encapsulating a set of algorithms that can be used interchangeably, depending on the user’s needs.
- Template - Allows us to define the steps of an algorithm but defer the execution of those steps to subclasses
-
Visitor - Apply a function to every item in a collection or aggregate object. Different from the iterator only in perspective - we are applying an external function on each item.
12.
Command Pattern
like storing commands in ImageProxy example
storing sequence of commands works the similarly
create classes for undoable individual commands and for undoable macros. The basic idea is to store commands to be executed in succession at a later time, store the output at a given stage, reset it later if you want. Since callables are first class objects that can be passed around in lists or dicts, Python is a great language for this pattern.
- Command.Command - takes do and undo callables and an optional description
- Command.Macro - takes optional description and any number of Command.Command objects added
import Command ## Python in Practice module
def create_cell_command(self, x, y, color):
__def undo():
____self.cell(x, y, undo.color) # setter b/c color
__def do():
____undo.color = self.cell(x,y) # getter in closure
____self.cell(x, y, color) # setter b/c color
__return Command.Command(do, undo, “cell”)
Interpreter Pattern
How to allow the user to enter non string data and how to let them program applications. (?)
here python safely parses two strings:
try:
__count = int(userCount)
__when = datetime.datetime.strptime(userDate, “%Y/%m/%d”).date()
except ValueError as err:
__print(err)
But maybe allowing trusted users access to the interpreter themselves? Use PLY or PyParsing.
Beats writing a Domain Specific Language (DSL - which is apparently doable out of the box).
Essentially:
- program makes a prompt using “input()” and passes the output to a function that knows the global and local contexts and adds the current context to the local
- rather than give it the whole global() context, it makes a function called global_context() that returns a subset of it
- calculate - evaluates the expression and prints the local context
- update - changes the name of the variable passed to localContext next time round
Interpreter with exec() instead of eval()
exec() is not limited to a single expression and always returns None
context can be passed to exec() via locals and globals dicts.
genome1.py super simple
genome2.py and genome3.py
these are tricky, but revolve around using sys.Popen
def execute(code, context):
__module, offset = create_module(code.code, context)
__with subprocess.Popen([sys.executable, “-“], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as process:
____communicate(process, code, module, offset)
genome3.py returns its results in a pickle
this pattern cannot protect from executing unsafe code
Iterator Pattern
sequentially acess items inside a collection without exposing any of the internals or the aggregate’s implementation
three options:
- satisfy the sequence protocol
- two argument form of built-in iter()
- satisfy the iterator protocol
sequence
class AtoZ:
__def __getitem__(self, index):
____if 0 <= index < 26:
______return chr(index + ord(‘A’))
____raise IndexError()
for leter in iter(AtoZ()):….
two-arg iter():
for it in iter(callable, Sentinal_value):
__print(it)
print()
iter stops when callable returns a StopIteration or if it returns the sentinal value (eg. None)
iteration protocol:
define __iter__(self) using return or yield
uses a bag as an example. Python has a bag at collections.Counter
Mediator Pattern
Provides means of creating an object - the mediator - that can encapsulate the interactions between other objects.
achieve interactions between objects that have no direct knowledge of each other.
When a button is clicked, the button just tells the mediator, which tells anything else that might be interested.
The examples are getting long, but this is good. Look at mediator examples.
These only show one-to-one widget-function relationships, but many-to-many is possible.
Memento Pattern
Means of saving and restoring an object’s state without violating encapsulation.
pickle supports this out of the box. All python objects, (apart from file objects), can be pickled/unpickled.
when there is a limitation on pickle:
- __setstate__() and __getstate__()
- possibly __getnewargs__()
Unpickling involves executing arbitrary python code, so unpickling from untrusted sources is not an option. JSON is safer, or use checksums and encryption with pickling to ensure the pickle hasn’t been meddled with.
Observer Pattern
Slider with History and LiveView observers
Supports many-to-many dependency relationships between objects. When one object changes state, all related objects are notified.
MVC paradigm is most common.
Controllers mediate between the input and model. When the model changes, the associated views change.
In the example, a model representing a slider inherits from an Observed class. The observed base class can add observers, remove them, and notify them. The notify method calls “update” on any of the slider’s observers (triggered by property setter methods). One observer just keeps track of the history while another prints out some HTML based on the slider’s value.
Observer pattern is widely used in GUI programming, also other event-processing architectures.
- database triggers
- Django’s signaling system
- QT GUI app framework’s signals
- many uses of WebSockets
State Pattern
multiplexer example
Intended to provide objects whose behavior changes when their state changes - objects that have modes.
multiplexer example - two states.
when active, accepts connections - event name, callback pairs
for event_name, callback in ((“name”, func)):
__multiplexer.connect(event_name, callback)
__multiplexer.connect(event_name, gen_callback)
for multiplexer object we can use state-specific methods.
@state.setter
def state(self, state):
__if state == Multiplexer.ACTIVE:
____self.connect = # private methods
…more assignments
__else:
____self.connect = lambda *args: None #for each method you want to cancel.
Strategy Pattern
Provides means of encapsulating a set of algorithms that can be used interchangeably, depending on the user’s needs.
class accepts an algorithm and calls that algorithm’s methods. The interchangeable algorithms will have methods with the same name or will become the original class’s method.
class Layout:
__def __init__(self, tabulator):
____self.tabulate = tabulator
tab = Layout(HtmlTab)
tab.tabulate(##things HtmlTab needs to have)
Template Pattern
Allows us to define the steps of an algorithm but defer the execution of those steps to subclasses
A lot like the Bridge structural pattern
Example:
Make an AbstractWordCounter with two static methods - can_count(filename) and count(filename). Subclasses are made for text and html documents.
so we can do this:
def count_words(filename):
__for wordCounter in (TextCounter, HtmlCounter):
____if wordCounter.can_count(filename):
______return wordCounter.count(filename)
Visitor Pattern
Apply a function to every item in a collection or aggregate object. Different from the iterator only in perspective - we are applying an external function on each item. This is done with map.
- Patterns to use with coroutines
- Pattern for lazy evaluation
- Patterns with no direct support in Python
- Chain of responsibility, Mediator, Observer
- Command
- State, Strategy, Template