Como devo retornar valores interessantes de um com-afirmação?
-
22-08-2019 - |
Pergunta
Existe uma maneira melhor do que usar globals para obter valores interessantes de um gerente de contexto?
@contextmanager
def transaction():
global successCount
global errorCount
try:
yield
except:
storage.store.rollback()
errorCount += 1
else:
storage.store.commit()
successCount += 1
Outras possibilidades:
-
singletons
tipo de globals ...
-
tupla como um argumento para o gerente de contexto
faz a função mais específica para um problema / menos reutilizável
-
instância que detém os atributos específicos como um argumento para o gerente de contexto
mesmos problemas que a tupla, mas mais legível
-
gerar uma exceção no final do gestor contexto segurando os valores.
péssima idéia
Solução
http://docs.python.org/reference/datamodel.html # contexto gestores
Crie uma classe que detém as contagens êxito e de erro, e que implementa o __enter__
e __exit__
métodos.
Outras dicas
Eu ainda acho que você deve ser a criação de uma classe para prendê-lo contagem de erro / sucesso, como eu disse em você última pergunta . Eu estou supondo que você tem a sua própria classe, então basta adicionar algo como isso a ele:
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
é Nenhum se não há exceções, uma vez invocando a contextmanager
)
E então você provavelmente já estão usando isso em algum lugar, que irá invocar o contextmanager
e executar o seu código __exit__()
. Editar:. Como Eli comentou, apenas a criar uma nova instância de transação quando você deseja redefinir as coutners
t = transaction()
for q in queries:
with t:
t.execute(q)
"tupla como um argumento para o gerente de contexto
faz a função mais específica para um problema / menos reutilizável "
False.
Isso faz com que o gerente contexto reter estado.
Se você não implementar qualquer coisa mais do que isso, será reutilizável.
No entanto, você não pode realmente usar uma tupla porque é imutável. Você precisa de alguma coleção mutável. Dicionários e definições de classe vêm à mente.
Por isso, a implementação recomendada é
"instância que detém a atributos específicos como um argumento para o gerente de contexto"
Uma definição simples classe com dois atributos é tudo que você precisa. No entanto, o status da transação é stateful e você precisa manter em algum lugar do estado.
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