这两天在PythonTip刷题,突然看到这里提供了Python的设计模式demo,正是我多年来想找的东西。
于是乎,我就动用了我的爬爬爬爬爬虫把这些代码都爬下来了,放到简书,有时间就过来看看。25种设计模式,还是挺多的。
borg
class Borg:
__shared_state = {}
def __init__(self):
self.__dict__ = self.__shared_state
def __str__(self):
return self.state
class YourBorg(Borg):
pass
if __name__ == '__main__':
rm1 = Borg()
rm2 = Borg()
rm1.state = 'Idle'
rm2.state = 'Running'
print('rm1:', rm1)
print('rm2:', rm2)
rm2.state = 'Zombie'
print('rm1:', rm1)
print('rm2:', rm2)
print('rm1 id:', id(rm1))
print('rm2 id:', id(rm2))
rm3 = YourBorg()
print('rm1:', rm1)
print('rm2:', rm2)
print('rm3:', rm3)
facade
"""http://dpip.testingperspective.com/?p=26"""
import time
SLEEP = 0.5
# Complex Parts
class TC1:
def run(self):
print("###### In Test 1 ######")
time.sleep(SLEEP)
print("Setting up")
time.sleep(SLEEP)
print("Running test")
time.sleep(SLEEP)
print("Tearing down")
time.sleep(SLEEP)
print("Test Finished\n")
class TC2:
def run(self):
print("###### In Test 2 ######")
time.sleep(SLEEP)
print("Setting up")
time.sleep(SLEEP)
print("Running test")
time.sleep(SLEEP)
print("Tearing down")
time.sleep(SLEEP)
print("Test Finished\n")
class TC3:
def run(self):
print("###### In Test 3 ######")
time.sleep(SLEEP)
print("Setting up")
time.sleep(SLEEP)
print("Running test")
time.sleep(SLEEP)
print("Tearing down")
time.sleep(SLEEP)
print("Test Finished\n")
# Facade
class TestRunner:
def __init__(self):
self.tc1 = TC1()
self.tc2 = TC2()
self.tc3 = TC3()
self.tests = [i for i in (self.tc1, self.tc2, self.tc3)]
def runAll(self):
[i.run() for i in self.tests]
# Client
if __name__ == '__main__':
testrunner = TestRunner()
testrunner.runAll()
chain
# http://www.testingperspective.com/wiki/doku.php/collaboration/chetan/designpatternsinpython/chain-of-responsibilitypattern
class Handler:
def successor(self, successor):
self.successor = successor
class ConcreteHandler1(Handler):
def handle(self, request):
if request > 0 and request <= 10:
print("in handler1")
else:
self.successor.handle(request)
class ConcreteHandler2(Handler):
def handle(self, request):
if request > 10 and request <= 20:
print("in handler2")
else:
self.successor.handle(request)
class ConcreteHandler3(Handler):
def handle(self, request):
if request > 20 and request <= 30:
print("in handler3")
else:
print('end of chain, no handler for {}'.format(request))
class Client:
def __init__(self):
h1 = ConcreteHandler1()
h2 = ConcreteHandler2()
h3 = ConcreteHandler3()
h1.successor(h2)
h2.successor(h3)
requests = [2, 5, 14, 22, 18, 3, 35, 27, 20]
for request in requests:
h1.handle(request)
if __name__ == "__main__":
client = Client()
abstract_factory
# http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/
"""Implementation of the abstract factory pattern"""
import random
class PetShop:
"""A pet shop"""
def __init__(self, animal_factory=None):
"""pet_factory is our abstract factory.
We can set it at will."""
self.pet_factory = animal_factory
def show_pet(self):
"""Creates and shows a pet using the
abstract factory"""
pet = self.pet_factory.get_pet()
print("This is a lovely", pet)
print("It says", pet.speak())
print("It eats", self.pet_factory.get_food())
# Stuff that our factory makes
class Dog:
def speak(self):
return "woof"
def __str__(self):
return "Dog"
class Cat:
def speak(self):
return "meow"
def __str__(self):
return "Cat"
# Factory classes
class DogFactory:
def get_pet(self):
return Dog()
def get_food(self):
return "dog food"
class CatFactory:
def get_pet(self):
return Cat()
def get_food(self):
return "cat food"
# Create the proper family
def get_factory():
"""Let's be dynamic!"""
return random.choice([DogFactory, CatFactory])()
# Show pets with various factories
if __name__ == "__main__":
shop = PetShop()
for i in range(3):
shop.pet_factory = get_factory()
shop.show_pet()
print("=" * 20)
bridge
# http://en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Bridge_Pattern#Python
# ConcreteImplementor 1/2
class DrawingAPI1(object):
def draw_circle(self, x, y, radius):
print('API1.circle at {}:{} radius {}'.format(x, y, radius))
# ConcreteImplementor 2/2
class DrawingAPI2(object):
def draw_circle(self, x, y, radius):
print('API2.circle at {}:{} radius {}'.format(x, y, radius))
# Refined Abstraction
class CircleShape(object):
def __init__(self, x, y, radius, drawing_api):
self._x = x
self._y = y
self._radius = radius
self._drawing_api = drawing_api
# low-level i.e. Implementation specific
def draw(self):
self._drawing_api.draw_circle(self._x, self._y, self._radius)
# high-level i.e. Abstraction specific
def scale(self, pct):
self._radius *= pct
def main():
shapes = (
CircleShape(1, 2, 3, DrawingAPI1()),
CircleShape(5, 7, 11, DrawingAPI2())
)
for shape in shapes:
shape.scale(2.5)
shape.draw()
if __name__ == '__main__':
main()
memento
"""code.activestate.com/recipes/413838-memento-closure/"""
import copy
def Memento(obj, deep=False):
state = (copy.copy, copy.deepcopy)[bool(deep)](obj.__dict__)
def Restore():
obj.__dict__.clear()
obj.__dict__.update(state)
return Restore
class Transaction:
"""A transaction guard. This is really just
syntactic suggar arount a memento closure.
"""
deep = False
def __init__(self, *targets):
self.targets = targets
self.Commit()
def Commit(self):
self.states = [Memento(target, self.deep) for target in self.targets]
def Rollback(self):
for st in self.states:
st()
class transactional(object):
"""Adds transactional semantics to methods. Methods decorated with
@transactional will rollback to entry state upon exceptions.
"""
def __init__(self, method):
self.method = method
def __get__(self, obj, T):
def transaction(*args, **kwargs):
state = Memento(obj)
try:
return self.method(obj, *args, **kwargs)
except:
state()
raise
return transaction
class NumObj(object):
def __init__(self, value):
self.value = value
def __repr__(self):
return '<%s: %r>' % (self.__class__.__name__, self.value)
def Increment(self):
self.value += 1
@transactional
def DoStuff(self):
self.value = '1111' # <- invalid value
self.Increment() # <- will fail and rollback
if __name__ == '__main__':
n = NumObj(-1)
print(n)
t = Transaction(n)
try:
for i in range(3):
n.Increment()
print(n)
t.Commit()
print('-- commited')
for i in range(3):
n.Increment()
print(n)
n.value += 'x' # will fail
print(n)
except:
t.Rollback()
print('-- rolled back')
print(n)
print('-- now doing stuff ...')
try:
n.DoStuff()
except:
print('-> doing stuff failed!')
import traceback
traceback.print_exc(0)
pass
print(n)
mediator
"""http://dpip.testingperspective.com/?p=28"""
import time
class TC:
def __init__(self):
self._tm = tm
self._bProblem = 0
def setup(self):
print("Setting up the Test")
time.sleep(1)
self._tm.prepareReporting()
def execute(self):
if not self._bProblem:
print("Executing the test")
time.sleep(1)
else:
print("Problem in setup. Test not executed.")
def tearDown(self):
if not self._bProblem:
print("Tearing down")
time.sleep(1)
self._tm.publishReport()
else:
print("Test not executed. No tear down required.")
def setTM(self, TM):
self._tm = tm
def setProblem(self, value):
self._bProblem = value
class Reporter:
def __init__(self):
self._tm = None
def prepare(self):
print("Reporter Class is preparing to report the results")
time.sleep(1)
def report(self):
print("Reporting the results of Test")
time.sleep(1)
def setTM(self, TM):
self._tm = tm
class DB:
def __init__(self):
self._tm = None
def insert(self):
print("Inserting the execution begin status in the Database")
time.sleep(1)
#Following code is to simulate a communication from DB to TC
import random
if random.randrange(1, 4) == 3:
return -1
def update(self):
print("Updating the test results in Database")
time.sleep(1)
def setTM(self, TM):
self._tm = tm
class TestManager:
def __init__(self):
self._reporter = None
self._db = None
self._tc = None
def prepareReporting(self):
rvalue = self._db.insert()
if rvalue == -1:
self._tc.setProblem(1)
self._reporter.prepare()
def setReporter(self, reporter):
self._reporter = reporter
def setDB(self, db):
self._db = db
def publishReport(self):
self._db.update()
rvalue = self._reporter.report()
def setTC(self, tc):
self._tc = tc
if __name__ == '__main__':
reporter = Reporter()
db = DB()
tm = TestManager()
tm.setReporter(reporter)
tm.setDB(db)
reporter.setTM(tm)
db.setTM(tm)
# For simplification we are looping on the same test.
# Practically, it could be about various unique test classes and their
# objects
while (True):
tc = TC()
tc.setTM(tm)
tm.setTC(tc)
tc.setup()
tc.execute()
tc.tearDown()
prototype
import copy
class Prototype:
def __init__(self):
self._objects = {}
def register_object(self, name, obj):
"""Register an object"""
self._objects[name] = obj
def unregister_object(self, name):
"""Unregister an object"""
del self._objects[name]
def clone(self, name, **attr):
"""Clone a registered object and update inner attributes dictionary"""
obj = copy.deepcopy(self._objects.get(name))
obj.__dict__.update(attr)
return obj
def main():
class A:
pass
a = A()
prototype = Prototype()
prototype.register_object('a', a)
b = prototype.clone('a', a=1, b=2, c=3)
print(a)
print(b.a, b.b, b.c)
if __name__ == '__main__':
main()
decorator
# http://stackoverflow.com/questions/3118929/implementing-the-decorator-pattern-in-python
class foo(object):
def f1(self):
print("original f1")
def f2(self):
print("original f2")
class foo_decorator(object):
def __init__(self, decoratee):
self._decoratee = decoratee
def f1(self):
print("decorated f1")
self._decoratee.f1()
def __getattr__(self, name):
return getattr(self._decoratee, name)
u = foo()
v = foo_decorator(u)
v.f1()
v.f2()
adapter
# http://ginstrom.com/scribbles/2008/11/06/generic-adapter-class-in-python/
import os
class Dog(object):
def __init__(self):
self.name = "Dog"
def bark(self):
return "woof!"
class Cat(object):
def __init__(self):
self.name = "Cat"
def meow(self):
return "meow!"
class Human(object):
def __init__(self):
self.name = "Human"
def speak(self):
return "'hello'"
class Car(object):
def __init__(self):
self.name = "Car"
def make_noise(self, octane_level):
return "vroom%s" % ("!" * octane_level)
class Adapter(object):
"""
Adapts an object by replacing methods.
Usage:
dog = Dog
dog = Adapter(dog, dict(make_noise=dog.bark))
"""
def __init__(self, obj, adapted_methods):
"""We set the adapted methods in the object's dict"""
self.obj = obj
self.__dict__.update(adapted_methods)
def __getattr__(self, attr):
"""All non-adapted calls are passed to the object"""
return getattr(self.obj, attr)
def main():
objects = []
dog = Dog()
objects.append(Adapter(dog, dict(make_noise=dog.bark)))
cat = Cat()
objects.append(Adapter(cat, dict(make_noise=cat.meow)))
human = Human()
objects.append(Adapter(human, dict(make_noise=human.speak)))
car = Car()
car_noise = lambda: car.make_noise(3)
objects.append(Adapter(car, dict(make_noise=car_noise)))
for obj in objects:
print("A", obj.name, "goes", obj.make_noise())
if __name__ == "__main__":
main()
factory_method
#encoding=utf-8
"""http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/"""
class GreekGetter:
"""A simple localizer a la gettext"""
def __init__(self):
self.trans = dict(dog="蟽魏蠉位慰蟼", cat="纬维蟿伪")
def get(self, msgid):
"""We'll punt if we don't have a translation"""
try:
return self.trans[msgid]
except KeyError:
return str(msgid)
class EnglishGetter:
"""Simply echoes the msg ids"""
def get(self, msgid):
return str(msgid)
def get_localizer(language="English"):
"""The factory method"""
languages = dict(English=EnglishGetter, Greek=GreekGetter)
return languages[language]()
# Create our localizers
e, g = get_localizer("English"), get_localizer("Greek")
# Localize some text
for msgid in "dog parrot cat bear".split():
print(e.get(msgid), g.get(msgid))
observer
"""http://code.activestate.com/recipes/131499-observer-pattern/"""
class Subject(object):
def __init__(self):
self._observers = []
def attach(self, observer):
if not observer in self._observers:
self._observers.append(observer)
def detach(self, observer):
try:
self._observers.remove(observer)
except ValueError:
pass
def notify(self, modifier=None):
for observer in self._observers:
if modifier != observer:
observer.update(self)
# Example usage
class Data(Subject):
def __init__(self, name=''):
Subject.__init__(self)
self.name = name
self._data = 0
@property
def data(self):
return self._data
@data.setter
def data(self, value):
self._data = value
self.notify()
class HexViewer:
def update(self, subject):
print('HexViewer: Subject %s has data 0x%x' %
(subject.name, subject.data))
class DecimalViewer:
def update(self, subject):
print('DecimalViewer: Subject %s has data %d' %
(subject.name, subject.data))
# Example usage...
def main():
data1 = Data('Data 1')
data2 = Data('Data 2')
view1 = DecimalViewer()
view2 = HexViewer()
data1.attach(view1)
data1.attach(view2)
data2.attach(view2)
data2.attach(view1)
print("Setting Data 1 = 10")
data1.data = 10
print("Setting Data 2 = 15")
data2.data = 15
print("Setting Data 1 = 3")
data1.data = 3
print("Setting Data 2 = 5")
data2.data = 5
print("Detach HexViewer from data1 and data2.")
data1.detach(view2)
data2.detach(view2)
print("Setting Data 1 = 10")
data1.data = 10
print("Setting Data 2 = 15")
data2.data = 15
if __name__ == '__main__':
main()
command
import os
class MoveFileCommand(object):
def __init__(self, src, dest):
self.src = src
self.dest = dest
def execute(self):
self()
def __call__(self):
print('renaming {} to {}'.format(self.src, self.dest))
os.rename(self.src, self.dest)
def undo(self):
print('renaming {} to {}'.format(self.dest, self.src))
os.rename(self.dest, self.src)
if __name__ == "__main__":
command_stack = []
# commands are just pushed into the command stack
command_stack.append(MoveFileCommand('foo.txt', 'bar.txt'))
command_stack.append(MoveFileCommand('bar.txt', 'baz.txt'))
# they can be executed later on
for cmd in command_stack:
cmd.execute()
# and can also be undone at will
for cmd in reversed(command_stack):
cmd.undo()
iterator
"""http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/"""
"""Implementation of the iterator pattern with a generator"""
def count_to(count):
"""Counts by word numbers, up to a maximum of five"""
numbers = ["one", "two", "three", "four", "five"]
# enumerate() returns a tuple containing a count (from start which
# defaults to 0) and the values obtained from iterating over sequence
for pos, number in zip(range(count), numbers):
yield number
# Test the generator
count_to_two = lambda: count_to(2)
count_to_five = lambda: count_to(5)
print('Counting to two...')
for number in count_to_two():
print(number, end=' ')
print()
print('Counting to five...')
for number in count_to_five():
print(number, end=' ')
print()
template
"""http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/"""
"""An example of the Template pattern in Python"""
ingredients = "spam eggs apple"
line = '-' * 10
# Skeletons
def iter_elements(getter, action):
"""Template skeleton that iterates items"""
for element in getter():
action(element)
print(line)
def rev_elements(getter, action):
"""Template skeleton that iterates items in reverse order"""
for element in getter()[::-1]:
action(element)
print(line)
# Getters
def get_list():
return ingredients.split()
def get_lists():
return [list(x) for x in ingredients.split()]
# Actions
def print_item(item):
print(item)
def reverse_item(item):
print(item[::-1])
# Makes templates
def make_template(skeleton, getter, action):
"""Instantiate a template method with getter and action"""
def template():
skeleton(getter, action)
return template
# Create our template functions
templates = [make_template(s, g, a)
for g in (get_list, get_lists)
for a in (print_item, reverse_item)
for s in (iter_elements, rev_elements)]
# Execute them
for template in templates:
template()
null
#!/user/bin/env python
"""http://code.activestate.com/recipes/68205-null-object-design-pattern/"""
class Null:
def __init__(self, *args, **kwargs):
"""Ignore parameters."""
return None
def __call__(self, *args, **kwargs):
"""Ignore method calls."""
return self
def __getattr__(self, mname):
"""Ignore attribute requests."""
return self
def __setattr__(self, name, value):
"""Ignore attribute setting."""
return self
def __delattr__(self, name):
"""Ignore deleting attributes."""
return self
def __repr__(self):
"""Return a string representation."""
return "<Null>"
def __str__(self):
"""Convert to a string and return it."""
return "Null"
def test():
"""Perform some decent tests, or rather: demos."""
# constructing and calling
n = Null()
print(n)
n = Null('value')
print(n)
n = Null('value', param='value')
print(n)
n()
n('value')
n('value', param='value')
print(n)
# attribute handling
n.attr1
print('attr1', n.attr1)
n.attr1.attr2
n.method1()
n.method1().method2()
n.method('value')
n.method(param='value')
n.method('value', param='value')
n.attr1.method1()
n.method1().attr1
n.attr1 = 'value'
n.attr1.attr2 = 'value'
del n.attr1
del n.attr1.attr2.attr3
# representation and conversion to a string
assert repr(n) == '<Null>'
assert str(n) == 'Null'
if __name__ == '__main__':
test()
state
"""Implementation of the state pattern"""
'''http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/'''
class State(object):
"""Base state. This is to share functionality"""
def scan(self):
"""Scan the dial to the next station"""
self.pos += 1
if self.pos == len(self.stations):
self.pos = 0
print("Scanning... Station is", self.stations[self.pos], self.name)
class AmState(State):
def __init__(self, radio):
self.radio = radio
self.stations = ["1250", "1380", "1510"]
self.pos = 0
self.name = "AM"
def toggle_amfm(self):
print("Switching to FM")
self.radio.state = self.radio.fmstate
class FmState(State):
def __init__(self, radio):
self.radio = radio
self.stations = ["81.3", "89.1", "103.9"]
self.pos = 0
self.name = "FM"
def toggle_amfm(self):
print("Switching to AM")
self.radio.state = self.radio.amstate
class Radio(object):
"""A radio. It has a scan button, and an AM/FM toggle switch."""
def __init__(self):
"""We have an AM state and an FM state"""
self.amstate = AmState(self)
self.fmstate = FmState(self)
self.state = self.amstate
def toggle_amfm(self):
self.state.toggle_amfm()
def scan(self):
self.state.scan()
# Test our radio out
if __name__ == '__main__':
radio = Radio()
actions = [radio.scan] * 2 + [radio.toggle_amfm] + [radio.scan] * 2
actions = actions * 2
for action in actions:
action()
builder
#!/usr/bin/python
# -*- coding : utf-8 -*-
"""
@author: Diogenes Augusto Fernandes Herminio <diofeher@gmail.com>
https://gist.github.com/420905#file_builder_python.py
"""
# Director
class Director(object):
def __init__(self):
self.builder = None
def construct_building(self):
self.builder.new_building()
self.builder.build_floor()
self.builder.build_size()
def get_building(self):
return self.builder.building
# Abstract Builder
class Builder(object):
def __init__(self):
self.building = None
def new_building(self):
self.building = Building()
# Concrete Builder
class BuilderHouse(Builder):
def build_floor(self):
self.building.floor = 'One'
def build_size(self):
self.building.size = 'Big'
class BuilderFlat(Builder):
def build_floor(self):
self.building.floor = 'More than One'
def build_size(self):
self.building.size = 'Small'
# Product
class Building(object):
def __init__(self):
self.floor = None
self.size = None
def __repr__(self):
return 'Floor: %s | Size: %s' % (self.floor, self.size)
# Client
if __name__ == "__main__":
director = Director()
director.builder = BuilderHouse()
director.construct_building()
building = director.get_building()
print(building)
director.builder = BuilderFlat()
director.construct_building()
building = director.get_building()
print(building)
graph_search
class GraphSearch:
"""Graph search emulation in python, from source
http://www.python.org/doc/essays/graphs/"""
def __init__(self, graph):
self.graph = graph
def find_path(self, start, end, path=[]):
self.start = start
self.end = end
self.path = path
self.path += [self.start]
if self.start == self.end:
return self.path
if not self.graph.has_key(self.start):
return None
for node in self.graph[self.start]:
if node not in self.path:
newpath = self.find_path(node, self.end, self.path)
if newpath:
return newpath
return None
def find_all_path(self, start, end, path=[]):
self.start = start
self.end = end
self.path = path
self.path += [self.start]
if self.start == self.end:
return [self.path]
if not self.graph.has_key(self.start):
return []
paths = []
for node in self.graph[self.start]:
if node not in self.path:
newpaths = self.find_all_path(node, self.end, self.path)
for newpath in newpaths:
paths.append(newpath)
return paths
def find_shortest_path(self, start, end, path=[]):
self.start = start
self.end = end
self.path = path
self.path += [self.start]
if self.start == self.end:
return self.path
if not self.graph.has_key(self.start):
return None
shortest = None
for node in self.graph[self.start]:
if node not in self.path:
newpath = self.find_shortest_path(node, self.end, self.path)
if newpath:
if not shortest or len(newpath) < len(shortest):
shortest = newpath
return shortest
#example of graph usage
graph = {'A': ['B', 'C'],
'B': ['C', 'D'],
'C': ['D'],
'D': ['C'],
'E': ['F'],
'F': ['C']
}
#inistialization of new graph search object
graph1 = GraphSearch(graph)
print graph1.find_path('A', 'D')
print graph1.find_all_path('A', 'D')
print graph1.find_shortest_path('A', 'D')
flyweight
"""http://codesnipers.com/?q=python-flyweights"""
import weakref
class Card(object):
"""The object pool. Has builtin reference counting"""
_CardPool = weakref.WeakValueDictionary()
"""Flyweight implementation. If the object exists in the
pool just return it (instead of creating a new one)"""
def __new__(cls, value, suit):
obj = Card._CardPool.get(value + suit, None)
if not obj:
obj = object.__new__(cls)
Card._CardPool[value + suit] = obj
obj.value, obj.suit = value, suit
return obj
# def __init__(self, value, suit):
# self.value, self.suit = value, suit
def __repr__(self):
return "<Card: %s%s>" % (self.value, self.suit)
if __name__ == '__main__':
# comment __new__ and uncomment __init__ to see the difference
c1 = Card('9', 'h')
c2 = Card('9', 'h')
print(c1, c2)
print(c1 == c2)
print(id(c1), id(c2))
pool
"""http://stackoverflow.com/questions/1514120/python-implementation-of-the-object-pool-design-pattern"""
class QueueObject():
def __init__(self, queue, auto_get=False):
self._queue = queue
self.object = self._queue.get() if auto_get else None
def __enter__(self):
if self.object is None:
self.object = self._queue.get()
return self.object
def __exit__(self, type, value, traceback):
if self.object is not None:
self._queue.put(self.object)
self.object = None
def __del__(self):
if self.object is not None:
self._queue.put(self.object)
self.object = None
def main():
try:
import queue
except ImportError: # python 2.x compatibility
import Queue as queue
def test_object(queue):
queue_object = QueueObject(queue, True)
print('Inside func: {}'.format(queue_object.object))
sample_queue = queue.Queue()
sample_queue.put('yam')
with QueueObject(sample_queue) as obj:
print('Inside with: {}'.format(obj))
print('Outside with: {}'.format(sample_queue.get()))
sample_queue.put('sam')
test_object(sample_queue)
print('Outside func: {}'.format(sample_queue.get()))
if not sample_queue.empty():
print(sample_queue.get())
if __name__ == '__main__':
main()
composite
"""
A class which defines a composite object which can store
hieararchical dictionaries with names.
This class is same as a hiearchical dictionary, but it
provides methods to add/access/modify children by name,
like a Composite.
Created Anand B Pillai <abpillai@gmail.com>
"""
__author__ = "Anand B Pillai"
__maintainer__ = "Anand B Pillai"
__version__ = "0.2"
def normalize(val):
""" Normalize a string so that it can be used as an attribute
to a Python object """
if val.find('-') != -1:
val = val.replace('-', '_')
return val
def denormalize(val):
""" De-normalize a string """
if val.find('_') != -1:
val = val.replace('_', '-')
return val
class SpecialDict(dict):
""" A dictionary type which allows direct attribute
access to its keys """
def __getattr__(self, name):
if name in self.__dict__:
return self.__dict__[name]
elif name in self:
return self.get(name)
else:
# Check for denormalized name
name = denormalize(name)
if name in self:
return self.get(name)
else:
raise AttributeError('no attribute named %s' % name)
def __setattr__(self, name, value):
if name in self.__dict__:
self.__dict__[name] = value
elif name in self:
self[name] = value
else:
# Check for denormalized name
name2 = denormalize(name)
if name2 in self:
self[name2] = value
else:
# New attribute
self[name] = value
class CompositeDict(SpecialDict):
""" A class which works like a hierarchical dictionary.
This class is based on the Composite design-pattern """
ID = 0
def __init__(self, name=''):
if name:
self._name = name
else:
self._name = ''.join(('id#', str(self.__class__.ID)))
self.__class__.ID += 1
self._children = []
# Link back to father
self._father = None
self[self._name] = SpecialDict()
def __getattr__(self, name):
if name in self.__dict__:
return self.__dict__[name]
elif name in self:
return self.get(name)
else:
# Check for denormalized name
name = denormalize(name)
if name in self:
return self.get(name)
else:
# Look in children list
child = self.findChild(name)
if child:
return child
else:
attr = getattr(self[self._name], name)
if attr:
return attr
raise AttributeError('no attribute named %s' % name)
def isRoot(self):
""" Return whether I am a root component or not """
# If I don't have a parent, I am root
return not self._father
def isLeaf(self):
""" Return whether I am a leaf component or not """
# I am a leaf if I have no children
return not self._children
def getName(self):
""" Return the name of this ConfigInfo object """
return self._name
def getIndex(self, child):
""" Return the index of the child ConfigInfo object 'child' """
if child in self._children:
return self._children.index(child)
else:
return -1
def getDict(self):
""" Return the contained dictionary """
return self[self._name]
def getProperty(self, child, key):
""" Return the value for the property for child
'child' with key 'key' """
# First get the child's dictionary
childDict = self.getInfoDict(child)
if childDict:
return childDict.get(key, None)
def setProperty(self, child, key, value):
""" Set the value for the property 'key' for
the child 'child' to 'value' """
# First get the child's dictionary
childDict = self.getInfoDict(child)
if childDict:
childDict[key] = value
def getChildren(self):
""" Return the list of immediate children of this object """
return self._children
def getAllChildren(self):
""" Return the list of all children of this object """
l = []
for child in self._children:
l.append(child)
l.extend(child.getAllChildren())
return l
def getChild(self, name):
""" Return the immediate child object with the given name """
for child in self._children:
if child.getName() == name:
return child
def findChild(self, name):
""" Return the child with the given name from the tree """
# Note - this returns the first child of the given name
# any other children with similar names down the tree
# is not considered.
for child in self.getAllChildren():
if child.getName() == name:
return child
def findChildren(self, name):
""" Return a list of children with the given name from the tree """
# Note: this returns a list of all the children of a given
# name, irrespective of the depth of look-up.
children = []
for child in self.getAllChildren():
if child.getName() == name:
children.append(child)
return children
def getPropertyDict(self):
""" Return the property dictionary """
d = self.getChild('__properties')
if d:
return d.getDict()
else:
return {}
def getParent(self):
""" Return the person who created me """
return self._father
def __setChildDict(self, child):
""" Private method to set the dictionary of the child
object 'child' in the internal dictionary """
d = self[self._name]
d[child.getName()] = child.getDict()
def setParent(self, father):
""" Set the parent object of myself """
# This should be ideally called only once
# by the father when creating the child :-)
# though it is possible to change parenthood
# when a new child is adopted in the place
# of an existing one - in that case the existing
# child is orphaned - see addChild and addChild2
# methods !
self._father = father
def setName(self, name):
""" Set the name of this ConfigInfo object to 'name' """
self._name = name
def setDict(self, d):
""" Set the contained dictionary """
self[self._name] = d.copy()
def setAttribute(self, name, value):
""" Set a name value pair in the contained dictionary """
self[self._name][name] = value
def getAttribute(self, name):
""" Return value of an attribute from the contained dictionary """
return self[self._name][name]
def addChild(self, name, force=False):
""" Add a new child 'child' with the name 'name'.
If the optional flag 'force' is set to True, the
child object is overwritten if it is already there.
This function returns the child object, whether
new or existing """
if type(name) != str:
raise ValueError('Argument should be a string!')
child = self.getChild(name)
if child:
# print 'Child %s present!' % name
# Replace it if force==True
if force:
index = self.getIndex(child)
if index != -1:
child = self.__class__(name)
self._children[index] = child
child.setParent(self)
self.__setChildDict(child)
return child
else:
child = self.__class__(name)
child.setParent(self)
self._children.append(child)
self.__setChildDict(child)
return child
def addChild2(self, child):
""" Add the child object 'child'. If it is already present,
it is overwritten by default """
currChild = self.getChild(child.getName())
if currChild:
index = self.getIndex(currChild)
if index != -1:
self._children[index] = child
child.setParent(self)
# Unset the existing child's parent
currChild.setParent(None)
del currChild
self.__setChildDict(child)
else:
child.setParent(self)
self._children.append(child)
self.__setChildDict(child)
if __name__ == "__main__":
window = CompositeDict('Window')
frame = window.addChild('Frame')
tfield = frame.addChild('Text Field')
tfield.setAttribute('size', '20')
btn = frame.addChild('Button1')
btn.setAttribute('label', 'Submit')
btn = frame.addChild('Button2')
btn.setAttribute('label', 'Browse')
# print(window)
# print(window.Frame)
# print(window.Frame.Button1)
# print(window.Frame.Button2)
print(window.Frame.Button1.label)
print(window.Frame.Button2.label)
strategy
"""http://stackoverflow.com/questions/963965/how-is-this-strategy-pattern-written-in-python-the-sample-in-wikipedia
In most of other languages Strategy pattern is implemented via creating some base strategy interface/abstract class and
subclassing it with a number of concrete strategies (as we can see at http://en.wikipedia.org/wiki/Strategy_pattern),
however Python supports higher-order functions and allows us to have only one class and inject functions into it's
instances, as shown in this example.
"""
import types
class StrategyExample:
def __init__(self, func=None):
self.name = 'Strategy Example 0'
if func is not None:
self.execute = types.MethodType(func, self)
def execute(self):
print(self.name)
def execute_replacement1(self):
print(self.name + ' from execute 1')
def execute_replacement2(self):
print(self.name + ' from execute 2')
if __name__ == '__main__':
strat0 = StrategyExample()
strat1 = StrategyExample(execute_replacement1)
strat1.name = 'Strategy Example 1'
strat2 = StrategyExample(execute_replacement2)
strat2.name = 'Strategy Example 2'
strat0.execute()
strat1.execute()
strat2.execute()
proxy
import time
class SalesManager:
def work(self):
print("Sales Manager working...")
def talk(self):
print("Sales Manager ready to talk")
class Proxy:
def __init__(self):
self.busy = 'No'
self.sales = None
def work(self):
print("Proxy checking for Sales Manager availability")
if self.busy == 'No':
self.sales = SalesManager()
time.sleep(2)
self.sales.talk()
else:
time.sleep(2)
print("Sales Manager is busy")
if __name__ == '__main__':
p = Proxy()
p.work()
p.busy = 'Yes'
p.work()
visitor
"""http://peter-hoffmann.com/2010/extrinsic-visitor-pattern-python-inheritance.html"""
class Node(object):
pass
class A(Node):
pass
class B(Node):
pass
class C(A, B):
pass
class Visitor(object):
def visit(self, node, *args, **kwargs):
meth = None
for cls in node.__class__.__mro__:
meth_name = 'visit_'+cls.__name__
meth = getattr(self, meth_name, None)
if meth:
break
if not meth:
meth = self.generic_visit
return meth(node, *args, **kwargs)
def generic_visit(self, node, *args, **kwargs):
print('generic_visit '+node.__class__.__name__)
def visit_B(self, node, *args, **kwargs):
print('visit_B '+node.__class__.__name__)
a = A()
b = B()
c = C()
visitor = Visitor()
visitor.visit(a)
visitor.visit(b)
visitor.visit(c)
顺序是乱的,因为爬虫是多线程的,反正内容都在这里。爬虫在我的Github里面,可以自己找。
最后还是强调一点,这些代码来自PythonTip,版权归PythonTip所有。
P.s 欢迎大家闲来无事一起刷题啊!