Ho uno scenario in cui eseguo dinamicamente funzioni in fase di esecuzione e devo tenere traccia di un ambito "localizzato". Nell'esempio seguente, "startScope" e "endScope" creerebbero effettivamente livelli di "nidificazione" (in realtà, le cose contenute in questo ambito localizzato non sono dichiarazioni di stampa ... sono le chiamate di funzione che inviano dati altrove e il nidificazione è tracciato lì. startScope/endScope imposta semplicemente i flag di controllo che vengono utilizzati per iniziare/terminare la profondità di annidamento corrente).È possibile creare un ambito dinamico localizzato in Python?
Questo funziona perfettamente per il rilevamento dei dati nidificati, tuttavia le eccezioni sono un'altra cosa. Idealmente, un'eccezione si tradurrebbe in una "caduta" dell'attuale ambito localizzato e non nella fine dell'intera funzione (myFunction nell'esempio seguente).
def startScope():
#Increment our control object's (not included in this example) nesting depth
control.incrementNestingDepth()
def endScope():
#Decrement our control object's (not included in this example) nesting depth
control.decrementNestingDepth()
def myFunction():
print "A"
print "B"
startScope()
print "C"
raise Exception
print "D"
print "This print statement and the previous one won't get printed"
endScope()
print "E"
def main():
try:
myFunction()
except:
print "Error!"
L'esecuzione di questo sarebbe (teoricamente) uscita la seguente:
>>> main()
A
B
C
Error!
E
>>>
Sono abbastanza certo questo non è possibile, come ho scritto sopra - Volevo solo dipingere un quadro di il tipo di risultato finale che sto cercando di ottenere.
È qualcosa del genere possibile in Python?
Edit: A più rilevante (anche se lunga) esempio di come questo viene effettivamente utilizzato:
class Log(object):
"""
Log class
"""
def __init__(self):
#DataModel is defined elsewhere and contains a bunch of data structures/handles nested data/etc...
self.model = DataModel()
def Warning(self, text):
self.model.put("warning", text)
def ToDo(self, text):
self.model.put("todo", text)
def Info(self, text):
self.model.put("info", text)
def StartAdvanced(self):
self.model.put("startadvanced")
def EndAdvanced(self):
self.model.put("endadvanced")
def AddDataPoint(self, data):
self.model.put("data", data)
def StartTest(self):
self.model.put("starttest")
def EndTest(self):
self.model.put("endtest")
def Error(self, text):
self.model.put("error", text)
#myScript.py
from Logger import Log
def test_alpha():
"""
Crazy contrived example
In this example, there are 2 levels of nesting...everything up to StartAdvanced(),
and after EndAdvanced() is included in the top level...everything between the two is
contained in a separate level.
"""
Log.Warning("Better be careful here!")
Log.AddDataPoint(fancyMath()[0])
data = getSerialData()
if data:
Log.Info("Got data, let's continue with an advanced test...")
Log.StartAdvanced()
#NOTE: If something breaks in one of the following methods, then GOTO (***)
operateOnData(data)
doSomethingCrazy(data)
Log.ToDo("Fill in some more stuff here later...")
Log.AddDataPoint(data)
Log.EndAdvanced()
#(***) Ideally, we would resume here if an exception is raised in the above localized scope
Log.Info("All done! Log some data and wrap everything up!")
Log.AddDataPoint({"data": "blah"})
#Done
#framework.py
import inspect
from Logger import Log
class Framework(object):
def __init__(self):
print "Framework init!"
self.tests = []
def loadTests(self, file):
"""
Simplifying this for the sake of clarity
"""
for test in file:
self.tests.append(test)
def runTests(self):
"""
Simplifying this for the sake of clarity
"""
#test_alpha() as well as any other user tests will be run here
for test in self.tests:
Log.StartTest()
try:
test()
except Exception,e :
Log.Error(str(e))
Log.EndTest()
#End
Potete chiarire quali aspetti di questo sono must-have e quali sono flessibili? Inoltre, hai bisogno/vuoi che questi "ambiti" abbiano un impatto su qualcosa di diverso dalla gestione delle eccezioni? Se l'eccezione è rilevata in 'main', non è possibile ottenere' print "E" 'per eseguire; una volta propagata l'eccezione, non è possibile "riprendere" l'esecuzione a un livello inferiore. – BrenBarn
Per questo esempio, sono interessato solo al risultato. L'esempio (come scritto sopra) chiaramente non funzionerà per il motivo che hai appena menzionato. Per quanto riguarda la flessibilità, non ho il controllo diretto sul contenuto di "myFunction" ... tutto quello che so è che "startScope" e "endScope" saranno chiamati, e posso gestire quelle chiamate in qualsiasi modo ritenga opportuno. Attualmente, questo significa spingere/scoppiare da una pila in una classe di controllo separata. Funziona per i dati, ma la gestione delle eccezioni è un'altra storia. La mia speranza è che ci sia una sorta di schema di progettazione comune che si occupa di questo genere di cose ... – Novark