代码之家  ›  专栏  ›  技术社区  ›  Georg Schölly Crazy Developer

如何从WITH语句返回有趣的值?

  •  3
  • Georg Schölly Crazy Developer  · 技术社区  · 16 年前

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

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

    其他可能性:

    • 独生子女

      有点全局…

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

      使函数更特定于问题/可重用性更低

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

      与元组的问题相同,但更清晰

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

      真是馊主意

    3 回复  |  直到 7 年前
        1
  •  7
  •   Jonas Kölker    16 年前

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

    创建一个类,该类保存成功和错误计数,并实现 __enter__ __exit__ 方法。

        2
  •  3
  •   UtsavShah    7 年前

    我仍然认为你应该创建一个类来记录你的错误/成功,就像我在你里面说的那样。 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 )

    然后您可能已经在某个地方使用了它,它将调用 上下文管理器 运行你的 __exit__() 代码。 编辑: 正如Eli所评论的,只有在您想要重置coutner时才创建一个新的事务实例。

    t = transaction()
    for q in queries:
        with t:
            t.execute(q)
    
        3
  •  -1
  •   S.Lott    16 年前

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

    使函数更特定于问题/更不可重用”

    错误的。

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

    如果您不实现更多的东西,它将是可重用的。

    但是,实际上不能使用元组,因为它是不可变的。你需要一些易变的收藏。字典和类定义浮现在脑海中。

    因此,建议的实施是

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

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

    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