Как мне вернуть интересные значения из оператора with?
-
22-08-2019 - |
Вопрос
Есть ли лучший способ получить интересные значения от менеджера контекста, чем использование глобальных переменных?
@contextmanager
def transaction():
global successCount
global errorCount
try:
yield
except:
storage.store.rollback()
errorCount += 1
else:
storage.store.commit()
successCount += 1
Другие возможности:
одиночки
какие-то глобалы...
кортеж в качестве аргумента контекстного менеджера
делает функцию более специфичной для проблемы/менее многоразовой
экземпляр, который содержит определенные атрибуты в качестве аргумента для менеджера контекста
те же проблемы, что и кортеж, но более разборчиво
вызвать исключение в конце контекстного менеджера, содержащего значения.
действительно плохая идея
Решение
Видеть http://docs.python.org/reference/datamodel.html#context-managers
Создайте класс, который хранит счетчики успехов и ошибок и реализует __enter__
и __exit__
методы.
Другие советы
Я все еще думаю, что вам следует создать класс для хранения подсчета ошибок/успехов, как я уже сказал у вас. последний вопрос.Я предполагаю, что у вас есть свой собственный класс, поэтому просто добавьте к нему что-то вроде этого:
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
имеет значение None, если при вызове нет исключений. contextmanager
)
И тогда вы, вероятно, уже где-то используете это, что вызовет contextmanager
и запусти свой __exit__()
код. Редактировать: Как прокомментировал Эли, создавайте новый экземпляр транзакции только тогда, когда вы хотите сбросить счетчики.
t = transaction()
for q in queries:
with t:
t.execute(q)
"кортеж как аргумент контекстному менеджеру
делает функцию более специфичной для проблемы/менее многоразовой"
ЛОЖЬ.
Это заставляет контекстный менеджер сохранять состояние.
Если вы не реализуете ничего большего, чем это, его можно будет использовать повторно.
Однако на самом деле вы не можете использовать кортеж, поскольку он неизменяем.Вам нужна изменяемая коллекция.На ум приходят словари и определения классов.
Следовательно, рекомендуемая реализация
«экземпляр, который содержит определенные атрибуты в качестве аргумента для менеджера контекста»
Все, что вам нужно, — это простое определение класса с двумя атрибутами.Однако статус вашей транзакции имеет состояние, и вам нужно где-то его сохранять.
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