8

有没有比使用全局变量从上下文管理器获取有趣值更好的方法?

@contextmanager
def transaction():
    global successCount
    global errorCount
    try:
        yield
    except:
        storage.store.rollback()
        errorCount += 1
    else:
        storage.store.commit()
        successCount += 1

其他可能性:

  • 单身人士

    某种全球性的...

  • 元组作为上下文管理器的参数

    使功能更具体地解决问题/减少可重用性

  • 将特定属性作为上下文管理器的参数保存的实例

    与元组相同的问题,但更易读

  • 在保存值的上下文管理器末尾引发异常。

    真是个坏主意

4

3 回答 3

9

请参阅http://docs.python.org/reference/datamodel.html#context-managers

创建一个包含成功和错误计数并实现__enter____exit__方法的类。

于 2009-05-18T13:31:38.547 回答
5

我仍然认为您应该创建一个类来保存错误/成功计数,正如我在上一个问题中所说的那样。我猜你有自己的课程,所以只需添加这样的内容:

class transaction:
    def __init__(self):
        self.errorCount = 0
        self.successCount = 0  

    def __enter__(*args):
        pass  

    def __exit__(self, type, value, traceback):
        if type:
            storage.store.rollback()
            self.errorCount += 1
        else:
            storage.store.commit()
            self.successCount += 1

type如果在调用 时没有异常,则为 None contextmanager

然后您可能已经在某处使用它,它将调用contextmanager并运行您的__exit__()代码。 编辑:正如 Eli 评论的那样,仅当您想要重置 coutners 时才创建一个新的事务实例。

t = transaction()
for q in queries:
    with t:
        t.execute(q)
于 2009-05-18T13:49:53.940 回答
0

"元组作为上下文管理器的参数

使功能更具体地解决问题/减少可重用性”

错误的。

这使得上下文管理器保持状态。

如果你没有实现更多的东西,它将是可重用的。

但是,您实际上不能使用元组,因为它是不可变的。你需要一些可变的集合。我想到了字典和类定义。

因此,推荐的实现是

“将特定属性作为上下文管理器的参数保存的实例”

您只需要一个具有两个属性的简单类定义。但是,您的交易状态是有状态的,您需要在某处保留状态。

class Counters(dict):
    SUCCEED= 0
    FAIL= 1
    def __init__( self ):
        self[ self.SUCCEED ]= 0
        self[ self.FAIL ]= 0 
    def increment( self, status ):
        self[status] += 1

class Transaction(object):
    def __init__( self, worker, counters ):
        self.worker= worker
        self.counters= counters
    def __enter__( self ):
        self.counters.status= None
    def process( self, *args, **kw ):
        status= self.worker.execute( *args, **kw )
        self.counters.increment( status )
    def __exit__( self ):
        pass

counts= Counters()
for q in queryList:
    with Transaction(execQuery,counts) as t:
        t.process( q )
print counts
于 2009-05-18T14:21:02.427 回答