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

发布于 2024-07-20 07:19:12 字数 556 浏览 6 评论 0原文

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

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

其他可能性:

  • 单例

    某种全局变量...

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

    使函数更具体地针对问题/更少可重用

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

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

  • 在上下文末尾引发异常持有价值观的经理。

    真是个坏主意

Is there a better way than using globals to get interesting values from a context manager?

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

Other possibilities:

  • singletons

    sort of globals...

  • tuple as an argument to the context manager

    makes the function more specific to a problem /less reusable

  • instance that holds the specific attributes as an argument to the context manager

    same problems as the tuple, but more legible

  • raise an exception at the end of the context manager holding the values.

    really bad idea

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

注定孤独终老 2024-07-27 07:19:12

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

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

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

Create a class which holds the success and error counts, and which implements the __enter__ and __exit__ methods.

童话里做英雄 2024-07-27 07:19:12

我仍然认为您应该创建一个类来保存错误/成功计数,正如我在您中所说的 最后一个问题。 我猜你有自己的类,所以只需向其中添加类似的内容:(

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

如果调用 contextmanager 后没有异常,则 type 为 None)

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

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

I still think you should be creating a class to hold you error/success counts, as I said in you last question. I'm guessing you have your own class, so just add something like this to it:

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 is None if there are no exceptions once invoking the contextmanager)

And then you probably are already using this somewhere, which will invoke the contextmanager and run your __exit__() code. Edit: As Eli commented, only create a new transaction instance when you want to reset the coutners.

t = transaction()
for q in queries:
    with t:
        t.execute(q)
一抹淡然 2024-07-27 07:19:12

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

使函数更具体地解决问题/更少可重用”

错误。

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

如果您不实现除此之外的任何内容,它将是可重用的。

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

因此,推荐的实现是

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

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

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

"tuple as an argument to the context manager

makes the function more specific to a problem /less reusable"

False.

This makes the context manager retain state.

If you don't implement anything more than this, it will be reusable.

However, you can't actually use a tuple because it's immutable. You need some mutable collection. Dictionaries and class definitions come to mind.

Consequently, the recommended implementation is

"instance that holds the specific attributes as an argument to the context manager"

A simple class definition with two attributes is all you need. However, your transaction status is stateful and you need to retain state somewhere.

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文