2016-04-28 81 views
2

我有很多类(例如联系人),我也希望跟踪更改历史记录。以下是我的出发点。我想这是一个常见的使用案例,所以我会欣赏这里最佳实践的指导。这会是一个使用多重继承的好地方,那会是什么样子?Python继承“对象历史”的最佳实践

from datetime import date 

class ContactHistory(object): 
    def __init__(self, contact, change_action, change_user_id, change_source): 
     self.name = contact.name 
     self.phone = contact.phone 
     self.email = contact.email 
     self.change_action = change_action 
     self.change_user_id = change_user_id 
     self.change_source = change_source 
     self.change_date = date.today() 

    def __repr__(self): 
     return '%s, %s, %s, %s, %s, %s, %s' % (self.name, self.email, self.phone, self.change_action, self.change_user_id, self.change_source, self.change_date) 

class Contact(object): 
    def __init__(self, name, phone, email, change_user_id, change_source): 
     self.name = name 
     self.phone = phone 
     self.email = email 
     self.history = []  
     self.history.append(ContactHistory(self, 'created', change_user_id, change_source)) 

    def update_phone(self, phone, change_user_id, change_source): 
     self.phone = phone 
     self.history.append(ContactHistory(self, 'phone updated', change_user_id, change_source)) 

    def get_history(self): 
     return self.history 

contact = Contact('Bill', '214-555-1212', 'me', 'admin page') 
contact.update('972-555-1212', 'me', 'contact management page') 
print contact.get_history() 
+1

可能http://stackoverflow.com/questions/8858525/track-changes-to-lists-and-dictionaries-in-python是有趣的。 – larsks

+0

这个链接上有好东西@larsks ... @JackOfAll,也许你想查找'备忘录模式'?这不是你想要的直接,但也许你会从中得到一些新的想法? –

回答

1

这里有一种方法可以使用继承来解决这个问题。 ChangeableObject可以通过向可改变的是所需要的任何对象被继承,与该对象只是描述了用于创建一个浅克隆为历史的参数:

from collections import namedtuple 

Change = namedtuple("Change", ("old", "new", "action")) 

class History(object): 
    def __init__(self): 
     self.history = [] 

    def save_change(self, old, new, action): 
     change = Change(old, new, action) 
     self.history.append(change) 

    def get_history(self): 
     return self.history 

class ChangeableObject(object): 
    def __init__(self, make_history=True): 
     if make_history: 
      self.history = History() 
      self.history.save_change(None, self, "created") 
     self.cloneable_attributes =() 

    @classmethod 
    def get_clone(cls, obj): 
     attrs = {attr: getattr(obj, attr) for attr in obj.cloneable_attributes} 
     return cls(make_history=False, **attrs) 

    def view_history(self): 
     return self.history.get_history() 

class Contact(ChangeableObject): 
    def __init__(self, name, phone, email, make_history=True): 
     super(Contact, self).__init__(make_history=make_history) 
     self.name = name 
     self.phone = phone 
     self.email = email 
     self.cloneable_attributes = ("name", "phone", "email") 

    def update_phone(self, phone): 
     clone = self.get_clone(self) 
     self.phone = phone 
     self.history.save_change(clone, self, "phone updated") 

    def __repr__(self): 
     return "{} {} {}".format(self.name, self.phone, self.email) 

随着示例代码:

c = Contact("me", "123-123-123", "[email protected]") 
c.update_phone("456-456-456") 
print c 
for i, hist in enumerate(c.view_history()): 
    print "{}. {}".format(i, hist) 

输出:

me 456-456-456 [email protected] 
0. Change(old=None, new=me 456-456-456 [email protected], action='created') 
1. Change(old=me 123-123-123 [email protected], new=me 456-456-456 [email protected], action='phone updated') 
+0

谢谢!这非常有帮助。 – JackOfAll