在python中使函数等同的机制

时间:2018-05-21 16:08:08

标签: python decorator

我了解到我们可以在Python中将一个函数与另一个函数等同于:

def func_1(x)
    print("func_1")
    print(x)

def func_2(x)
    print("func_2")
    print(x)

func_1 =func_2

所以在这里发生的事情是每次调用func_1都会执行func_2。

但是,我读到了装饰器,下面是一个简单的代码说明:

def our_decorator(func):
    def function_wrapper(x):
        print("Before calling " + func.__name__)
        func(x)
        print("After calling " + func.__name__)
    return function_wrapper

def foo(x):
    print("Hi, foo has been called with " + str(x))

print("We call foo before decoration:")
foo("Hi")

print("We now decorate foo with f:")
foo = our_decorator(foo)

print("We call foo after decoration:")
foo(42)

我们可以在以下行中看到:

foo = our_decorator(foo)

类似于之前的函数方程式正在发生。我认为这就是装饰器可能正在工作的方式,即通过调用decorator来替换对decoratee的调用。

然而,在这种印象下,如果我写下如下代码:

def our_decorator():
    def function_wrapper(x):
        print("Before calling " )
        foo(x)
        print("After calling " )
    return function_wrapper

def foo(x):
    print("Hi, foo has been called with " + str(x))

print("We call foo before decoration:")
foo("Hi")

print("We now decorate foo with f:")
foo = our_decorator()

print("We call foo after decoration:")
foo(42)

上面的结果是无限递归打印无限数量"在调用"之前。

所以,我可以得出结论,装饰器必须是一个将函数作为参数的东西。

因此,函数的等同在这两个cae中是不同的,即等同于将另一个函数作为参数的函数,并将两个不接受另一个函数作为参数的函数等同起来。

这两者在内部实施方面有何不同?

3 个答案:

答案 0 :(得分:1)

你所谓的“等同函数”实际上只是一个变量赋值。函数定义(带def)创建一个函数并将其赋值给变量名。执行func_1 = func_2后,您有2个变量引用相同的函数。

装饰器示例中发生的情况是前一段的自然结果。如果您需要进一步澄清,请发表评论。

答案 1 :(得分:0)

我希望通过解释几个术语来回答你的问题。

  1. 您使用术语“等同于”来表示通常称为“分配”的内容。 name = expr是一个赋值语句。名称name被赋予(分配)给对象,该对象是表达式expr的结果。

  2. 在Python中,函数不受特殊处理。这有时用句子“函数是第一类对象”表示,基本上它意味着函数对象可以分配给变量(名称),作为参数传递等,与数字,字符串和其他对象。

  3. (函数)装饰器处理另一个函数。它是一个函数,它将函数作为参数进行修饰,并返回一个“装饰”(即以某种方式增强或修改)版本。有时它只注册函数,例如作为处理程序或作为API的一部分并返回它不变。它有一个特殊的语法:

  4. @decorator
    def func(...):
        pass
    

    相当于:

    func = decorator(func)
    

    还有:

    @decorator(args)
    def func(...):
        pass
    

    相当于:

    _real_decorator = decorator(args)
    func = _real_decorator(func)
    

    因为这个@decorator语法易于使用且易于阅读,所以通常不会写:

    func = decorator(func)
    

    总结:

    func1 = some_func是明确的作业,为some_func提供其他名称。

    func2 = create_function()这在某些语言中称为函数工厂。你在问题中写了这个。

    func = decorate_function(func)这是func

    的装饰

    注意:存在类装饰器,它们非常相似,但增强了类定义而不是函数。

答案 2 :(得分:0)

装饰师看起来像这样:

def decorator_with_args(*args, **kwargs):
    def wrapper(f: "the function being decorated"):
        def wrapped(*args, **kwargs):
            # inside here is the code that is actually executed
            # when calling the decorated function. This should
            # always include...
            f(*args, **kwargs)

            # and usually return its result
        return wrapped
    return wrapper

# or

def decorator_without_args(f: "the function being decorated"):
    def wrapped(*args, **kwargs):
        # as above
        return f(*args, **kwargs)
    return wrapped

并用于:

@decorator_with_args("some", "args")
def foo(x):
    print("foo:", x)  # or whatever

@decorator_without_args
def bar(x):
    print("bar:", x)

这相当于在没有@decorator...魔法的情况下定义每个函数并在之后应用装饰器

def baz(x):
    print("baz:", x)

baz = decorator_with_args("some", "arguments")(baz)
# or
baz = decorator_without_args(baz)

在你的示例代码中,你在装饰器中调用foo,然后用装饰器装饰foo,这样你最终会无限递归。每次调用foo时,它都会运行您的装饰器代码,该代码也会调用foo。每次装饰者调用foo时,它都会运行您的装饰器代码,该代码也会调用foo。每当装饰者的装饰者调用foo时,都会运行你的装饰师代码......等等