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
真的很糟糕
3 个解决方案
#1
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.
创建一个包含成功和错误计数的类,并实现__enter__和__exit__方法。
#2
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
)
(如果在调用contextmanager后没有异常,则type为None)
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.
然后你可能已经在某处使用了它,它将调用contextmanager并运行你的__exit __()代码。编辑:正如Eli评论的那样,只有在您想要重置coutner时才创建新的事务实例。
t = transaction()
for q in queries:
with t:
t.execute(q)
#3
"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
#1
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.
创建一个包含成功和错误计数的类,并实现__enter__和__exit__方法。
#2
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
)
(如果在调用contextmanager后没有异常,则type为None)
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.
然后你可能已经在某处使用了它,它将调用contextmanager并运行你的__exit __()代码。编辑:正如Eli评论的那样,只有在您想要重置coutner时才创建新的事务实例。
t = transaction()
for q in queries:
with t:
t.execute(q)
#3
"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