嵌套函数如何用于装饰器?

时间:2019-10-18 09:51:58

标签: python python-3.x

我不太了解以下代码的行为。 该代码的目标是仅允许一次装饰器装饰的功能的一次处理。由于我在try块中返回了一次result,因此我不明白为什么在第二次调用中没有第二次“ Hello william”。因此,我试图打印一次结果并获取无作为输出。我期望包含“ Hello william”的字符串。

有人可以向我解释这种行为吗?

以下是输出:

Before first call
Exception
Hello William !
Before second call
None
Finished

代码如下:

def once(func):
    """once is a decorator which allows only one execution of the function"""
    def nested(*args,**kargs):
        try:
            print(nested.onceResult)
            return nested.onceResult
        except AttributeError:
            print("### EXCEPTION###")
            nested.onceResult = func(*args,**kargs)
            return nested.onceResult
    return nested

@once
def hello(name):
    print(f"Hello {str(name)} !")

print("Before first call")
hello("William")
print("Before second call")
hello("Roger")
print("Finished")

1 个答案:

答案 0 :(得分:0)

我建议使用一个类来实现您的目标。

这是我的方法:

  1. 如果无论传递什么参数,只要执行一次功能,就可以通过
class ExecuteOnceClass:
    called = []

    @staticmethod
    def execute(function):
        def wrapper(*args, **kwargs):
            if function.__name__ in ExecuteOnceClass.called:
                print("Function already called once")
            else:
                function(*args, **kwargs)
                ExecuteOnceClass.called.append(function.__name__)
                print("called function")
        return wrapper

@ExecuteOnceClass.execute
def hello(name):
    print(f"Hello {name}.")

hello("Neuneu")
hello("Sofian")

预期输出:

Hello Neuneu.
called function
Function already called once
  1. 如果您希望函数通过一次参数调用被调用一次:
class ExecuteOnceClass:
    called = {}

    @staticmethod
    def execute(function):
        def wrapper(*args, **kwargs):
            if function.__name__ in ExecuteOnceClass.called and {"args": args, "kwargs": kwargs} in ExecuteOnceClass.called[function.__name__]:
                print("Function already called once with the same arguments")
            else:
                function(*args, **kwargs)
                if ExecuteOnceClass.called.get(function.__name__, None):
                    ExecuteOnceClass.called[function.__name__].append({"args": args, "kwargs": kwargs})
                else:
                    ExecuteOnceClass.called[function.__name__] = [{"args": args, "kwargs": kwargs}]
                print("called function")
        return wrapper

@ExecuteOnceClass.execute
def hello(name):
    print(f"Hello {name}.")

hello("Neuneu")
hello("Sofien")
hello("Neuneu")
hello("Sofien")

预期输出:

Hello Neuneu.
called function
Hello Sofien.
called function
Function already called once with the same arguments
Function already called once with the same arguments

编辑: 如果您的函数返回了某些内容,则需要对代码进行一些编辑:

class ExecuteOnceClass:
    called = {}

    @staticmethod
    def execute(function):
        def wrapper(*args, **kwargs):
            if function.__name__ in ExecuteOnceClass.called and {"args": args, "kwargs": kwargs} in ExecuteOnceClass.called[function.__name__]:
                print("Function already called once with the same arguments")
            else:
                functionResult = function(*args, **kwargs)
                if ExecuteOnceClass.called.get(function.__name__, None):
                    ExecuteOnceClass.called[function.__name__].append({"args": args, "kwargs": kwargs})
                else:
                    ExecuteOnceClass.called[function.__name__] = [{"args": args, "kwargs": kwargs}]
                print("called function")
            return functionResult
        return wrapper

@ExecuteOnceClass.execute
def hello(name):
    return f"Hello {name}."

print(hello("Neuneu"))

预期输出:

Hello Neuneu.

祝你好运!

第二编辑: 为了更好地理解python(当然还有装饰器),我强烈推荐您此视频:
What Does It Take To Be An Expert At Python?
观看此视频,我学到了很多东西。