可以在Python中创建一个动态的本地化范围吗?

2024-10-01 07:47:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个在运行时动态运行函数的场景,需要跟踪“本地化”范围。在下面的示例中,“startScope”和“endScope”实际上是在创建“嵌套”级别(实际上,这个本地化范围中包含的内容不是print语句……而是函数调用,它们将数据发送到其他地方,并在那里跟踪嵌套)。startScope/endScope(仅设置用于开始/结束当前嵌套深度的控制标志)。你知道吗

这些都可以很好地跟踪嵌套数据,但是,异常是另一回事。理想情况下,异常将导致“脱离”当前的本地化范围,而不是结束整个函数(下面示例中的myFunction)。你知道吗

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!"

运行此操作(理论上)会产生以下结果:

>>> main()
A
B
C
Error!
E

>>>

我很确定这是不可能的,因为我已经写在上面了-我只是想画一幅画的那种最终结果,我正在努力实现。你知道吗

在Python中这样做可能吗?你知道吗

编辑:一个更相关(尽管很长)的示例,说明如何实际使用它:

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

Tags: ofthetextintestselflogdata
1条回答
网友
1楼 · 发布于 2024-10-01 07:47:38

使用with语句使用上下文管理器可以获得类似的效果。这里我使用^{}装饰器:

@contextlib.contextmanager
def swallower():
    try:
        yield
    except ZeroDivisionError:
        print("We stopped zero division error")

def foo():
    print("This error will be trapped")
    with swallower():
        print("Here comes error")
        1/0
        print("This will never be reached")
    print("Merrily on our way")
    with swallower():
        print("This error will propagate")
        nonexistentName
    print("This won't be reached")

>>> foo()
This error will be trapped
Here comes error
We stopped zero division error
Merrily on our way
This error will propagate
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    foo()
  File "<pyshell#3>", line 10, in foo
    nonexistentName
NameError: global name 'nonexistentName' is not defined

这不能像你的例子那样用普通的函数调用来完成。在您的示例中,函数startScopemyFunction主体的其余部分执行之前返回,因此startScope对它没有任何影响。要处理异常,需要在myFunction内部使用某种显式结构(一个with语句或一个常规的try/except);无法让一个简单的函数调用神奇地截获调用方中引发的异常。你知道吗

你应该仔细阅读context managers,因为它们似乎适合你要做的事情。上下文管理器的__enter____exit__方法将对应于您的startScopeendScope。“使用函数调用时,您是否希望使用这些函数来做什么,可能更取决于您是否希望使用函数调用来做什么”。你知道吗

相关问题 更多 >