2

我正在尝试改进(如果可能的话)下面的 DataContext 类或找到替代解决方案:

class Store(object):

    def __init__( self, contents=None):
        self.contents = contents

class DataContext(object):

    def __init__( self, datastore ) : # datastore is of type store
        self.store = datastore

    def __enter__( self ) :
        self.temp_store = copy.copy( self.store.contents )  # Improve upon this!

    def __exit__( self, type, value, traceback ) :
        self.store.contents = self.temp_store

示例用法:

data = Store( [1,2,3] )
print "Before context: ", data.contents
with DataContext( data ):
    data.contents.append( 4 )         # Tampering with the data 
    print "Within context: ", data.contents

print "Outside context: ", data.contents

输出:

Before context:  [1, 2, 3]
Within context:  [1, 2, 3, 4]
Outside context:  [1, 2, 3]

copy对于大型数据结构来说,这可能很昂贵。什么是(或是否有)一种干净的方法来仅将更改存储在上下文中的数据结构中,然后在 期间撤消对数据的这些特定更改exit

4

2 回答 2

1

您可以使用某种检查点。例如,您可以保留一个单独的结构,您可以在其中插入新元素。当您退出上下文时,您需要从容器中删除这些新元素。

显然,与进行深度合作相比,这是否值得取决于几个因素,例如:

  1. 底层容器。并非所有的 API 都具有相同的 API,因此您需要针对不同的受支持容器类型专门化检查点机制(这可能不是微不足道的)。
  2. 进入上下文之前的元素与在上下文中插入的元素数量的比率是多少。

此外,就正确性而言,容器的类型也会影响这种机制的设计。例如,如果容器是一个列表,则需要删除在上下文中插入的所有元素。另一方面,如果容器是一个集合,您只需在它们最初不存在的情况下移除它们。

为简单起见,假设您只对列表感兴趣并且只支持append操作,那么一个可能的解决方案实际上非常简单:

类数据上下文(对象):

def __init__( self, datastore ) : # datastore is of type store
    self.store = datastore
    self.num_added = 0

def __enter__( self ) :
    pass

def __exit__( self, type, value, traceback ) :
    l = len(self.store.contents)
    del self.store.contents[l - self.num_added : l]

def append( self, elem ) :
    self.store.contents.append(elem)
    self.num_added += 1

绝对这是一个非常简单的案例,只是为了添加对从列表中任何位置删除元素的支持,您需要保留对列表执行的操作的某种日志。日志可以是指定操作类型(插入、删除)及其参数(例如,索引、数据)的条目列表。此外,如果您想支持所有列表操作,您将需要使用代理或包装器来拦截列表上的每个修改操作(例如,appendextendinsert、等)。remove

如果您想要更通用并且不仅支持列表而且支持其他类型的容器,那么您将需要用于不同容器操作的包装器。例如,因为set您需要支持addremoveupdateintersection_update等。为此,您可以创建一个类层次结构,该层次结构从DataContext每个类型的专用操作下降。

无论如何,正如您所看到的,实现它的复杂性会显着增加,具体取决于您想要成为多少通用性。因此,如果您只是想要一个为列表量身定制的特定解决方案,那么实施它可能会有所回报,否则最好付出执行容器副本的代价。

于 2012-05-24T22:32:35.427 回答
0

您可以Store使用数据库作为底层存储来实现,并且只需ROLLBACK.

于 2012-05-25T06:52:56.943 回答