Comment dois-je retourner des valeurs intéressantes d'une avec-déclaration?
-
22-08-2019 - |
Question
Y at-il une meilleure façon que d'utiliser globals pour obtenir des valeurs intéressantes d'un gestionnaire de contexte?
@contextmanager
def transaction():
global successCount
global errorCount
try:
yield
except:
storage.store.rollback()
errorCount += 1
else:
storage.store.commit()
successCount += 1
Autres possibilités:
-
singletons
sorte de ... GLOBALS
-
tuple comme argument au gestionnaire de contexte
rend la fonction plus spécifique à un problème / moins réutilisable
-
instance qui détient les attributs spécifiques comme argument au gestionnaire de contexte
mêmes problèmes que le tuple, mais plus lisible
-
soulever une exception à la fin du gestionnaire de contexte contenant les valeurs.
mauvaise idée
La solution
Voir http://docs.python.org/reference/datamodel.html # contexte gestionnaires
Créer une classe qui détient le succès et erreur compte, et qui met en œuvre les méthodes de __enter__
et __exit__
.
Autres conseils
Je pense toujours que vous devriez créer une classe pour vous tenir compte erreur / succès, comme je le disais en vous dernier question. Je devine que vous avez votre propre classe, donc il suffit d'ajouter quelque chose comme ça à elle:
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
est Aucun s'il n'y a aucune exception en invoquant une fois que le contextmanager
)
Et vous utilisez déjà probablement quelque part ce qui appellera l'contextmanager
et exécutez votre code __exit__()
. Edit:. Eli a commenté, créez seulement une nouvelle instance de transaction lorsque vous souhaitez réinitialiser les coutners
t = transaction()
for q in queries:
with t:
t.execute(q)
"tuple comme argument au gestionnaire de contexte
rend la fonction plus spécifique à un problème / moins réutilisable "
Faux.
Cela rend le gestionnaire de contexte conserver l'état.
Si vous ne mettez pas en œuvre quelque chose de plus que cela, il sera réutilisable.
Cependant, vous ne pouvez pas utiliser en fait un tuple parce qu'il est immuable. Vous avez besoin d'une collection mutable. Les dictionnaires et les définitions de classe viennent à l'esprit.
Par conséquent, la mise en œuvre recommandée est
« instance qui contient les attributs spécifiques comme argument au gestionnaire de contexte »
Une définition simple de classe avec deux attributs est tout ce que vous avez besoin. Cependant, l'état de votre transaction est stateful et vous devez conserver quelque part état.
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