文章目录
函数对象
函数是第一类对象:指的是函数可以当做数据传递
- 可以被引用:x=1,y=x
def func(x,y):
print(x,y)
f=func
f(1,2)
- 可以当做函数的参数传入
def foo():
print('from foo')
def bar(func): #传参,把foo传入函数bar
func() #这里的func(),就等于foo()
bar(foo)
- 可以当做函数的返回值
def foo():
print('from foo')
def bar():
return foo
f=bar() #return foo,把foo返回给f
f() #f()就相等于foo()
- 可以当做容器类型的元素
#例1:
def foo():
print('from foo')
def bar():
return foo
l=[foo,bar]
print(1)
l[0]()
bar()() #函数bar返回的值再执行函数foo
#例2:
def get():
print('get')
def put():
print('put')
def ls():
print('ls')
def auth():
print('auth')
func_dic={'get':get,
'put':put,
'ls':ls,'auth':auth}
cmd =input('>>>>').strip()
if cmd in func_dic:
func_dic[cmd]()
函数嵌套
函数的嵌套调用
def my_max(x,y):
if x>=y:
return x
else:
return y
def my_max2(a,b,c,d): #a=1,b=32312,c=12121,d=4342
res1=my_max(a,b) #比较1,32312,res1=32312
res2=my_max(res1,c) #比较32312,12121 res2=32312
res3=my_max(res2,d) #比较32312,4342 res3=32312
return res3
print(my_max2(1,32312,12121,4342))
函数的嵌套定义
def f1():
def f2():
print('from f2')
def f3():
print('from f3')
f3()
f2()
f1()
#执行f1的时候,f1()函数中定义了f2,并且要执行f2,得到from f2,同时在f2函数中定义了一个f3,并且要执行f3,得到from f3的结果
名称空间与作用域
名称空间
名称空间指的是:存放名字与值绑定关系的地方
加载顺序:内置->全局->局部名称空间
访问名字的顺序:局部->全局->内置名称空间
- 内置名称空间(python解释器启动就有)
python解释器内置的名字:max、len、print
- 全局名称空间(执行python文件时生效)
#文件级定义的名字
x=1
def fun():pass
import time
if x==1:
y=2
#这些都是全局名称空间
- 局部名称空间(函数调用时生效,调用结束后失效)
函数内部定义的名字
def fun():
x=21 #这个就是局部名称空间
作用域
- 全局作用域
内置名称空间与全局名称空间的名字,全局存活,全局有效,globals()
xxxxxxxx=1111111
print(globals())
>>>
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000000024ACA90>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/python20期课程/day3/函数.py', '__cached__': None, 'x': 1, 'func': <function func at 0x0000000002383EA0>, 'time': <module 'time' (built-in)>, 'y': 2,'xxxxxxxx':1111111}
- 局部作用域
局部名称空间的名字,临时存活,局部有效
xxxxxxxxx=111111111111111111111
def f1():
cccccc=222222
print(locals())
#注意,这个里面包含全局作用域的
>>>
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000000000247CA90>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/python20期 课程/day3/函数.py', '__cached__': None, 'x': 1, 'func': <function func at 0x00000000023D3EA0>, 'time': <module 'time' (built-in)>, 'y': 2,'xxxxxxxxx':111111111111111111111,'cccccc':222222}
x='gobal' #全局作用域的变量
def f1():
#x=1 #局部作用域的变量
def f2():
##x=2 #局部作用域的变量
def f3():
###x=3 #局部作用域的变量
print(x)
f3()
f2()
f1()
>>> #(打印的结果)
3
>2
>>1
>>>gobal
#这里的意思是最内层的函数找值,是由内到外的,一层一层的找
#局部变量升级全局变量使用global x
x=100
def func():
global x #把x升级为全局变量,此时func中的x=2进入全局作用域
x=2
func() #此时运行函数func(),x=2为全局变量,覆盖了x=100
print(x)
#锁定作用域
x='global'
def f1():
x=121
def f2():
nonlocal x #锁定作用域为局部作用域
# x=0
f2()
print('====f1 innter---->',x)
f1()
print(x)
注意俩点
- 打破函数层级限制来调用函数
def outter():
def inner():
print('inner')
return inner
print(outter()) #这里outter返回的值是函数inner的名字
a=outter() #a拿上inner函数返回的结果
def bar():
a() #执行a函数,就相当于执行了inner函数
bar()
>>>
<function outter.<locals>.inner at 0x000000000297CC80>
inner
- 函数的作用域关系是在函数定义阶段就已经固定了,与调用位置无关
x=1
def outter():
#x=2 #1、这里注释掉,让inner内部的x去找全局作用域的变量
def inner():
print('inner',x)
return inner
f=outter()
print(f)
x=123123123123123121312312312
def bar():
x=3
f() #2、在这里调用的f(),也就是inner函数
x=2334121231231233333333333333333333333333333333 #4、也就是最后找到的是这里的值
bar() #3、在这里执行bar() f()这个函数中有个x的变量名,应该找这里最新定义的变量的值
x=1111111111111111111111
闭包函数
- 定义在函数内部的函数,
- 该函数的函数体代码包含对外部作用域(而不是全局作用域)名称的引用
- 通常将闭包函数用return返回,然后可以在任意使用
- 爬页面:闭包函数为我们提供了一种新的为函数传参的方式
z=1
def outer():
x=1
y=2
def inner():
print(x,y)
return inner
f=outer() #这里的f指的是inner闭包函数的名字
print(f.__closure__[0].cell_contents) #查看指定元组所对应的应用上层参数的值
print(f.__closure__[0]) ##打印结果是元组,元组个数代表的是闭包所引用的上次函数的元素个数
print(f.__closure__[1].cell_contents)
print(f.__closure__) #结果是元组,可以使用索引的方式查看
import requests #pip3 install requests
def outter(url):
def get(url):
response=requests.get(url)
if response.status_code == 200:
print(len(response.text))
return get
baidu=outter('https://www.baidu.com')
python=outter('https://www.python.org')
baidu('https://www.baidu.com')
python('https://www.python.org')
闭包函数的应用—>装饰器
开放封闭原则:对扩展开放,对修改是封闭的
装饰器:装饰它人的,器指的是任意可调用对象,现在的场景装饰器-->函数,被装饰的对象也是-->函数
原则:
- 不修改被装饰对象的源代码,
- 不修改被装饰对象的调用方式
- 装饰器的目的:
- 在遵循1,2的前提下为被装饰对象添加上新功能
#步骤1
import time
def index():
time.sleep(1)
print('welecome to index')
start=time.time()
index()
stop=time.time()
print(stop - start)
#步骤2
import time
def index():
time.sleep(1)
print('welecome to index')
def inner():
start=time.time()
index()
stop=time.time()
print(stop - start)
inner()
#步骤3:把步骤二中的index取出来使用传参的方式传入
import time
def index():
time.sleep(0.5)
print('welecome to index')
def timmer(func): #使用形参传值
start=time.time()
func() #使用变量func
stop=time.time()
print(stop - start)
timmer(index) #传入index,修改了原代码的调用方式
#步骤4:把func放到timmer函数中,传参
import time
def index():
time.sleep(1)
print('welecome to index')
def timmer(func): #func的值为index
#func=index
def inner():
start=time.time()
func() #这里就相等于index()
stop=time.time()
print(stop - start)
return inner
index=timmer(index) #1、执行函数timmer(index)传值为index,返回值是innder这个闭包函数,然后赋值给index
index() #这里的index是闭包函数innder
装饰器的语法:在被装饰对象正上方单独一行写上,@装饰器名
无参装饰器(即@后面没有参数)
#改进1:使用@来使用装饰器
import time
def timmer(func):
def inner():
start=time.time()
func()
stop=time.time()
print(stop - start)
return inner
@timmer #index=timmer(index)
def index():
time.sleep(0.5)
print('welecome to index')
return 11111
a=index()
print(a) #返回为None
#改进2:原函数需要传值
import time
def timmer(func):
def inner(*regs,**kwargs):
start=time.time()
res=func(*regs,**kwargs)
stop=time.time()
print(stop - start)
return res
return inner
@timmer #index=timmer(index)
def home(name,*regs):
time.sleep(1)
print('home,%name',regs)
home('lqx',12,'male')
#实例加注解
import time
def outter(func):
def inner(*args,**kwargs): #这里inner中的参数会传给func,让func把参数传给真正的index
start=time.time()
res=func(*args,**kwargs) #如果真正的index有返回值,这里执行的结果也是有返回值的,所以赋值给res,把res,retrun出来,就可以把真正的index的执行结果打印出来
stop=time.time()
print(stop-start)
return res
return inner
@outter #index=outter(index) #这里执行的返回值是innder,并且把index的参数传给了func
def index(name): #如果这里的index需要传参,就需要知道最原始的别名对象的index了,也就是上面的func,传的参数,就应该由func带进来
time.sleep(1)
print('welecome to index %s'%name)
return 111
index('lqx') #这里的index实际上是inner函数
print(index('lqx')) #inner函数会执行func(真正的index函数),return的结果应该是真正的index函数的return结果
有参装饰器(即@后面有参数)
首先先实现三个需求:
1、原始函数实现一个认证功能
2、如果原始函数有形参
3、如果原始函数有返回值
# 先实现需求1:原始函数实现一个认证功能
import time
def outter(func):
def inner():
name=input('name>>>').strip()
passwd=input('passwd>>>').strip()
if name == 'lqx' and passwd == '123':
print('login seccussfull')
func()
else:
print('login err')
return inner
@outter
def index():
time.sleep(0.5)
print('welecome to index %s')
index()
#实现需求2:如果原始函数有形参
import time
def outter(func):
def inner(*args,**kwargs): #这里接受任意
name=input('name>>>').strip()
passwd=input('passwd>>>').strip()
if name == 'lqx' and passwd == '123':
print('login seccussfull')
func(*args,**kwargs) #那么这里也应该有参数
else:
print('login err')
return inner
@outter
def index(name,*args,**kwargs): #如果这里有参数
time.sleep(0.5)
print('welecome to index %s'%name)
index('lqx',18,231312) #如果这里有参数,那么上面的inner也应该有接受参数的形参
#实现需求3:如果原始函数有返回值
import time
def outter(func):
def inner(*args,**kwargs): #这里接受任意
name=input('name>>>').strip()
passwd=input('passwd>>>').strip()
if name == 'lqx' and passwd == '123':
print('login seccussfull')
res=func(*args,**kwargs) #那么这里也应该有参数
return res
else:
print('login err')
return inner
@outter
def index(name,*args,**kwargs): #如果这里有参数
time.sleep(0.5)
print('welecome to index %s'%name)
return 11112312312312312
a=index('lqx',18,231312) #如果这里有参数,那么上面的inner也应该有接受参数的形参
print(a)
有参装饰器:
import time
def auth(engine='file'):
def outter(func):
def inner(*args,**kwargs): #这里接受任意
if engine == 'file':
name=input('name>>>').strip()
passwd=input('passwd>>>').strip()
if name == 'lqx' and passwd == '123':
print('login seccussfull')
res=func(*args,**kwargs) #那么这里也应该有参数
return res
else:
print('login err')
elif engine == 'mysql':
print('login')
else:
print('login err')
return inner
return outter
# engine='file'
@auth(engine='file') #outter #index=auth(index)
#@outter
def index(name,*args,**kwargs): #如果这里有参数
time.sleep(0.5)
print('welecome to index %s'%name)
return 11112312312312312
a=index('lqx',18,231312) #如果这里有参数,那么上面的inner也应该有接受参数的形参
print(a)
并行多个装饰器
这里的意思的用俩个装饰器,第一个装饰器修饰第二个装饰器,第二个装饰器修饰下面的原函数。因此,这里的第一个装饰器一定是一个可以完全修饰任意原函数的一个装饰器
import time
def timmer(func):
def inner(*args,**kwargs):
start=time.time()
res=func(*args,**kwargs)
stop=time.time()
print(stop - start)
return res
return inner
def auth2(engine='file'):
def auth(func):
def inner(*reags,**kwargs):
if engine == 'file':
name=input('name>>>').strip()
passwd=input('passwd>>>').strip()
if name == 'lqx' and passwd == '123':
print('login successfull')
res=func(*reags,**kwargs)
return res
else:
print('login err')
elif engine == 'mysql':
print('mysql auth')
else:
print('login err')
return inner
return auth
@timmer
@auth2(engine='file')
def index(name,*args):
time.sleep(1)
print('welecome %s to index'%name)
return 12341234123123123123123131231232132131231231
a=index('lqx',123,'age','sex')
print(a)
wraps注释信息伪装
使用模块wraps,实际上这个wraps也是一个装饰器,
只要把@wraps,放到原函数的传值的上面就可以实现
然后在原函数的后面执行print(help(原函数)),就可以看到原函数的注释信息
from functools import wraps #注释信息伪装
import time
def timmer(func):
@wraps(func) #注释信息模块
def inner(*args,**kwargs):
start=time.time()
res=func(*args,**kwargs)
stop=time.time()
print(stop - start)
return res
# inner.__doc__ = func.__doc__ # 把index的注释信息赋值给inner
# inner.__name__=func.__name__ #把index的注释新的的名字也赋值给inner
return inner
@timmer
def index(name):
'''index 函数。。。。。'''
time.sleep(1)
print('welecome %s to index'%name)
return 12341234123123123123123131231232132131231231
print(help(index))