智一面的面试题提供python的测试题
使用地址:http://www.gtalent.cn/exam/interview?token=99ef9b1b81c34b4e0514325e9bd3be54

 

装饰器让你在一个函数的前后去执行代码。

# 一个装饰器函数,参数是一个函数
def a_new_decorator(a_func):
 	# 嵌套一个函数,用于在执行a_func之前执行其他操作
    def wrapTheFunction():
    	# 执行a_func()之前,执行的操作
        print("I am doing some boring work before executing a_func()")
 		# 执行a_func()函数
        a_func()
 		# 执行a_func之后的一些操作
        print("I am doing some boring work after executing a_func()")
 	# 返回一个函数地址,使得调用a_new_decorator时,转而调用内部的wrapTheFunction函数
    return wrapTheFunction
 

# 测试示例,一个普通的函数,将作为装饰器参数
def a_function_requiring_decoration():
    print("I am the function which needs some decoration to remove my foul smell")
# 普通函数的正常执行状况
a_function_requiring_decoration()
#outputs: "I am the function which needs some decoration to remove my foul smell"


# 将一个函数赋值给一个变量,类似C语言中的函数指针操作,使得该变量使用()就可以调用其指代的函数
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
#now a_function_requiring_decoration is wrapped by wrapTheFunction()
 
# 执行这个装饰器函数,可以观察到结果如下
a_function_requiring_decoration()
#outputs:I am doing some boring work before executing a_func()
#        I am the function which needs some decoration to remove my foul smell
#        I am doing some boring work after executing a_func()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

上面演示的示例,正是python中装饰器所做的事。我们可以使用@做到上述相同的结果。

# 装饰器函数
def a_new_decorator(a_func):
 
    def wrapTheFunction():
        print("I am doing some boring work before executing a_func()")
 
        a_func()
 
        print("I am doing some boring work after executing a_func()")
 
    return wrapTheFunction

# 使用@使用一个装饰器
# 他将在调用a_function_requiring_decoration时,将该函数作为参数
#	传入作为装饰器函数的a_new_decorator中,产生类似 
#	a_new_decorator( a_function_requiring_decoration) 的调用效果
@a_new_decorator	# 装饰器,
def a_function_requiring_decoration():
    """Hey you! Decorate me!"""
    print("I am the function which needs some decoration to "
          "remove my foul smell")
 
a_function_requiring_decoration()
#outputs: I am doing some boring work before executing a_func()
#         I am the function which needs some decoration to remove my foul smell
#         I am doing some boring work after executing a_func()
 
#the @a_new_decorator is just a short way of saying:
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

接上述代码,我们运行print(a_function_requiring_decoration.__name__) 发现Ouput输出应该是"a_function_requiring_decoration",这里的函数被warpTheFunction替代了。

print(a_function_requiring_decoration.__name__)
#outputs:  wrapTheFunction
  • 1
  • 2

它重写了我们函数的名字和注释文档(docstring)。幸运的是Python提供给我们一个简单的函数来解决这个问题,那就是functools.wraps。我们修改上一个例子来使用functools.wraps:

from functools import wraps
 
def a_new_decorator(a_func):
    @wraps(a_func)
    def wrapTheFunction():
        print("I am doing some boring work before executing a_func()")
        a_func()
        print("I am doing some boring work after executing a_func()")
    return wrapTheFunction
 
@a_new_decorator
def a_function_requiring_decoration():
    """Hey yo! Decorate me!"""
    print("I am the function which needs some decoration to "
          "remove my foul smell")
 
print(a_function_requiring_decoration.__name__)
# Output: a_function_requiring_decoration
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

简单理解就是 @wraps可以保证装饰器修饰的函数的__name__的值保持不变。
而装饰器的作用是,在不改变原有功能代码的基础上,添加额外的功能,如用户验证等
@wraps(func)的作用是,不改变使用装饰器原有函数的结构(如__name__, doc)

示例:

from functools import wraps
def decorator_name(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        if not can_run:
            return "Function will not run"
        return f(*args, **kwargs)
    return decorated
 
@decorator_name
def func():
    return("Function is running")
 
can_run = True
print(func())
# Output: Function is running
 
can_run = False
print(func())
# Output: Function will not run
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

注意:@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。


使用场景:

授权(Authorization)
装饰器能有助于检查某个人是否被授权去使用一个web应用的端点(endpoint)。它们被大量使用于Flask和Django web框架中。这里是一个例子来使用基于装饰器的授权:

 

 

  •