更改嵌套函数的decorator中的值

时间:2015-06-04 20:08:23

标签: python python-2.7 decorator python-decorators globals

我有一个与此相似的案例 -

flag = True
print "Before All things happened, flag is", flag
def decorator(*a):
    def real_decorator(function):
        def wrapper(*args, **kwargs):
            global flag
            flag = False
            print "just in real decorator before function call i.e. before", function.__name__
            print "flag is " , flag
            function(*args, **kwargs)
            print "In real decorator after function call i.e. after", function.__name__
            flag = True
            print "flag is ", flag
        return wrapper
    return real_decorator

@decorator()
def subtota():
    print "in subtota"
    print "flag is" , flag

@decorator()
def print_args(*args):
    print "in print args"
    for arg in args:
        print arg
    print "flag is ", flag
    subtota()
    print "we do want flag to be false here, after subtota"
    print "but, flag is ", flag


print_args("bilbo", "baggins")

print "after All things happended flag is ", flag

输出

Before All things happened, flag is True
just in real decorator before function call i.e. before print_args
flag is  False
in print args
bilbo
baggins
flag is  False
just in real decorator before function call i.e. before subtota
flag is  False
in subtota
flag is False
In real decorator after function call i.e. after subtota
flag is  True
we do want flag to be false here, after subtota
but, flag is  True
In real decorator after function call i.e. after print_args
flag is  True
after All things happended flag is  True

在这里,我不想在subtota()之后更改flag的值,或者我们可以说,我们希望保持每个函数的行为彼此独立。 我们怎样才能做到这一点? PS - 无法避免使用模块级全局变量flag

编辑 - 期望的行为 - 只有在执行最上面的函数之后,该标志才应为false。

3 个答案:

答案 0 :(得分:2)

我发现你的目标在这里有点不清楚。

如果需要跟踪每个功能状态,可以在修饰的功能对象本身上设置一个标志:

def decorator(*a):
    def real_decorator(function):
        def wrapper(*args, **kwargs):
            function.flag = False
            function(*args, **kwargs)
            function.flag = True
        return wrapper
    return real_decorator

你也可以在这里wrapper设置它以使装饰版本上的标志可用:

wrapper.flag = False

如果您只需要在进入和退出最外面的装饰调用时切换标记,您可以使用单独的全局来计算您有多少级别;你也可以在decorator函数上设置它:

def decorator(*a):
    decorator._depth = 0
    def real_decorator(function):
        def wrapper(*args, **kwargs):
            global flag
            if decorator._depth == 0:  # entering outermost call
                flag = False

            decorator._depth += 1
            function(*args, **kwargs)
            decorator._depth -= 1

            if decorator._depth == 0:  # exiting outermost call
                flag = True
        return wrapper
    return real_decorator

答案 1 :(得分:1)

在包装器中保存标志的旧值,并恢复为它而不是True

答案 2 :(得分:0)

除了使用作用于装饰器的变量之外,我尝试使用以下方法 -

def decorator(*a):
def real_decorator(function):
    def wrapper(*args, **kwargs):
        global flag
        old_flag = flag
        flag = False
        function(*args, **kwargs)
        flag = old_flag
    return wrapper
return real_decorator

这看起来有点简单,并且完美无缺。