装饰器
一 函数对象:
python一切皆对象
函数是第一类对象 (函数可以被当做数据传递)
1 可以被引用 即 x = func
2 可以当做函数的参数传入.
3 可以当做函数的返回值
4 可以作为容器数据类型的元素
例1
def func(x):
pass
return x
x = func(10) 这是调用函数的返回值不是函数
x = func
x()
li = [1,x,2]
例2
def func(bar):
bar()
def bar():
pass
func(bar)
例3
def outter():
def inner():
print('inner')
return inner
x = outter()
x()
二 函数的嵌套调用和定义
当两个函数互相调用时
会超出最大递归深度报错
def func():
print('func')
func()
def bar():
print('bar')
func()
func()
例1 嵌套调用
def max(x,y):
if x>y:
return x
else:
return y
def max4(x,y,z,a):
res = max(x,y)
res = max(res,z)
res = max(res,q)
max4(1,2,3,4,)
例2 嵌套定义
def func1():
def func2():
def func():
print('aaf')
func()
def func2()
func1()
三 命名空间作用域
3.1
内置命名空间
全局命名空间
ps : 内置全局空间中的变量是全局有效 >>查询 glsbals()
局部命名空间 (函数[类]运行时开辟的内存空间
各个局部空间相互独立)
局部命名空间中可以访问其外层空间
#2、作用域关系是在函数定义阶段就已经固定的,
与函数的调用位置无关,
如下 个人理解 可能不对
因为在定义函数时,函数名与内存地址的的对应关系会存放在当前的命名空间所以
作用域关系是在函数定义阶段就已经固定的.带调用函数时是从定义时的命名空间调用的.
x=1
def f1():
def f2():
print(x)
return f2
x=100
def f3(func):
x=2
func()
x=10000
f3(f1())
#3、查看作用域:globals(),locals()
locals 是函数内的名字空间,包括局部变量和形参
enclosing 外部嵌套函数的名字空间(闭包中常见)
globals 全局变量,函数定义所在模块的名字空间
builtins 内置模块的名字空间
builtins()
globals()
enclosing()
locals()
四 闭包函数
什么是闭包:
闭包是 1 当在调用一个其他函数中的内嵌函数时,内嵌函数会优先调取它外层函数的命名空间内的变量而不是从当前的命名空间提取变量:这就是闭包
2 将函数需要的数据打包起来,只能允许特定的函数(也就是内嵌函数调用) :这就是闭包
本质类似通过构建一层外部函数扩充内层函数的局部命名空间并为其添加某一功能
也就是说基于函数对象的概念,可以将函数返回到任意位置去调用,但作用域的关系是在定义完函数时就已经被确定了的,与函数的调用位置无关。
也就是说函数被当做数据处理时,始终以自带的作用域为准。若内嵌函数包含对外部函数作用域(而非全局作用域)中变量的引用,那么该’内嵌函数’就是闭包函数,简称闭包(Closures)
x=1
def f1():
def f2():
print(x)
return f2
def f3():
x=3
f2=f1() #调用f1()返回函数f2
f2() #需要按照函数定义时的作用关系去执行,与调用位置无关
f3() #结果为1
x=1
def outer():
x=2
def inner():
print(x)
return inner
func=outer()
func() # 结果为2
装饰器
是什么?
用于装饰其他函数的工具
原则
1 不改变被装饰函数的源码
2 不改变被装饰函数的调用方式
装饰器:
无参装饰器:
写法:
第一步
def outer(func): (传入被装饰函数的名字)
def inner(*args,**kwargs):
return inner
第二部
def outer(func): (传入被装饰函数的名字)
def inner(*args,**kwargs):
print('代码块1')
res = func(*args,**kwargs)
print('代码块2')
return res
return inner
第三部
@outer
def func():
pass
装饰器函数(初稿)
import time
# def login(file):
# inp_name = input('place input your username !').strip()
# inp_password = input('place input yuor password').strip()
# with open(file, mode='r', encoding='utf-8') as f:
# date = []
# for line in f:
# iofo = line.strip().split()
# date.append(iofo)
# if inp_name == iofo[0].strip() and inp_password == iofo[1]:
# return True
# return False
#
# print(login(file=f'user_iofo'))
def outter(func):
def inner(*args, **kwargs):
start = time.time()
login(*args, **kwargs)
end = time.time()
print(end-start)
return inner
@outter
def login(file):
inp_name = input('place input your username !').strip()
inp_password = input('place input yuor password').strip()
with open(file, mode='r', encoding='utf-8') as f:
date = []
for line in f:
iofo = line.strip().split()
date.append(iofo)
if inp_name == iofo[0].strip() and inp_password == iofo[1]:
return True
return False
'''不行应该时返回True''' #因为现在的login返回的是inner的值
print(login(file=f'user_iofo'))
print(True)
改进完成,当时有缺点.
1 返回值没有相应的改变
2 文本解释没有相应的改变
装饰器改进(副稿)
# import time
# def outter(func):
#
# def inner(*args, **kwargs):
# inner.__doc__=login.__doc__
# inner.__name__=login.__name__
# start = time.time()
# res = login(*args, **kwargs)
# end = time.time()
# print(end-start)
# return res
# return inner
#
#
# @outter
# def login(file):
# inp_name = input('place input your username !').strip()
# inp_password = input('place input yuor password').strip()
# with open(file, mode='r', encoding='utf-8') as f:
# date = []
# for line in f:
# iofo = line.strip().split()
# date.append(iofo)
# if inp_name == iofo[0].strip() and inp_password == iofo[1]:
# return True
# return False
# '''不行应该时返回True'''
# print(login(file=f'user_iofo'))
# print(True)
# 文本文档名字修改较为麻烦>所以我们调用工具修改
from functools import wraps
import time
def outter(func):
@wraps(func)
def inner(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print(end-start)
return res
return inner
@outter
def login(file):
inp_name = input('place input your username !').strip()
inp_password = input('place input yuor password').strip()
with open(file, mode='r', encoding='utf-8') as f:
date = []
for line in f:
iofo = line.strip().split()
date.append(iofo)
if inp_name == iofo[0].strip() and inp_password == iofo[1]:
return True
return False
'''不行应该时返回True'''
print(login(file=f'user_iofo'))
print(True)
print(help(login))
有参装饰器
inner函数中需要其他参数的传入,而outer 函数和inner函数没法传其他参数.
所以我们觉得再加一层闭包来传入参数
第一步
def ginseng(x,y):
def outer(func):
pass
return outer()
第二步
def ginseng(x,y):
def outer(func):
def inner():
pass
return inner
return outer()
第三步
def ginseng(x,y):
def outer(func):
def inner(*args,**kwargs):
print(x,y)
set =func(*args,**kwargs)
return set
return inner
def ginseng(x,y):
def outer(func):
def inner(*args,**kwargs):
print(x,y)
set =func(*args,**kwargs)
return set
return inner
return outer
个人理解装饰器
无参装饰器:功能用来拓展函数 ,为原函数添加其他功能
原则 1 源码不动 2 调用方式不变
(1) 既要添加新功能又要保持原函数代码不变,==>>那么只能重新写一个函数(以outer函数为例)将原函数传入outer函数中,
然后在outer函数中添加新功能拓展函数,(函数的调用嵌套)
(2) 但是有要求调用方式不变,调用方式很好解决(可以用复制的方法),但是要保证新调用函数名与原函数传参相一致并且要传给原函数.
而outer函数传入的参数包括原函数,不可能与原函数的参数一致,所以只能再次写一个函数
(以inner函数为例)将原函数的参数传入inner函数,并使其与原函数的参数一致(函数的定义嵌套)
(3) 因为我们[必须保证我们传入的原函数可以调用传入的参数]所以只有在函数的外层或者内层再次写一个函数,又因为我们传入参数时必须知道原函数
是什么,所以outer函数在最外层传入(函数名),inner函数在第二层,接受原函数的参数,并且传递给原函数参数(使用(*args,**kwargs))的方式
(4) 给函数添加功能要在inner函数内,inner是负责接收原函数的参数的,即我们要用inner函数代替原函数.所以添加的功能要在函数内部.
(5) 最后通过outer()返回inner,再将outer()赋值给原函数的函数名.例 login = outer() = inner. 调用login()相当于调用 inner() 至此进出功能完成