一、函数之名称空间
1.1、什么是名称空间
名称空间:存放名字的地方
例子:S=1,1存放于内存中,那名字 S 存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方
1.2、名称空间 (存放名字与值的绑定关系)
1、内置名称空间
存放python解释器自带名字,比如内置的函数名:len,max,sum
创建:随着python解释器启动而创建
销毁:随着python解释器关闭而销毁
2、全局名称空间
存放文件级别的名字,比如x,f1,z
x=1
def f1():
y=2
if x == 1:
z=3
创建:文件开始执行时则立即创建
销毁:文件开始执行完毕时则销毁
3、局部名称空间
存放函数内的名字,强调:函数的参数也属于局部的
创建:函数执行时才临时创建
销毁:函数执行完毕则立即销毁
4、名称空间的加载顺序
内置名称空间--->全局名称空间--->局部名称空间
强调:加载的目的是为了把名字存起来,存起来的目的是为了取出来,那么但凡查找一个名字一定会从三种名称空间之一找到。
5、名称空间的查找名字顺序
局部名称空间===>全局名称空间===>内置名称空间
例子:名称空间加载顺序与名称空间查找名字顺序使用案例:
len=10
def f1():
# len=100
def f2():
# len=1000
def f3():
# len=10000
print(len)
f3()
# len=200
f2()
len=11111111111 #这里相当于修改了全局定义的'len=10',修改为'len=11111111111'
f1()
len=11111111111
函数的查找关系是在函数定义阶段就已经固定死的,与调用位置无关
# 函数名字的查找关系是在函数定义阶段就已经固定死的,与调用位置无关
x=100
def f1():
x=10
print(x)
def f2():
x=111111
f1()
f2()
>>:10
二、作用域
全局范围:内置名称空间中的名字,全局名称空间中的名字
特点:全局有效,全局存活
局部范围:局部名称空间中的名字
特点:局部有效,临时存活
全局变量:定义在全局作用域的名字
局部变量:定义在局部作用域的名字
2.1、当全局数据类型是可变类型时,在函数内是可以修改的
l=[] #全局类型(可变数据类型)
def foo1():
l.append(2) #在函数内往全局类型里面追加数据
foo1()
print(l)
>>:[2] #追加完毕后,全局类型l的值已经为[2]
2.2、当全局数据类型是不可变类型时,在函数内不能修改
L=100 #全局类型(不可变类型)
def foo1():
L=222 #在函数内定义L的值为222
foo1()
print(L)
>>:100 #执行后全局类型L的值并没有被修改
2.3、global与nonlocal
1、global用法(改全局变量的值):如果全局数据类型是不可变类型时,在函数内想要修改该变量的值的话。(global这种方式最好少用,因为改全局变量的值后,其他代码调用这个全局变量时也会修改)
L=100 #全局类型(不可变类型)
def foo1():
global L #使用global则声明:L为全局类型
L=222 #在函数内定义L的值为222
foo1()
print(L)
>>:222 #执行后全局类型L的值就被修改为222
2、nonlocal用法(修改当前上一层变量的值,如果没有则报错):nonlocal会从当前外一层开始查找,一直查找到最外层的函数,如果没有找到则报错
def foo1():
x=10
def foo2():
nonlocal x #使用nonlocal则声明:x是当前函数外层的变量
x=100
foo2()
print(x) #在此处打印函数foo1内x的值
foo1()
>>:100
三、函数对象
函数可以当做变量去处理 (把函数想想成一个变量) ,那么:
1、函数可以被赋值
def foo():
print('from foo')
f = foo
print(foo)
print(f)
foo()
f()
>>:<function foo at 0x000002401456AC80> #这是执行print(foo) 得到的
>>:<function foo at 0x000002401456AC80> #这是执行print(f) 得到的
>>:from foo #这是执行foo() 得到的
>>:from foo #这是执行f() 得到的
2、函数可以当做参数传给一个函数
def foo():
print('from foo')
print(foo)
def bar(func): # func=foo
print(func)
func()
bar(foo) #执行函数bar时传参数为"foo(foo为函数),那么func接收到的值就为函数'foo'"
>>:<function foo at 0x000002B418DFAD08> #这是执行print(func) 得到的
>>:from foo #这是执行func() 得到的,运行func()就相当于运行了foo()
>>:<function foo at 0x000002B418DFAD08> #这是执行print(foo)得到的
3、可以当做函数的返回值
def bar():
print('from bar')
def foo(func): # func=bar
return func # return bar
f=foo(bar)
此时:f就等于函数bar,它们内存地址都是一样的
print(f)
得到的值:<function bar at 0x000001DE62D23E18>
print(bar)
得到的值:<function bar at 0x000001DE62D23E18>
那么执行f()就相当于执行函数bar()
f()
得到的值:from bar
bar()
得到的值:from bar
4、可以当做容器类型元素 (这个功能常常用到)
def get():
print('from get')
def put():
print('from put')
def ls():
print('from ls')
def login():
print('from login')
main_dict={
'1':[get,'下载'],
'2':[put,'上传'],
'3':[ls,'查看'],
'4':[login,'登录'],
}
def run():
while True:
print("----------------------")
for n in main_dict:
print(n,main_dict[n][1])
print('输入 "q" 或者 "exit" 即可退出程序!')
print("----------------------")
choose=input('pls input num:> ').strip()
if len(choose) == 0:continue
if choose == 'q' or choose == 'exit':break
if choose in main_dict:
main_dict[choose][0]()
run()
四、闭包函数 == [函数嵌套+名称空间与作用域+函数对象] 三者的综合应用
1、什么是闭包函数?
函数内的函数。
强调:函数外层指的不是全局作用域(而是函数内部的)。
满足上述两个条件,那么该内部函数就称之为闭包函数。
闭包指的是一个概念,总结了:函数的作用域关系是在函数定义阶段就已经固定死的,与调用位置无关。
闭包:闭的概念指的是,这个函数一定是来自于函数内的。
包的概念指的是,这个res函数拿到的不仅仅是函数本身所具有的的数据,而是包裹了x=1这个值,那么也就是说不管以后在哪里调用这个res函数,包裹的x=1这个值始终不变,x的值始终为1。
9.5.1、闭包函数简单例子理解
def outner():
x=1
def inner():
print(x)
return inner
res=outner() #此时的函数res可以看出是一个全局变量,在任何地方都可以被引用--用到了函数对象的概念。[函数outner()就相当于函数inner,那么给inner函数赋值给res的话,函数res==函数inner]
res() #那么在执行函数res()就相当于执行函数inner()
>>:1
def foo(): #res函数也可以被其他函数调用(函数res已经是全局变量了--用到了函数对象的概念)
print('from foo')
res()
foo()
>>:from foo
>>:1
9.5.2、闭包函数生产小例子
def sudada(url): #函数内传参和在函数()传参是一样的
# url='https://www.baidu.com' #函数内传参和在函数()传参是一样的
def foo():
import requests
response=requests.get(url)
if response.status_code == 200:
print(response.text)
return foo
baidu=sudada('https://www.baidu.com') #变量baidu其实等于函数foo
python=sudada('https://www.python.org') #变量python其实等于函数foo
baidu() #执行函数baidu(),就相当于执行函数foo()
python() #执行函数python(),就相当于执行函数foo()
五、装饰器
装饰器常用(套用)格式:
def outter(func):
def wrapper():
#代码1
#代码2
#代码n...
return wrapper
1 开放封闭原则
软件一旦上线之后就应该遵循开放封闭原则
具体是指对修改是封闭的,但对扩展是开放的
2、什么是装饰器
装饰就是修饰,器指的就是工具
装饰器本身: 可以是任意可调用的对象 --->>函数
被装饰的对象:也可以是任意可调用的对象 --->>函数
3、装饰器是用来为被装饰对象添加新功能的一种工具
必须遵循:
1、不能修改被装饰对象的源代码
2、不能修改被装饰对象的调用方式
9.6.1、装饰器例子1:
需求:查看一个index函数调用,花费了多长时间
-------------------------------------------方法1----------------------------------------
1、简单实现需求:定义一个outer函数,在outer函数里面调用index函数,在上一些逻辑判断即可实现
import time
def index():
time.sleep(1)
print('welcome to index')
def outer(func):
start_time = time.time()
func()
stop_time = time.time()
print('run time is %s' %(stop_time - start_time))
outer(index)
得到的值如下:
welcome to index
run time is 1.000652551651001
-------------------------------------------方法2----------------------------------------
# 实现需求2:定义一个outer函数,在outer函数里面再定义一个wrapper函数,通过wrapper函数来拿到index函数调用花费的时间,\
# 然后return wrapper函数,那么调用outer函数时就会拿到一个返回值,我们可以把这个返回值定义为 "index" 那么使用 "index" 函数时 \
# 就相当于调用outer函数内的wrapper函数,实现的装饰器的作用!
import time #导入time模块
def index(): [被装饰对象] #定义函数index(),在不改变函数index()的情况下,求执行"print('welcome to index')"这段代码的开始时间与结束时间
time.sleep(1)
print('welcome to index')
def outter(func): [装饰器] #func是outter函数的一个参数
def wrapper(): #wrapper就是用来统计时间差,这么一个功能
start_time=time.time()
func() #在wrapper函数内调用func()时,先在wrapper函数内找(wrapper函数内没有),然后在outter函数内找
stop_time=time.time()
print('run time is %s' %(stop_time - start_time))
return wrapper #返回函数wrapper的内存地址
#把outter(index)[内存地址]复制给index[这里index指的是一个变量名,无意义]
index=outter(index) #函数outter(index)实际上就是函数wrapper的内存地址
#或者说调用wrapper函数,就相当于调用index(原始)函数
index() #执行函数index(),就相当于执行了函数wrapper()。{同时wrapper()==index()}
得到的值如下:
welcome to index
run time is 1.000652551651001
9.6.2、装饰器例子2:原始函数index里面需要返回值时(return)
import time
def index():
time.sleep(1)
print('welcome to index')
return 123 #这里让函数返回123
def outter(func):
def wrapper(): #wrapper函数的功能就是:1.测试index函数运行时间,2.拿到Index函数的返回值123
start_time=time.time()
res=func() #把返回值赋值给res
stop_time=time.time()
print('run time is %s' %(stop_time - start_time))
return res #在返回index函数的返回值
return wrapper
index=outter(index)
res=index()
print(res)
>>:welcome to index
>>:run time is 1.0006911754608154
>>:123
9.6.2、装饰器语法糖:在被装饰对象正上方单独一行写@装饰器的名字
def timmer(func): [装饰器名称]
def wrapper(*args,**kwargs):....
return wrapper
@timmer [装饰器语法糖]
def index():.... [被装饰对象]
@timmer [装饰器语法糖]
def home(name):.... [被装饰对象]
9.6.3、无参装饰器
import time
def timmer(func):
def wrapper(*args,**kwargs): #可以接受任意值[*接受所有溢出的位置参数,**接受所有的关键字参数]
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s' %(stop_time - start_time))
return res
return wrapper
@timmer # index=timmer(index)
def index(): #无参函数
time.sleep(1)
print('welcome to index')
return 1234
@timmer # home=timmer(home) home('sudada') 这里的"sudada"传的值由wrapper(*args,**kwargs)接收。
def home(name): #有参函数,参数name
time.sleep(2)
print('welcome %s to home page' %name)
index() #此处的函数index是被装饰器timmer装饰后的,而不是原始的index函数
>>:welcome to index
>>:run time is 1.000145673751831
home('sudada') #此处的函数home是被装饰器timmer装饰后的,而不是原始的home函数
>>:welcome egon to home page
>>:run time is 2.000617265701294
9.6.4、有参装饰器
import time
current_user={'login':False}
def auth(engine):
def outter(func):
def wrapper(*args,**kwargs): # 这是一个闭包函数
if current_user['login']:
return func(*args,**kwargs) # 这调用的是被装饰的函数[index()或者home(name)],并返回执行结果
user=input('username>>>: ').strip() #用户登录
pwd=input('password>>>: ').strip()
if engine == 'file': #判断以哪种方式打开
if user == 'egon' and pwd == '123':
current_user['login']=True
return func(*args,**kwargs) # 这调用的是被装饰的函数[index()或者home(name)],并返回执行结果
elif engine == 'mysql':
print('基于mysql数据的认证')
return func(*args, **kwargs)
elif engine == 'ldap':
print('基于ldap的认证方式')
return func(*args, **kwargs)
return wrapper # 返回闭包函数的执行结果
return outter # 返回闭包函数的执行结果
@auth(engine='mysql') # @outter # index=outter(index) #index=wrapper
def index():
time.sleep(1)
print('welcome to index')
return 1234
@auth(engine='ldap') # @outter # home=outter(home) #home=wrapper
def home(name):
time.sleep(2)
print('welcome %s to home page' %name)
index()
# username>>>: szq
# password>>>: 123
# 基于mysql数据的认证
home('egon')
# username>>>: egon
# password>>>: 123
# 基于ldap的认证方式