如何在 'with' 语句中包装静态 class(来自 .NET)

How to wrap a static class (from .NET) in a 'with' statement

我正在尝试用漂亮的 pythonic 包装器包装一个 .NET 库,以便在 IronPython 中使用。

这个库中经常使用的模式是 PersistenceBlock,它使数据库 CRUD 操作变得干净 'all or nothing':

try:
  Persistence.BeginNewTransaction()
  # do stuff here
  Persistence.CommitTransaction()
except Exception, e:
  Persistence.AbortTransaction()
  Log.Error(e)
finally:
  Persistence.CloseTransaction()

我想将其包装在允许此类代码的 class 中:

with PersistenceBlock:
  # do stuff here

这是我想出的:

class PersistenceBlock():
  def __init__(self):

  def __enter__(self):
    return self

  def __exit__(self, exctype, excinst, exctb):
    try:
      Persistence.BeginNewTransaction()
      yield
      Persistence.CommitTransaction()
    except:
      Persistence.AbortTransaction()
      Log.Error(e)
    finally
      Persistence.CloseTransaction()

这是 PEP343 的正确实现吗?我可能会错过什么?

让我感到困惑的主要是 Persistence 是一个静态的 .NET class,因此没有 'instance' 正常意义上的管理。

我试过搜索,但是'with'这个词压倒了结果:(

您可以通过搜索 context manager 协议找到文档 - 这是应该与 with 语句一起使用的所有对象都应该实现的协议。

上下文管理器(即 __enter__ 方法)不需要 return 任何东西 - 仅当您想使用 with ... as ... 语法时。在您的 __exit__ 方法中,您必须进行一些适当的错误检查:如果有异常则重新引发异常,如果没有则提交。可能是这样的:

class PersistenceContext():

    def __enter__(self):
        # when opening the block, open a transaction
        Persistence.BeginNewTransaction()

    def __exit__(self, exctype, excinst, exctb):      
        if excinst is None:
            # all went well - commit & close
            Persistence.CommitTransaction()
            Persistence.CloseTransaction()
        else:
            # something went wrong - abort, close and raise the error
            Persistence.AbortTransaction() 
            Persistence.CloseTransaction()
            raise exctype, excinst, exctb

为了完整起见,您还可以使用 contextmanager 装饰器通过一个简单的生成器来实现您的上下文:

import contextlib

@contextlib.contextmanager     
def PersisenceContext():

    try:
        yield Persistence.BeginNewTransaction()
    except Exception:
        Persistence.AbortTransaction()
        raise
    else:
        Persistence.CommitTransaction()
    finally:
        Persistence.CloseTransaction()