赞
踩
import xml.etree.ElementTree as etree import json # JSONConnector类解析JSON文件,通过parsed_data()方法以一个字典(dict)的形式 返回数据。 # 修饰器property使parsed_data()显得更像一个常规的变量,而不是一个方法 class JSONConnector: def __init__(self, filepath): self.data = dict() with open(filepath, mode='r', encoding='utf-8') as f: self.data = json.load(f) @property def parsed_data(self): return self.data # XMLConnector类解析xml数据 class XMLConnector: def __init__(self, filepath): self.tree = etree.parse(filepath) @property def parsed_data(self): return self.tree # 函数connection_factory是一个工厂方法, # 基于输入文件路径的扩展名返回一个JSONConnector或XMLConnector的实例 def connection_factory(filepath): if filepath.endswith('json'): connector = JSONConnector elif filepath.endswith('xml'): connector = XMLConnector else: raise ValueError('Cannot connect to {}'.format(filepath)) return connector(filepath) # 函数connect_to()对connection_factory()进行包装,添加了异常处理 def connect_to(filepath): factory = None try: factory = connection_factory(filepath) except ValueError as ve: print(ve) return factory # 注意,虽然JSONConnector和XMLConnector拥有相同的接口, # 但是对于parsed_data() 返回的数据并不是以统一的方式进行处理。 # 对于每个连接器,需使用不同的Python代码来处理。 def main(): sqlite_factory = connect_to('data/person.sq3') print() xml_factory = connect_to('data/person.xml') xml_data = xml_factory.parsed_data liars = xml_data.findall(".//{}[{}='{}']".format('person', 'lastName', 'Liar')) print('found: {} persons'.format(len(liars))) for liar in liars: print('first name: {}'.format(liar.find('firstName').text)) print('last name: {}'.format(liar.find('lastName').text)) [print('phone number ({})'.format(p.attrib['type']), p.text) for p in liar.find('phoneNumbers')] print() json_factory = connect_to('data/donut.json') json_data = json_factory.parsed_data print('found: {} donuts'.format(len(json_data))) for donut in json_data: print('name: {}'.format(donut['name'])) print('price: ${}'.format(donut['ppu'])) [print('topping: {} {}'.format(t['id'], t['type'])) for t in donut['topping']] if __name__ == '__main__': main()
# Frog青蛙碰到Bug虫子,就吃掉它 class Frog: def __init__(self, name): self.name = name def __str__(self): return self.name # 这里模拟Frog和Bug类之间的交互 def interact_with(self, obstacle): print('{} the Frog encounters {} and {}!'.format(self, obstacle, obstacle.action())) class Bug: def __str__(self): return 'a bug' def action(self): return 'eats it' # 类FrogWorld是一个抽象工厂,其主要职责是创建游戏的主人公和障碍物。 # 区分创建方法并使其名字通用(比如,make_character()和make_obstacle()), # 这让我们可以动态改变当前激活的工厂(也因此改变了当前激活的游戏),而无需进行任何代码变更。 class FrogWorld: def __init__(self, name): print(self) self.player_name = name def __str__(self): return '\n\n\t------ Frog World ———' def make_character(self): return Frog(self.player_name) def make_obstacle(self): return Bug() # 男巫类Wizard class Wizard: def __init__(self, name): self.name = name def __str__(self): return self.name # 男巫类Wizard和怪兽类Ork两者之间的交互 def interact_with(self, obstacle): print('{} the Wizard battles against {} and {}!'.format(self, obstacle, obstacle.action())) # 怪兽类Ork class Ork: def __str__(self): return 'an evil ork' def action(self): return 'kills it' # 抽象工厂,生成实例 class WizardWorld: def __init__(self, name): print(self) self.player_name = name def __str__(self): return '\n\n\t------ Wizard World ———' def make_character(self): return Wizard(self.player_name) def make_obstacle(self): return Ork() # 类GameEnvironment是我们游戏的主入口。它接受factory作为输入, # 用其创建游戏的世界。方法play()则会启动hero和obstacle之间的交互 class GameEnvironment: def __init__(self, factory): self.hero = factory.make_character() self.obstacle = factory.make_obstacle() def play(self): self.hero.interact_with(self.obstacle) # 函数validate_age()提示用户提供一个有效的年龄。如果年龄无效,则会返回一个元组, 其第一个元素设置为False。 # 如果年龄没问题,元素的第一个元素则设置为True,但我们真正关 心的是元素的第二个元素,也就是用户提供的年龄, def validate_age(name): try: age = input('Welcome {}. How old are you? '.format(name)) age = int(age) except ValueError as err: print("Age {} is invalid, please try \ again…".format(age)) return (False, age) return (True, age) # 该函数请求用户的姓名和年龄,并根据用户的年龄决定该玩 哪个游戏 def main(): name = input("Hello. What's your name? ") valid_input = False while not valid_input: valid_input, age = validate_age(name) game = FrogWorld if age < 18 else WizardWorld environment = GameEnvironment(game(name)) environment.play() if __name__ == '__main__': main()
# coding: utf-8 class Computer: def __init__(self, serial_number): self.serial = serial_number self.memory = None # 单位为GB self.hdd = None # 单位为GB self.gpu = None def __str__(self): info = ('Memory: {}GB'.format(self.memory), 'Hard Disk: {}GB'.format(self.hdd), 'Graphics Card: {}'.format(self.gpu)) return '\n'.join(info) # 引入了一个建造者ComputerBuilder、一个指挥者HardwareEngineer # 以及一步接一步装配一台电脑的过程,这样现在就支持不同的配置了 class ComputerBuilder: def __init__(self): self.computer = Computer('AG23385193') def configure_memory(self, amount): self.computer.memory = amount def configure_hdd(self, amount): self.computer.hdd = amount def configure_gpu(self, gpu_model): self.computer.gpu = gpu_model class HardwareEngineer: def __init__(self): self.builder = None def construct_computer(self, memory, hdd, gpu): self.builder = ComputerBuilder() [step for step in (self.builder.configure_memory(memory), self.builder.configure_hdd(hdd), self.builder.configure_gpu(gpu))] @property def computer(self): return self.builder.computer def main(): engineer = HardwareEngineer() engineer.construct_computer(hdd=500, memory=8, gpu='GeForce GTX 650 Ti') computer = engineer.computer print(computer) if __name__ == '__main__': main()
# coding: utf-8 from enum import Enum # 枚举 import time PizzaProgress = Enum('PizzaProgress', 'queued preparation baking ready') # 准备阶段 PizzaDough = Enum('PizzaDough', 'thin thick') # 生面团 PizzaSauce = Enum('PizzaSauce', 'tomato creme_fraiche') # 调味料 PizzaTopping = Enum('PizzaTopping', 'mozzarella double_mozzarella bacon ham mushrooms red_onion oregano') # 配料 STEP_DELAY = 3 # 考虑是示例,单位为秒 class Pizza: def __init__(self, name): self.name = name self.dough = None self.sauce = None self.topping = [] def __str__(self): return self.name # 这个本来不用放在这里的,但是生面团都一样,因此这里提高代码利用率放在这里 def prepare_dough(self, dough): self.dough = dough print('preparing the {} dough of your {}...'.format(self.dough.name, self)) time.sleep(STEP_DELAY) print('done with the {} dough'.format(self.dough.name)) # 建造者:制作玛格丽特比萨(MargaritaBudiler), class MargaritaBuilder: def __init__(self): self.pizza = Pizza('margarita') self.progress = PizzaProgress.queued self.baking_time = 5 # 考虑是示例,单位为秒 def prepare_dough(self): self.progress = PizzaProgress.preparation self.pizza.prepare_dough(PizzaDough.thin) def add_sauce(self): print('adding the tomato sauce to your margarita...') self.pizza.sauce = PizzaSauce.tomato time.sleep(STEP_DELAY) print('done with the tomato sauce') def add_topping(self): print('adding the topping (double mozzarella, oregano) to your margarita') self.pizza.topping.append([i for i in (PizzaTopping.double_mozzarella, PizzaTopping.oregano)]) time.sleep(STEP_DELAY) print('done with the topping (double mozzarrella, oregano)') def bake(self): self.progress = PizzaProgress.baking print('baking your margarita for {} seconds'.format(self.baking_time)) time.sleep(self.baking_time) self.progress = PizzaProgress.ready print('your margarita is ready') # 建造者:制作奶油熏肉比萨(CreamyBaconBuilder)。 class CreamyBaconBuilder: def __init__(self): self.pizza = Pizza('creamy bacon') self.progress = PizzaProgress.queued self.baking_time = 7 # 考虑是示例,单位为秒 def prepare_dough(self): self.progress = PizzaProgress.preparation self.pizza.prepare_dough(PizzaDough.thick) def add_sauce(self): print('adding the crème fraîche sauce to your creamy bacon') self.pizza.sauce = PizzaSauce.creme_fraiche time.sleep(STEP_DELAY) print('done with the crème fraîche sauce') def add_topping(self): print('adding the topping (mozzarella, bacon, ham, mushrooms, red onion, oregano) to your creamy bacon') self.pizza.topping.append([t for t in (PizzaTopping.mozzarella, PizzaTopping.bacon, PizzaTopping.ham, PizzaTopping.mushrooms, PizzaTopping.red_onion, PizzaTopping.oregano)]) time.sleep(STEP_DELAY) print('done with the topping (mozzarella, bacon, ham, mushrooms, red onion, oregano)') def bake(self): self.progress = PizzaProgress.baking print('baking your creamy bacon for {} seconds'.format(self.baking_time)) time.sleep(self.baking_time) self.progress = PizzaProgress.ready print('your creamy bacon is ready') # 指挥者就是服务员。Waiter类的核心是construct_pizza方法, # 该方法接受一个建造者作为参数,并以正确的顺序执行比萨的所有准备步骤。 class Waiter: def __init__(self): self.builder = None def construct_pizza(self, builder): self.builder = builder [step() for step in (builder.prepare_dough, builder.add_sauce, builder.add_topping, builder.bake)] @property def pizza(self): return self.builder.pizza # 函数validate_style()类似于第1章中描述的validate_age()函数,用于确保用户提供有效的输入, # 当前案例中这个输入是映射到一个比萨建造者的字符;输入字符m表示使用 MargaritaBuilder类, # 输入字符c则使用CreamyBaconBuilder类。 # 这些映射关系存储在参数 builder中。该函数会返回一个元组,如果输入有效,则元组的第一个元素被设置为True,否则为False, def validate_style(builders): try: pizza_style = input('What pizza would you like, [m]argarita or [c]reamy bacon? ') builder = builders[pizza_style]() valid_input = True except KeyError as err: print('Sorry, only margarita (key m) and creamy bacon (key c) are available') return (False, None) return (True, builder) def main(): builders = dict(m=MargaritaBuilder, c=CreamyBaconBuilder) valid_input = False while not valid_input: valid_input, builder = validate_style(builders) print() waiter = Waiter() waiter.construct_pizza(builder) pizza = waiter.pizza print() print('Enjoy your {}!'.format(pizza)) if __name__ == '__main__': main()
# coding: utf-8 class Pizza: def __init__(self, builder): self.garlic = builder.garlic self.extra_cheese = builder.extra_cheese def __str__(self): garlic = 'yes' if self.garlic else 'no' cheese = 'yes' if self.extra_cheese else 'no' info = ('Garlic: {}'.format(garlic), 'Extra cheese: {}'.format(cheese)) return '\n'.join(info) class PizzaBuilder: def __init__(self): self.extra_cheese = False self.garlic = False def add_garlic(self): self.garlic = True return self def add_extra_cheese(self): self.extra_cheese = True return self def build(self): return Pizza(self) if __name__ == '__main__': pizza = Pizza.PizzaBuilder().add_garlic().add_extra_cheese().build() print(pizza)
# coding: utf-8 import copy from collections import OrderedDict class Book: # 仅有三个形参是固定的:name、authors和price, # v但是使用rest变长列表,调用者 能以关键词的形式(名称=值)传入更多的参数。 # self.__dict__.update(rest)一行将rest 的内容添加到Book类的内部字典中,成为它的一部分。 def __init__(self, name, authors, price, **rest): '''rest的例子有:出版商,长度,标签,出版日期''' self.name = name self.authors = authors self.price = price # 单位为美元 self.__dict__.update(rest) # 我们并不知道所有被添加参数的名称,但又需要访问内部字典将这些参数应用到__str__()中, # 并且字典的内容并不遵循任何特定的顺序,所以使用一个OrderedDict来强制元素有序, # 否则,每次程序执行都会产生不同的输出。 def __str__(self): mylist = [] ordered = OrderedDict(sorted(self.__dict__.items())) for i in ordered.keys(): mylist.append('{}: {}'.format(i, ordered[i])) if i == 'price': mylist.append('$') mylist.append('\n') return ''.join(mylist) # Prototype类实现了原型设计模式。Prototype类的核心是clone()方法,该方法使用我们 熟悉的copy.deepcopy()函数来完成真正的克隆工作。 # 但Prototype类在支持克隆之外做了一点更多的事情,它包含了方法register()和unregister(),这两个方法用于在一个字典中追 踪被克隆的对象。 class Prototype: def __init__(self): self.objects = dict() def register(self, identifier, obj): self.objects[identifier] = obj def unregister(self, identifier): del self.objects[identifier] def clone(self, identifier, **attr): found = self.objects.get(identifier) if not found: raise ValueError('Incorrect object identifier: {}'.format(identifier)) obj = copy.deepcopy(found) obj.__dict__.update(attr) return obj def main(): b1 = Book('The C Programming Language', ('Brian W. Kernighan', 'Dennis M.Ritchie'), price=118, publisher='Prentice Hall', length=228, publication_date='1978-02-22', tags=('C', 'programming', 'algorithms', 'data structures')) prototype = Prototype() cid = 'k&r-first' prototype.register(cid, b1) b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99, length=274, publication_date='1988-04-01', edition=2) for i in (b1, b2): print(i) print('ID b1 : {} != ID b2 : {}'.format(id(b1), id(b2))) if __name__ == '__main__': main()
简便记忆:外观(装饰器)代理(控制器)享元(适配器)
# coding: utf-8 from enum import Enum from abc import ABCMeta, abstractmethod State = Enum('State', 'new running sleeping restart zombie') class User: pass class Process: pass class File: pass class Server(metaclass=ABCMeta): @abstractmethod def __init__(self): pass def __str__(self): return self.name @abstractmethod def boot(self): pass @abstractmethod def kill(self, restart=True): pass class FileServer(Server): def __init__(self): '''初始化文件服务进程要求的操作''' self.name = 'FileServer' self.state = State.new def boot(self): print('booting the {}'.format(self)) '''启动文件服务进程要求的操作''' self.state = State.running def kill(self, restart=True): print('Killing {}'.format(self)) '''杀死文件服务进程要求的操作''' self.state = State.restart if restart else State.zombie def create_file(self, user, name, permissions): '''检查访问权限的有效性、用户权限,等等''' print("trying to create the file '{}' for user '{}' with permissions {}".format(name, user, permissions)) class ProcessServer(Server): def __init__(self): '''初始化进程服务进程要求的操作''' self.name = 'ProcessServer' self.state = State.new def boot(self): print('booting the {}'.format(self)) '''启动进程服务进程要求的操作''' self.state = State.running def kill(self, restart=True): print('Killing {}'.format(self)) '''杀死进程服务进程要求的操作''' self.state = State.restart if restart else State.zombie def create_process(self, user, name): '''检查用户权限、生成PID,等等''' print("trying to create the process '{}' for user '{}'".format(name, user)) class WindowServer: pass class NetworkServer: pass class OperatingSystem: '''外观''' def __init__(self): self.fs = FileServer() self.ps = ProcessServer() def start(self): [i.boot() for i in (self.fs, self.ps)] def create_file(self, user, name, permissions): return self.fs.create_file(user, name, permissions) def create_process(self, user, name): return self.ps.create_process(user, name) def main(): os = OperatingSystem() os.start() os.create_file('foo', 'hello', '-rw-r-r') os.create_process('bar', 'ls /tmp') if __name__ == '__main__': main()
## 1、直接使用递归,函数执行时间 def fibonacci(n): assert(n >= 0), 'n must be >= 0' return n if n in (0, 1) else fibonacci(n-1) + fibonacci(n-2) if __name__ == '__main__': from timeit import Timer t = Timer('fibonacci(8)', 'from __main__ import fibonacci') print(t.timeit()) # 结果16s多 ## 使用dict缓存计算结果 known = {0:0, 1:1} def fibonacci(n): assert(n >= 0), 'n must be >= 0' if n in known: return known[n] res = fibonacci(n-1) + fibonacci(n-2) known[n] = res return res if __name__ == '__main__': from timeit import Timer t = Timer('fibonacci(100)', 'from __main__ import fibonacci') print(t.timeit()) # 结果:0.3s多 ## 使用装饰器 # 函数functools.wraps() 是一个为创建修饰器提供便利的函数;虽不强制,但推荐使用, # 因为它能保留被修饰函数的文档和签名。这种情况要求参数列表*args,因为被修饰的函数可能有 输入参数。 import functools def memoize(fn): known = dict() @functools.wraps(fn) def memoizer(*args): if args not in known: known[args] = fn(*args) return known[args] return memoizer
# coding: utf-8 import functools def memoize(fn): known = dict() @functools.wraps(fn) def memoizer(*args): if args not in known: known[args] = fn(*args) return known[args] return memoizer @memoize def nsum(n): '''返回前n个数字的和''' assert(n >= 0), 'n must be >= 0' return 0 if n == 0 else n + nsum(n-1) @memoize def fibonacci(n): '''返回斐波那契数列的第n个数''' assert(n >= 0), 'n must be >= 0' return n if n in (0, 1) else fibonacci(n-1) + fibonacci(n-2) if __name__ == '__main__': from timeit import Timer measure = [{'exec': 'fibonacci(100)', 'import': 'fibonacci', 'func': fibonacci}, {'exec': 'nsum(200)', 'import': 'nsum', 'func': nsum}] for m in measure: t = Timer('{}'.format(m['exec']), 'from __main__ import \ {}'.format(m['import'])) print('name: {}, doc: {}, executing: {}, time: \ {}'.format(m['func'].__name__, m['func'].__doc__, m['exec'], t.timeit()))
# coding: utf-8 """ LazyProperty类实际上是一个描述符(请参考网页[t.cn/RqrYBND])。描述符(descriptor) 是Python中重写类属性访问方法(__get__()、__set__()和__delete__())的默认行为要使 用的一种推荐机制。LazyProperty类仅重写了__set__(),因为这是其需要重写的唯一访问方 法。换句话说,我们无需重写所有访问方法。__get__()方法所访问的特性值,正是下层方法想 要赋的值,并使用setattr()来手动赋值。__get__()实际做的事情非常简单,就是使用值来 替代方法!这意味着不仅特性是惰性加载的,而且仅可以设置一次。 """ class LazyProperty: def __init__(self, method): self.method = method self.method_name = method.__name__ # print('function overriden: {}'.format(self.method)) # print("function's name: {}".format(self.method_name)) def __get__(self, obj, cls): if not obj: return None value = self.method(obj) # 获取obj对象的method属性的值么? # print('value {}'.format(value)) setattr(obj, self.method_name, value) return value class Test: def __init__(self): self.x = 'foo' self.y = 'bar' self._resource = None @LazyProperty def resource(self): print('initializing self._resource which is: {}'.format(self._resource)) self._resource = tuple(range(5)) # 代价大的 return self._resource def main(): t = Test() print(t.x) print(t.y) # 做更多的事情。。。 print(t.resource) print(t.resource) if __name__ == '__main__': main()
class A: def __init__(self, val): self.val = val def __get__(self, instance, owner): print('self is ', self) print('instance is ', instance) print('owner is ', owner) return self.val class B: a = A(10) b = B() print(b.a) # descriptor # 一个类中定义了__set__, __get__和__delete__中的一个或多个就是descriptor。 # __get__函数定义的时候需要的参数为三个,分别为self, instance, owner。 # __set__函数定义的时候需要的参数为三个,分别是self, instance, value。 # 理解了下面的一句话就理解了文件描述器的实质: # self很简单,就是descriptor的实例; # instance就是descriptor所在类中的实例; # owner指的是descriptor所在的类。 # 还可以看出来的是,打印的b.a不是一个是实例对象,而是通过调用a.__get__()函数返回的值。 # 所以我感觉这个descriptor叫做描述器(借鉴于decorator)似乎更合适。。。 # 因为这个descriptor似乎是用来描述所在的实例的。。。 # 总结:通过实例调用(b.a)这个descriptor对象,返回的并不是这个descriptor(你可以尝试打印一个实例对象, # 看看返回的是什么),而是该descriptor调用__get__返回的值,所以这个a像是b的描述器。 class LazyProperty(object): def __init__(self, func): self.func = func def __get__(self, instance, owner): if instance is None: return self else: value = self.func(instance) setattr(instance, self.func.__name__, value) return value class A: @LazyProperty def func(self): time.sleep(1) return 10
# coding: utf-8 """ 查看用户列表:这一操作不要求特殊权限。 添加新用户:这一操作要求客户端提供一个特殊的密码。 """ class SensitiveInfo: def __init__(self): self.users = ['nick', 'tom', 'ben', 'mike'] def read(self): print('There are {} users: {}'.format(len(self.users), ' '.join(self.users))) def add(self, user): self.users.append(user) print('Added user {}'.format(user)) class Info: '''SensitiveInfo的保护代理''' def __init__(self): self.protected = SensitiveInfo() self.secret = '0xdeadbeef' def read(self): self.protected.read() def add(self, user): sec = input('what is the secret? ') self.protected.add(user) if sec == self.secret else print("That's wrong!") def main(): info = Info() while True: print('1. read list |==| 2. add user |==| 3. quit') key = input('choose option: ') if key == '1': info.read() elif key == '2': name = input('choose username: ') info.add(name) elif key == '3': exit() else: print('unknown option: {}'.format(key)) if __name__ == '__main__': main()
""" 用户输入一个数字,然后就能看到与这个数字相关的名人名言。 名人名言存储在一个quotes元组中。这种数据通常是存储在数据库、文件或其他地方, 只有模型能够直接访问它。 """ quotes = ('A man is not complete until he is married. Then he is finished.', 'As I said before, I never repeat myself.', 'Behind a successful man is an exhausted woman.', 'Black holes really suck...', 'Facts are stubborn things.') class QuoteModel: def get_quote(self, n): try: value = quotes[n] except IndexError as err: value = 'Not found!' return value class QuoteTerminalView: def show(self, quote): print('And the quote is: "{}"'.format(quote)) def error(self, msg): print('Error: {}'.format(msg)) def select_quote(self): return input('Which quote number would you like to see?') class QuoteTerminalController: def __init__(self): self.model = QuoteModel() self.view = QuoteTerminalView() def run(self): valid_input = False while not valid_input: n = self.view.select_quote() try: n = int(n) except ValueError as err: self.view.error("Incorrect index '{}'".format(n)) else: valid_input = True quote = self.model.get_quote(n) self.view.show(quote) def main(): controller = QuoteTerminalController() while True: controller.run() if __name__ == '__main__': main()
# coding: utf-8 """ 构造一小片水果树的森林,小到能确保在单个终端页面中阅读整个输出。 然而,无论你构造的森林有多大,内存分配都保持相同。 """ import random from enum import Enum # 枚举 TreeType = Enum('TreeType', 'apple_tree cherry_tree peach_tree') class Tree: # pool是一个类属性(类的所有实例共享的一个变量),(换句话说,是我们的缓存) pool = dict() # 使用特殊方法__new__(这个方法在__init__之前被调用), # 我们把Tree类变换成一个元类,元类支持自引用。这意味着cls引用的是Tree类。 # 当客户端要创建Tree的一个实例时,会以tree_type参数传递树的种类。 # 树的种类用于检查是否创建过相同种类的树。如果是,则返回之前创建的对象; # 否则,将这个新的树种添加到池中,并返回相应的新对象 def __new__(cls, tree_type): obj = cls.pool.get(tree_type, None) if not obj: obj = object.__new__(cls) # 实例化,对象.方法(类) cls.pool[tree_type] = obj # 将对象加入类的pool中 obj.tree_type = tree_type # 设置对象的属性 return obj # 元类编程中obj是本类实例化的对象 # cls是类 # 方法render()用于在屏幕上渲染一棵树。注意,享元不知道的所有可变(外部的)信息都需要由客户端代码显式地传递。 # 在当前案例中,每棵树都用到一个随机的年龄和一个x, y形式的位置。 # 为了让render()更加有用,有必要确保没有树会被渲染到另一个棵之上。 def render(self, age, x, y): print('render a tree of type {} and age {} at ({}, {})'.format(self.tree_type, age, x, y)) # main()函数展示了我们可以如何使用享元模式。一棵树的年龄是1到30年之间的一个随机值。 # 坐标使用1到100之间的随机值。虽然渲染了18棵树,但仅分配了3棵树的内存。 # 输出的最后一行证明当使用享元时,我们不能依赖对象的ID。函数id()会返回对象的内存地址。 # Python规范并没有要求id()返回对象的内存地址,只是要求id()为每个对象返回一个唯一性ID, # 不过CPython(Python的官方实现)正好使用对象的内存地址作为对象唯一性ID。 # 在我们的例子中,即使两个对象看起来不相同,但是如果它们属于同一个享元家族(在这里,家族由tree_type定义),那么它们实际上有相同的ID。 # 当然,不同ID的比较仍然可用于不同家族的对象,但这仅在客户端知道实现细节的情况下才可行(通常并非如此)。 def main(): rnd = random.Random() age_min, age_max = 1, 30 # 单位为年 min_point, max_point = 0, 100 tree_counter = 0 for _ in range(10): t1 = Tree(TreeType.apple_tree) t1.render(rnd.randint(age_min, age_max), rnd.randint(min_point, max_point), rnd.randint(min_point, max_point)) tree_counter += 1 for _ in range(3): t2 = Tree(TreeType.cherry_tree) t2.render(rnd.randint(age_min, age_max), rnd.randint(min_point, max_point), rnd.randint(min_point, max_point)) tree_counter += 1 for _ in range(5): t3 = Tree(TreeType.peach_tree) t3.render(rnd.randint(age_min, age_max), rnd.randint(min_point, max_point), rnd.randint(min_point, max_point)) tree_counter += 1 print('trees rendered: {}'.format(tree_counter)) print('trees actually created: {}'.format(len(Tree.pool))) t4 = Tree(TreeType.cherry_tree) t5 = Tree(TreeType.cherry_tree) t6 = Tree(TreeType.apple_tree) print('{} == {}? {}'.format(id(t4), id(t5), id(t4) == id(t5))) print('{} == {}? {}'.format(id(t5), id(t6), id(t5) == id(t6))) if __name__ == '__main__': main()
# 外部模块:external.py class Synthesizer: def __init__(self, name): self.name = name def __str__(self): return 'the {} synthesizer'.format(self.name) def play(self): return 'is playing an electronic song' class Human: def __init__(self, name): self.name = name def __str__(self): return '{} the human'.format(self.name) def speak(self): return 'says hello' # 自己的代码adapter.py from external import Synthesizer, Human class Computer: def __init__(self, name): self.name = name def __str__(self): return 'the {} computer'.format(self.name) def execute(self): return 'executes a program' # 客户端仅知道如何调用execute()方法,并不知道play() 4 和speak()。 # 在不改变Synthesizer和Human类的前提下,我们该如何做才能让代码有效?适配器是救星! # 我们创建一个通用的Adapter类,将一些带不同接口的对象适配到一个统一接口中。 # __init__()方法的obj参数是我们想要适配的对象,adapted_methods是一个字典,键值对中的键是客户端要调用的方法,值是应该被调用的方法。 class Adapter: def __init__(self, obj, adapted_methods): self.obj = obj self.__dict__.update(adapted_methods) def __str__(self): return str(self.obj) def main(): objects = [Computer('Asus')] synth = Synthesizer('moog') objects.append(Adapter(synth, dict(execute=synth.play))) human = Human('Bob') objects.append(Adapter(human, dict(execute=human.speak))) for i in objects: print('{} {}'.format(str(i), i.execute())) if __name__ == "__main__": main()
简便记忆:观察者命令解释器将责任链、状态机做成策略模板
# 基类Publisher,包括添加、删除及通知观察者这些公用功能。 # 观察者们保存在列表observers中。add()方法注册一个新的观察者,或者在该观察者已存在时引发一个错误。 # remove()方法注销一个已有观察者,或者在该观察者尚未存在时引发一个错误。 # 最后,notify()方法则在变化发生时通知所有观察者。 class Publisher: def __init__(self): self.observers = [] def add(self, observer): if observer not in self.observers: self.observers.append(observer) else: print('Failed to add: {}'.format(observer)) def remove(self, observer): try: self.observers.remove(observer) except ValueError: print('Failed to remove: {}'.format(observer)) def notify(self): [o.exec(self) for o in self.observers] # efaultFormatter类继承自Publisher,并添加格式化程序特定的功能。 class DefaultFormatter(Publisher): # __init__()做的第一件事情就是调用基类的__init__()方法 # DefaultFormatter实例有自己的名字,这样便于我们跟踪其状态。 def __init__(self, name): Publisher.__init__(self) self.name = name self._data = 0 # __str__()方法返回关于发布者名称和_data值的信息。 # type(self).__name是一种获取类名的方便技巧,避免硬编码类名。 def __str__(self): return "{}: '{}' has data = {}".format(type(self).__name__, self.name, self._data) # @property修饰器来提供_data变量的读访问方式。这样,我们就能使用object.data来替代object.data()。 @property def data(self): return self._data # @setter该修饰器会在每次使用赋值操作符(=)为_data变量赋新值时被调用。 @data.setter def data(self, new_value): try: self._data = int(new_value) except ValueError as e: print('Error: {}'.format(e)) else: self.notify() # 两个观察者:HexFormatter和BinaryFormatter的功能非常相似。 # 唯一的不同在于如何格式化从发布者那获取到的数据值,即分别以十六进制和二进制进行格式化。 class HexFormatter: def exec(self, publisher): print("{}: '{}' has now hex data = {}".format(type(self).__name__, publisher.name, hex(publisher.data))) class BinaryFormatter: def exec(self, publisher): print("{}: '{}' has now bin data = {}".format(type(self).__name__, publisher.name, bin(publisher.data))) def main(): df = DefaultFormatter('test1') print(df) print() hf = HexFormatter() df.add(hf) df.data = 3 print(df) print() bf = BinaryFormatter() df.add(bf) df.data = 21 print(df) print() df.remove(hf) df.data = 40 print(df) print() df.remove(hf) df.add(bf) df.data = 'hello' print(df) print() df.data = 15.8 print(df) if __name__ == '__main__': main()
import os verbose = True # 文件改名 class RenameFile: def __init__(self, path_src, path_dest): self.src, self.dest = path_src, path_dest def execute(self): if verbose: print("[renaming '{}' to '{}']".format(self.src, self.dest)) os.rename(self.src, self.dest) def undo(self): if verbose: print("[renaming '{}' back to '{}']".format(self.dest, self.src)) os.rename(self.dest, self.src) # 创建文件 class CreateFile: def __init__(self, path, txt='hello world\n'): self.path, self.txt = path, txt def execute(self): if verbose: print("[creating file '{}']".format(self.path)) with open(self.path, mode='w', encoding='utf-8') as out_file: out_file.write(self.txt) def undo(self): delete_file(self.path) # 读取文件不支持回滚 class ReadFile: def __init__(self, path): self.path = path def execute(self): if verbose: print("[reading file '{}']".format(self.path)) with open(self.path, mode='r', encoding='utf-8') as in_file: print(in_file.read(), end='') # 删除文件也不支持回滚 def delete_file(path): if verbose: print("deleting file '{}'".format(path)) os.remove(path) def main(): orig_name, new_name = 'file1', 'file2' commands = [] for cmd in CreateFile(orig_name), ReadFile(orig_name), RenameFile(orig_name, new_name): commands.append(cmd) [c.execute() for c in commands] answer = input('reverse the executed commands? [y/n] ') if answer not in 'yY': print("the result is {}".format(new_name)) exit() for c in reversed(commands): try: c.undo() except AttributeError as e: pass if __name__ == '__main__': main()
# coding: utf-8 """ 创建一种内部DSL控制一个智能屋 一个事件的形式为command -> receiver -> arguments。参数部分是可选的。 并不是所有事件都要求参数。不要求任何参数的事件例子如下所示。 open -> gate ->符号用于标记事件一个部分的结束,并声明下一个部分的开始。 Pyparsing是python中的一个模块 使用巴科斯-诺尔形式(Backus-Naur Form,BNF)表示法来定义语法 event ::= command token receiver token arguments command ::= word+ word ::= a collection of one or more alphanumeric characters token ::= -> receiver ::= word+ arguments ::= word+ 实际的代码: word = Word(alphanums) command = Group(OneOrMore(word)) token = Suppress("->") device = Group(OneOrMore(word)) argument = Group(OneOrMore(word)) event = command + token + device + Optional(token + argument) """ from pyparsing import Word, OneOrMore, Optional, Group, Suppress, alphanums class Gate: def __init__(self): self.is_open = False def __str__(self): return 'open' if self.is_open else 'closed' def open(self): print('opening the gate') self.is_open = True def close(self): print('closing the gate') self.is_open = False class Garage: def __init__(self): self.is_open = False def __str__(self): return 'open' if self.is_open else 'closed' def open(self): print('opening the garage') self.is_open = True def close(self): print('closing the garage') self.is_open = False class Aircondition: def __init__(self): self.is_on = False def __str__(self): return 'on' if self.is_on else 'off' def turn_on(self): print('turning on the aircondition') self.is_on = True def turn_off(self): print('turning off the aircondition') self.is_on = False class Heating: def __init__(self): self.is_on = False def __str__(self): return 'on' if self.is_on else 'off' def turn_on(self): print('turning on the heating') self.is_on = True def turn_off(self): print('turning off the heating') self.is_on = False class Boiler: def __init__(self): self.temperature = 83 # in celsius def __str__(self): return 'boiler temperature: {}'.format(self.temperature) def increase_temperature(self, amount): print("increasing the boiler's temperature by {} degrees".format(amount)) self.temperature += amount def decrease_temperature(self, amount): print("decreasing the boiler's temperature by {} degrees".format(amount)) self.temperature -= amount class Fridge: def __init__(self): self.temperature = 2 # 单位为摄氏度 def __str__(self): return 'fridge temperature: {}'.format(self.temperature) def increase_temperature(self, amount): print("increasing the fridge's temperature by {} degrees".format(amount)) self.temperature += amount def decrease_temperature(self, amount): print("decreasing the fridge's temperature by {} degrees".format(amount)) self.temperature -= amount def main(): word = Word(alphanums) command = Group(OneOrMore(word)) token = Suppress("->") device = Group(OneOrMore(word)) argument = Group(OneOrMore(word)) event = command + token + device + Optional(token + argument) gate = Gate() garage = Garage() airco = Aircondition() heating = Heating() boiler = Boiler() fridge = Fridge() tests = ('open -> gate', 'close -> garage', 'turn on -> aircondition', 'turn off -> heating', 'increase -> boiler temperature -> 5 degrees', 'decrease -> fridge temperature -> 2 degrees') open_actions = {'gate': gate.open, 'garage': garage.open, 'aircondition': airco.turn_on, 'heating': heating.turn_on, 'boiler temperature': boiler.increase_temperature, 'fridge temperature': fridge.increase_temperature} close_actions = {'gate': gate.close, 'garage': garage.close, 'aircondition': airco.turn_off, 'heating': heating.turn_off, 'boiler temperature': boiler.decrease_temperature, 'fridge temperature': fridge.decrease_temperature} """ 获取Pyparsing解析结果的最简单方式是使用parseString()方法,该方法返回的结果是一 个ParseResults实例,它实际上是一个可视为嵌套列表的解析树。例如,执行print(event. parseString('increase -> boiler temperature -> 3 degrees'))得到的结果如下所示。 [['increase'], ['boiler', 'temperature'], ['3', 'degrees']] """ for t in tests: if len(event.parseString(t)) == 2: # 没有参数 cmd, dev = event.parseString(t) cmd_str, dev_str = ' '.join(cmd), ' '.join(dev) if 'open' in cmd_str or 'turn on' in cmd_str: open_actions[dev_str]() elif 'close' in cmd_str or 'turn off' in cmd_str: close_actions[dev_str]() elif len(event.parseString(t)) == 3: # 有参数 cmd, dev, arg = event.parseString(t) cmd_str, dev_str, arg_str = ' '.join(cmd), ' '.join(dev), ' '.join(arg) num_arg = 0 try: num_arg = int(arg_str.split()[0]) # 抽取数值部分 except ValueError as err: print("expected number but got: '{}'".format(arg_str[0])) if 'increase' in cmd_str and num_arg > 0: open_actions[dev_str](num_arg) elif 'decrease' in cmd_str and num_arg > 0: close_actions[dev_str](num_arg) if __name__ == '__main__': main()
#!/usr/bin/python #coding:utf8 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()
from state_machine import State, Event, acts_as_state_machine, after, before, InvalidStateTransition @acts_as_state_machine class Process: created = State(initial=True) waiting = State() running = State() terminated = State() blocked = State() swapped_out_waiting = State() swapped_out_blocked = State() wait = Event(from_states=(created, running, blocked, swapped_out_waiting), to_state=waiting) run = Event(from_states=waiting, to_state=running) terminate = Event(from_states=running, to_state=terminated) block = Event(from_states=(running, swapped_out_blocked), to_state=blocked) swap_wait = Event(from_states=waiting, to_state=swapped_out_waiting) swap_block = Event(from_states=blocked, to_state=swapped_out_blocked) def __init__(self, name): self.name = name @after('wait') def wait_info(self): print('{} entered waiting mode'.format(self.name)) @after('run') def run_info(self): print('{} is running'.format(self.name)) @before('terminate') def terminate_info(self): print('{} terminated'.format(self.name)) @after('block') def block_info(self): print('{} is blocked'.format(self.name)) @after('swap_wait') def swap_wait_info(self): print('{} is swapped out and waiting'.format(self.name)) @after('swap_block') def swap_block_info(self): print('{} is swapped out and blocked'.format(self.name)) def transition(process, event, event_name): try: event() except InvalidStateTransition as err: print('Error: transition of {} from {} to {} failed'.format(process.name, process.current_state, event_name)) def state_info(process): print('state of {}: {}'.format(process.name, process.current_state)) def main(): RUNNING = 'running' WAITING = 'waiting' BLOCKED = 'blocked' TERMINATED = 'terminated' p1, p2 = Process('process1'), Process('process2') [state_info(p) for p in (p1, p2)] print() transition(p1, p1.wait, WAITING) transition(p2, p2.terminate, TERMINATED) [state_info(p) for p in (p1, p2)] print() transition(p1, p1.run, RUNNING) transition(p2, p2.wait, WAITING) [state_info(p) for p in (p1, p2)] print() transition(p2, p2.run, RUNNING) [state_info(p) for p in (p1, p2)] print() [transition(p, p.block, BLOCKED) for p in (p1, p2)] [state_info(p) for p in (p1, p2)] print() [transition(p, p.terminate, TERMINATED) for p in (p1, p2)] [state_info(p) for p in (p1, p2)] if __name__ == '__main__': main()
""" The state pattern allows us to change an object's behavior at runtime — something that Python naturally excels at! This example has a very simple radio. It has an AM/FM toggle switch, and a scan button to scan to the next station. """ 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 radio = Radio() actions = [radio.scan] * 2 + [radio.toggle_amfm] + [radio.scan] * 2 actions = actions * 2 for action in actions: action()
# coding: utf-8 # 检测一个字符串中所有的字符串是否都是唯一的 import time SLOW = 3 # 单位为秒 LIMIT = 5 # 字符数 WARNING = 'too bad, you picked the slow algorithm :(' def pairs(seq): n = len(seq) for i in range(n): yield seq[i], seq[(i + 1) % n] # 方法一:排序,然后判断相邻两个元素是否相等 def allUniqueSort(s): if len(s) > LIMIT: print(WARNING) time.sleep(SLOW) srtStr = sorted(s) for (c1, c2) in pairs(srtStr): if c1 == c2: return False return True # 方法二:利用python中的集合来处理 def allUniqueSet(s): if len(s) < LIMIT: print(WARNING) time.sleep(SLOW) return True if len(set(s)) == len(s) else False def allUnique(s, strategy): return strategy(s) def main(): while True: word = None while not word: word = input('Insert word (type quit to exit)> ') if word == 'quit': print('bye') return strategy_picked = None strategies = {'1': allUniqueSet, '2': allUniqueSort} while strategy_picked not in strategies.keys(): strategy_picked = input('Choose strategy: [1] Use a set, [2] Sort and pair> ') try: strategy = strategies[strategy_picked] print('allUnique({}): {}'.format(word, allUnique(word, strategy))) except KeyError as err: print('Incorrect option: {}'.format(strategy_picked)) if __name__ == '__main__': main()
""" 将一段文本发送给一个函数,该函数要生成一个包含该文本的横幅。 横幅有多种风格,比如点或虚线围绕文本。横幅生成器有一个默认风格, 但应该能够使用我们自己提供的风格。 """ from cowpy import cow def dots_style(msg): msg = msg.capitalize() msg = '.' * 10 + msg + '.' * 10 return msg def admire_style(msg): msg = msg.upper() return '!'.join(msg) def cow_style(msg): msg = cow.milk_random_cow(msg) return msg def generate_banner(msg, style=dots_style): print('-- start of banner --') print(style(msg)) print('-- end of banner --\n\n') def main(): msg = 'happy coding' [generate_banner(msg, style) for style in (dots_style, admire_style, cow_style)] if __name__ == '__main__': main()
参考:
《精通python设计模式》
《二十三种设计模式及其python实现》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。