一、函数的对象
函数对象:函数是第一类对象,即函数可以当作数据传递
1、可以被引用
1 def foo(): 2 print('from foo') 3 func = foo 4 print(foo) #不加扩号为foo函数的内存地址 5 print(func) #func指向foo的内存地址 6 func() #加扩号执行func函数,也就是执行foo的代码 7 8 """ 9 输出: 10 <function foo at 0x0000000000613E18> 11 <function foo at 0x0000000000613E18> 12 from foo 13 """
2、可以当作参数传递
1 def foo(): 2 print('from foo') 3 def bar(func): 4 print(func) #func指向foo的内存地址 5 func() #执行func参数,实际执行的是foo 6 bar(foo) #foo做为bar函数的参数 7 """ 8 输出 9 <function foo at 0x0000000002113E18> 10 from foo 11 """
3、返回值可以是函数
1 def foo(): 2 print('from foo') 3 4 def bar(func): 5 return func #返回func参数也就是foo函数的内存地址 6 7 f=bar(foo) #foo函数做为bar的参数,把foo的内存地址赋值给f 8 print(f) #打印f的内存地址 9 f() #执行f,也就是执行foo 10 """ 11 输出: 12 <function foo at 0x0000000002473E18> 13 from foo 14 """
4、可以当作容器类型的元素
1 def foo(): 2 print('from foo') 3 dic={'func':foo} #定义字典,key为func,value为foo函数的内存地址 4 print(dic['func']) #打印dic字典中key func对应的值,也就是foo的内存地址 5 dic['func']() #加扩号执行字典的value,也就是执行foo. 6 """ 7 输出: 8 <function foo at 0x0000000000773E18> 9 from foo 10 """
5、应用
1 def select(sql): #定义select函数,传入sql形参 2 print('========>select') 3 4 def insert(sql): 5 print('========>add') 6 7 def delete(sql): 8 print('=======>delete') 9 10 def update(sql): 11 print('-=---->update') 12 13 14 func_dic={ #定义func_dic字典,将函数做为字典的value值 15 'select':select, 16 'update':update, 17 'insert':insert, 18 'delete':delete 19 } 20 21 def main(): #定义main函数 22 while True: 23 sql = input('>>: ').strip() #输入内容赋值给sql变量 24 if not sql:continue #判断sql不为空则继续,为空则退出 25 l = sql.split() #sql变量切割成列表赋值给l 26 cmd=l[0] #将l列表的索引0位置的值赋值给cmd 27 if cmd in func_dic: #判断cmd的内容在func_dic字典中 28 func_dic[cmd](l) #则找到cmd内容在字典中对应的value值,并扩号执行value对应的函数. 29 30 main() #调用main函数 31 32 """ 33 输出: 34 >>: select * from tables; 35 ========>select 36 """ 37 38 39 def main(): 40 sql = input('>>: ') 41 l = sql.split() 42 print(l) #打印l列表,也就是sql变量切割后的内容 43 if l[0] == 'select': #判断l列表的索引0位置的值等于 select 44 select(1) #则执行select函数,并将l列表的索引0做为参数 45 elif l[0] == 'insert': 46 insert(l) 47 elif l[0] == 'delete': 48 delete(l) 49 elif l[0] == 'update': 50 update(l) 51 52 main() #调用main函数 53 """ 54 输出: 55 >>: select * from tables; 56 ['select', '*', 'from', 'tables;'] 57 ========>select 58 """
二、 名称空间与作用域
1、定义名字的方法
a.导入系统模块
import time
b.定义变量
name='egon'
c.自定义函数
def func(): pass
d.定义类
class Foo: pass
2、三种名称空间
1)内置名称空间:随着python解释器的启动而产生
1 print(sum) #内置名称空间 2 print(max) 3 print(min) 4 print(max([1,2,3])) 5 6 import builtins #导入builtins模块, 7 for i in dir(builtins): #查看所有内置名称空间 8 print(i)
2)全局名称空间:在当前文件中,以及文件的执行会产生全局名称空间,指的是文件级别定义的名字都会放入该空间
1 x=1 #全局变量x=1 2 def func(): #定义函数 3 money=2000 4 x=2 #在函数内定义x=2 5 print(func) 6 func() #执行函数,可以调到全局变量 7 print(x) #打印x ,x仍然等于1,局部x=2 没有调到,说明应用的是当前文件,也就是全局名称空间 8 print(money) #money属于局部变量,调用不了 9 """ 10 输出: 11 <function func at 0x0000000002133E18> 12 1 13 """
3)局部名称空间:调用函数时会产生局部名称空间,只在函数调用时临时绑定,调用结束解绑定
x=10000 def func(): x = 1 #局部变量 print(x) def f1(): pass func() #执行函数时打印函数内的局部变量x=1 """ 输出: 1 """ print(x) #直接打印应用全局变量 x=10000 """ 输出: 10000 """
3、作用域
1)作用域:为名称空间的具体应用。
2)作用域与名称空间的对应关系:
全局作用域:内置名称空间,全局名层空间。
局部作用:局部名称空间。
1 x=1 #全局后生效 2 def func(): 3 x=2 #局部优先生效 4 print(x) 5 sum=123123 6 print(sum) 7 func() 8 """ 9 输出: 10 2 11 123123 12 """ 13 14 x = 1 15 def func(): 16 x=2 17 18 func() 19 print(x) 20 """ 21 输出: 22 1 23 """
4)名字的查找顺序:局部名称空间---》全局名层空间---》内置名称空间
全局作用域:全局有效,在任何位置都能被访问到,除非del删掉,否则会一直存活到文件执行完毕。
局部作用域的名字:局部有效,只能在局部范围调用,只在函数调用时才有效,调用结束就失效。
1 """ 2 查看全局作用域内的名字:gloabls() 3 查看局局作用域内的名字:locals() 4 """ 5 6 x=1000 7 def func(): 8 x=2 9 # 在局部作用域中,打印全局作用域中的名字,在该作用域中x等于1000 10 print(globals()) 11 # 在局部作用域中,打印局部作用域的名字,执行结果为x等于2 {'x': 2} 12 print(locals()) 13 func() 14 """ 15 输出: 16 {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000002579240>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/python/S17/day04/s1.py', '__cached__': None, 'x': 1000, 'func': <function func at 0x00000000006B3E18>} 17 {'x': 2} 18 """ 19 print(globals()) #在全局作用域中,打印全局作用域中的名字,x等于1000 20 print(locals()) #在全局作用域中,打印局部作用域的名字,一层一层应用,因为当前在全局中没有局部,所以应用全局中的名字,x也等于1000 21 print(globals() is locals()) #在全局作用域中,判断全局名字是否在局部中,如果是返回True 22 """ 23 输出: 24 {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000002739240>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/python/S17/day04/s1.py', '__cached__': None, 'x': 1000, 'func': <function func at 0x0000000002483E18>} 25 {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000002739240>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/python/S17/day04/s1.py', '__cached__': None, 'x': 1000, 'func': <function func at 0x0000000002483E18>} 26 True 27 """
三、闭包
1、闭包,函数嵌套的一种方式,必须遵守以下规则:
a.定义在内部函数
b.包含对外部作用域而非全局作用域的引用,该内部函数就成为闭包函数
1 def f1(): #定义闭包,对象隐藏,全局不可见 2 x = 1 #x内部隐藏,全局不可见 3 def f2(): 4 print(x) #应用外部作用域,x=1 5 return f2 6 print(f1()) # return返回值为f2 ,所以f1执行结果就是f2的返回值也就是f2的内存地址 7 a = f1() #把f1的返回值也是就f2的内存地址 赋值给a 8 x=2 # 全局中x=2 9 a() #执行a就会执行f2里的代码,应用闭包中的x=1,而非全局中的x=2 10 11 """ 12 输出: 13 <function f1.<locals>.f2 at 0x00000000025EAEA0> 14 1 15 """
2、闭包应用:惰性计算
1 # 爬网页,旧方法获取网页所有代码内容 2 from urllib.request import urlopen #导入模块 3 res=urlopen('http://crm.oldboyedu.com').read() 4 print(res.decode('utf-8')) 5 6 7 from urllib.request import urlopen 8 def index(url): 9 def get(): 10 return urlopen(url).read() 11 12 return get 13 #存在内存里 14 oldboy=index('http://crm.oldboyedu.com') 15 #什么时候想用,什么时候用 16 print(oldboy().decode('utf-8')) #获取打印网页所有代码内容 17 # 闭包函数相对与普通函数会多出一个__closure__的属性,里面定义了一个元组用于存放所有的cell对象, 18 # 每个cell对象一一保存了这个闭包中所有的外部变量 19 print(oldboy.__closure__[0].cell_contents) 20 """ 21 输出: 22 http://crm.oldboyedu.com 23 """ 24 25 26 x=1 27 # y=2 28 def f1(): 29 # x=1 30 y=2 31 def f2(): 32 print(x,y) 33 return f2 34 35 f=f1() 36 print(f.__closure__[0].cell_contents) 37 """ 38 输出: 39 2 40 """
四、装饰器
1、装饰器:修饰别人的工具,修饰添加功能,工具指的是函数。
装饰器本身可以是任何可调用对象,被装饰的对象也可以是任意可调用对象。
2、为什么要用装饰器:
开放封闭原则:对修改是封闭的,对扩展是开放的
装饰器就是为了在不修改被装饰对象的源代码以及调用方式的前提下,为其添加新功能。
3、装饰器的基本写法
1 """ 2 给index函数使用装饰器增加执行时间 3 """ 4 import time 5 6 def timmer(func): 7 def wrapper(): 8 start_time=time.time() #在执行函数前执行,获取当前时间,执行开始时间 9 func() #执行函数,默认没有返回值 10 stop_time=time.time() #在执行函数后执行,获取当前时间,执行结束时间 11 print('run time is %s' %(stop_time-start_time)) 12 return wrapper 13 14 @timmer #给index函数增加装饰器 流程分析 index=timmer(index) 15 def index(): 16 time.sleep(3) 17 print('welcome to index') 18 19 index() #执行index函数,流程分析 wrapper(index)->index() 20 """ 21 输出: 22 welcome to index 23 run time is 3.0001718997955322 24 """
4、装饰器,一次定义,多次使用
1 import time 2 def timmer(func): 3 def wrapper(*args,**kwargs): # 传递参数,保证通用性,应为可变长参数(*args,**kwargs),可接受所有类型的实参 4 start_time=time.time() 5 res=func(*args,**kwargs) #有返回值,存值 6 stop_time=time.time() 7 print('run time is %s' %(stop_time-start_time)) 8 return res #有返回值,返回 9 return wrapper #返回值,返回wrapper的内存地址 10 11 @timmer #index=timmer(index) 12 def index(): 13 time.sleep(3) 14 print('welcome to index') 15 return 1 #有返回值,需要在装饰器中定义并存值 16 17 @timmer #再次使用装饰器 18 def foo(name): 19 time.sleep(1) 20 print('from foo') 21 22 #有返回值,传值打印 23 res=index() #wrapper() 24 print(res) 25 26 res1=foo('merry') #res1=wrapper('merry') 27 print(res1) 28 29 """ 30 输出: 31 welcome to index 32 run time is 3.000171661376953 33 1 34 from foo 35 run time is 1.0000569820404053 36 None 37 """
登录认证装饰器,一次定义,多次使用,因为使用了装饰器两个函数分别执行,且未保存第一次登录成功,所以需要输入两次账号密码
1 def auth(func): 2 def wrapper(*args,**kwargs): 3 name=input('>>: ') 4 password=input('>>: ') 5 if name == 'merry' and password == '123': 6 print('