一、函数预备知识(续一)
大家好,今天继续聊函数预备知识。涉及 函数闭包、装饰器;这两点是学习 requests 库、pytest 框架源码时基础。装饰器是函数闭包应用,我们首先会学习函数闭包;再掌握原理后,相信装饰器会轻松应用
0. 函数预备知识:
0.1 在 python 中函数也是 对象,可以把函数赋值给变量
def func(message): print("打印一条message: {}".format(message)) send_message = func print(func) # <function func at 0x0000000001D463A0> send_message("123") # 打印一条message: 123
0.2 函数也可以当做 实参 进行传递
def func(message): print("打印一条message: {}".format(message)) def call_func( f=None, message=None): f(message) call_func(func, 'call_func调用') # 打印一条message: call_func调用
0.3 函数的嵌套
def call_func(message):
def func(message):
print("打印一条message: {}".format(message))
return func(message)
call_func('内层函数') # 打印一条message: 内层函数
0.4 函数的返回值也可以是 函数对象
def call_func():
def func(message):
print("打印一条message: {}".format(message))
return func
result = call_func()
result("hello world") # 打印一条message: hello world
1. 闭包
在一个函数中嵌套定义另一个函数,内层函数运用外层函数的临时变量,并且外层函数返回内层函数对象(内层函数地址值);这样就构成闭包
条件:
1. 存在函数的嵌套关系
2. 内层函数使用外层函数变量
3. 外层函数返回内层函数的地址值(函数对象)
def outer(out): def inner(inn): print(f'outer:{out}') print(f'inner:{inn}') return inner f = outer('i am outer') print(f) # <function outer.<locals>.inner at 0x0000000001E27790> f('i am inner') # outer:i am outer inner:i am inner
2. 装饰器
应用题:若给 out 传递一个函数对象,在 inner 函数内增加对 该函数对象 调用,inn 变成传递给 该函数对象 形参 => 装饰器 (进一步优化,将 inn 替换成之前介绍 可变长形参 *args、**kwargs;即可增加装饰器使用范围)
def outer(func): def inner(inn): print("start function") func(inn) print("end fuction") return inner def running(p): print(str(p) + ':running...') running = outer(running) print(running) # <function outer.<locals>.inner at 0x00000000026A1940> running('decorator') # start function # decorator:running... # end fuction
语法糖@
running = outer(running) => @outer ,实战下面:
def outer(func): def inner(inn): print("start function") func(inn) print("end fuction") return inner @outer def running(p): print(str(p) + ':running...') #running = outer(running) print(running) # <function outer.<locals>.inner at 0x00000000026A1940> running('decorator') # start function # decorator:running... # end fuction
使用语法糖@ 在被装饰的函数定义时书写,之后不要在显示调用 running = outer(running)
装饰器统一定义:
def my_decorator(func): def wrapper(*args, **kwargs): print('wrapper of decorator') func(*args, **kwargs) return wrapper
以下内容转自 python 装饰器在接口自动化测试中的应用 中关于使用 类 实现装饰器的部分
装饰器也是可以接收参数的
装饰器还有更大程度的灵活性,可以接受自己定义的参数,可以给装饰器本身传递参数
def repeat(num): def my_decorator(func): def wrapper(*args, **kwargs): for i in range(num): print('wrapper of decorator') func(*args, **kwargs) return wrapper return my_decorator @repeat(4) def greet(message): print(message) greet('hello world')
3. 类装饰器
类也可以作为装饰器。类装饰器主要依赖于函数 __call__(),每当你调用一个类的示例时,函数call() 就会被执行一次。
这个类装饰器还不支持接收参数,后面我们实战的装饰器时可以支持结束参数的。
装饰器在接口自动化测试项目中应用
至此我们介绍完了装饰器,下面我们基于之前的理论,来进行一次实战。
需求是希望通过装饰器来实现接口的请求,能够自定义请求方法、请求的根路径、公共参数、headers 设置等功能。
使用的时候要定义一个类,比如下面这样:
上面的 header 会被自动的添加的 session 的 header 里,common_params 也会被添加到参数里,base_url 和装饰器里传的 url 会被拼接成一个完整的 url 去请求接口
__call__() 介绍:
__call__()
是一种magic method,在类中实现这一方法可以使该类的实例(对象)像函数一样被调用。默认情况下该方法在类中是没有被实现的。使用callable()方法可以判断某对象是否可以被调用。
__call__()
方法的作用其实是把一个类的实例化对象变成了可调用对象,也就是说把一个类的实例化对象变成了可调用对象,只要类里实现了__call__()
方法就行。如当类里没有实现__call__()
时,此时的对象p 只是个类的实例,不是一个可调用的对象,当调用它时会报错:‘Person’ object is not callable.
class People(object): def __init__(self,name): self.name=name def __call__(self): print("hello "+self.name) a = People('world') a.__call__() # hello world a() # hello world
参考文章: