2016-04-05 97 views
3

我有下面的装饰器演示代码。如果我在没有明确调用greet函数的情况下执行它,它将在装饰器函数内执行print语句并输出Inside decoratorPython装饰器函数执行

我无法理解装饰者的这种行为。即使我没有拨打greet函数,如何调用time_decorator

我使用Python 3

def time_decorator(original_func): 
    print('Inside decorator') 
    def wrapper(*args, **kwargs): 
     start = time.clock() 
     result = original_func(*args, **kwargs) 
     end = time.clock() 
     print('{0} is executed in {1}'.format(original_func.__name__, end-start)) 
     return result 
    return wrapper 


@time_decorator 
def greet(name): 
    return 'Hello {0}'.format(name) 

回答

1

装饰被称为在开始时间(当在程序启动Python解释器读取的代码),而不是在运行(当装饰功能实际上被称为)

在运行时,它是被调用的包装函数wrapper,它本身调用装饰函数并返回其结果。

所以这是完全正常的,print行被执行。

如果你装饰了10个功能,你会看到10倍的打印输出。无需为此发生调用装饰函数。

print移到wrapper之内,这样就不会再发生了。

Decorators以及metaclasses是所谓部分元编程(修改/创建代码,从现有的代码)。这是编程的一个非常吸引人的方面,需要时间来理解,但提供了惊人的可能性。

+0

谢谢@Apero!在编译时调用装饰器的动机是什么?除了装饰器之外,是否有任何在编译期间被调用的对象? –

+0

是的,元类在编译时修改它们是“元类”的类,而不是在运行时。元类和装饰器可以像代码黑客一样成为代码,因为它们修改分别元类或装饰的代码,而不必修改初始代码本身。然后每当这个“现在的代码”被调用时,新的黑客行为就会发生。 –

+0

我认为说“编译时间”颇具误导性。 Python函数(和类)定义由解释器在运行时(例如,当您启动程序时)运行的语句创建,而不是在较早的时间(如Java或C程序)。有一个涉及Python代码(从源代码到字节码)的编译步骤,但这与执行像'def'这样的语句无关。 – Blckknght

4

time_decorator在功能修饰期间执行。 wrapper不是(调用装饰greet()时调用此函数)。

@只是语法糖。以下代码片段是等效的。

装饰语法:

@time_decorator 
def greet(name): 
    return 'Hello {0}'.format(name) 

明确装修过程 - 装饰是返回基于另外一个新功能的功能。

def greet(name): 
    return 'Hello {0}'.format(name) 

greet = time_decorator(greet)