我应该如何从with语句中返回有趣的值?

问题描述 投票:4回答:3

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

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

其他可能性:

  • 单身 有点全局...
  • 元组作为上下文管理器的参数 使功能更加特定于问题/更少可重用
  • 将特定属性作为参数保存到上下文管理器的实例 与元组相同的问题,但更清晰
  • 在保存值的上下文管理器的末尾引发异常。 真的很糟糕
python with-statement contextmanager
3个回答
7
投票

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

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


3
投票

我仍然认为你应该创建一个课程来控制你的错误/成功,就像我在你说的那样last question。我猜你有自己的类,所以只需添加这样的东西:

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时没有例外,则contextmanager为None)

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

t = transaction()
for q in queries:
    with t:
        t.execute(q)

-1
投票

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

使功能更具体的问题/更少的可重用“

假。

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

如果您没有实现任何更多,它将是可重用的。

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

因此,建议的实施是

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

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

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
© www.soinside.com 2019 - 2024. All rights reserved.