有時,咱們須要原本來本地爲對象建立一個副本。舉例來講,假設你想建立一個應用來存儲、
分享、編輯(好比,修改、添加註釋及刪除)食譜。用戶Bob找到一份蛋糕食譜,在作了一些改
變後,以爲本身作的蛋糕很是美味,想要與朋友Alice分享這個食譜。可是該如何分享食譜呢?如
果在與Alice分享以後,Bob想對食譜作進一步的試驗,Alice手裏的食譜也能跟着變化嗎?Bob能
夠持有蛋糕食譜的兩個副本嗎?對蛋糕食譜進行的試驗性變動不該該對本來美味蛋糕的食譜造
成影響。
這樣的問題能夠經過讓用戶對同一份食譜持有多個獨立的副原本解決。每一個副本被稱爲一個
克隆,是某個時間點原有對象的一個徹底副本。這裏時間是一個重要因素。由於它會影響克隆所
包含的內容。例如,若是Bob在對蛋糕食譜作改進以臻完美以前就與Alice分享了,那麼Alice就絕
不可能像Bob那樣烘烤出本身的美味蛋糕,只能按照Bob原來找到的食譜烘烤蛋糕。
注意引用與副本之間的區別。若是Bob和Alice持有的是同一個蛋糕食譜對象的兩個引用,那
麼Bob對食譜作的任何改變,對於Alice的食譜版本都是可見的,反之亦然。咱們想要的是Bob和
Alice各自持有本身的副本,這樣他們能夠各自作變動而不會影響對方的食譜。實際上Bob須要蛋
糕食譜的兩個副本:美味版本和試驗版本。app
# coding: utf-8 import copy from collections import OrderedDict class Book: def __init__(self, name, authors, price, **rest): '''rest的例子有:出版商,長度,標籤,出版日期''' self.name = name self.authors = authors self.price = price # 單位爲美圓 self.__dict__.update(rest) 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) 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()