第一阶段:Python开发基础 day13 闭包函数 装饰器 迭代器
目录
上节课内容回顾# 可变长参数 * *args: 接收多余的位置实参 *(): 打散元组内的元素当做位置实参传给形参 ** **kwargs: 接收多余的关键字实参 **{}:打散字典的元素作为关键字实参传给形参 # 函数对象 函数名和变量名是等同的 1. 引用 2. 函数的参数 3. 函数的返回值 4. 容器类元素 # 函数的嵌套 ```python def f1(): def f2(): pass ``` ## 函数的调用 ```python def f1(): pass f1() def f2(): f1() # 函数必须得先定义后调用 ``` # 名称空间与作用域 ## 内置名称空间 Python解释器的内置方法,如 len/int/float,python解释器启动的时候就有了 ## 全局名称空间 python文件执行的时候生成 ## 局部名称空间 函数调用的时候生成 执行顺序 内置-->全局-->局部 查找顺序 当前位置开始 局部-->全局-->内置 ## 全局作用域 内置+全局 ## 局部作用域 局部 1. 全局作用域内的变量(x=1)和局部作用域内的变量(x=1),两个x没有任何关系,只针对不可变类型 2. 局部作用域1内变量(x=1)和局部作用域2内变量(x=1),两个x也没有任何关系,只针对不可变类型 一、闭包函数回顾:
def f1(): x = 1 def inner(): print(x) return inner func = f1() x = 2 def f2(): x = 3 func() f2() 1 一、什么是闭包? 闭包:闭是封闭(函数内部函数),包是包含(该内部函数对外部作用域而非全局作用域的变量的引用)。闭包指的是:函数内部函数对外部作用域而非全局作用域的引用。 提示:之前我们都是通过参数将外部的值传给函数,闭包提供了另外一种思路,包起来喽,包起呦,包起来哇。 def outter(): x = 1 def inner(): print(x) return inner f = outter() def f2(): x = 2 f() 1.1 两种为函数传参的方式为函数传参的方式一:使用参数的形式 def func(x): print(x) func(1) func(1) func(1) 为函数传参的方式二:包给函数 def outter(x): x = 1 def inner(): print(x) return inner f = outter(1) f() f() f() # 查看闭包的元素 print(F"f.__closure__[0].cell_contents: {f.__closure__[0].cell_contents}") 二、闭包函数的应用闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。 应用领域:延迟计算(原来我们是传参,现在我们是包起来)、爬虫领域。 import requests def get(url): response = requests.get(url) print(f"done: {url}") get('https://www.baidu.com') get('https://www.baidu.com') get('https://www.baidu.com') get('https://www.cnblogs.com/linhaifeng') get('https://www.cnblogs.com/linhaifeng') get('https://www.cnblogs.com/linhaifeng') 上面的方式是极其复杂的,我们如果使用默认参数也只能解决一个网址,因此我们可以考虑使用闭包的方式。 import requests def outter(url): def get(): response = requests.get(url) print(f"done: {url}") return get baidu=outter('https://www.baidu.com') python = outter('https://www.python.org') baidu() baidu() python() python() 二、装饰器一、无参装饰器1.1 什么是装饰器?器指的是工具,而程序中的函数就是具备某一功能的工具,所以装饰器指的是为被装饰器对象添加额外功能。因此定义装饰器就是定义一个函数,只不过该函数的功能是用来为其他函数添加额外的功能。 需要注意的是:
1.2 为什么要用装饰器?如果我们已经上线了一个项目,我们需要修改某一个方法,但是我们不想修改方法的使用方法,这个时候可以使用装饰器。因为软件的维护应该遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能指的是开放的。 装饰器的实现必须遵循两大原则:
装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。 1.3 怎么用装饰器?改变源代码 import time def index(): start = time.time() print('welcome to index') time.sleep(1) end = time.time() print(F"index run time is {start-end}") index() 编写重复代码 import time def index(): print('welcome to index') time.sleep(1) def f2(): print('welcome to index') time.sleep(1) start = time.time() index() end = time.time() print(F"index run time is {start-end}") start = time.time() f2() end = time.time() print(F"f2 run time is {start-end}") 第一种传参方式:改变调用方式 import time def index(): print('welcome to index') time.sleep(1) def time_count(func): start = time.time() func() end = time.time() print(f"{func} time is {start-end}") time_count(index) 第二种传参方式:包给函数-外包 import time def index(): print('welcome to index') time.sleep(1) def time_count(func): # func = 最原始的index def wrapper(): start = time.time() func() end = time.time() print(f"{func} time is {start-end}") return wrapper # f = time_count(index) # f() index = time_count(index) # index为被装饰函数的内存地址,即index = wrapper index() # wrapper() 1.4 完善装饰器上述的装饰器,最后调用index()的时候,其实是在调用wrapper(),因此如果原始的index()有返回值的时候,wrapper()函数的返回值应该和index()的返回值相同,也就是说,我们需要同步原始的index()和wrapper()方法的返回值。 import time def index(): print('welcome to index') time.sleep(1) return 123 def time_count(func): # func = 最原始的index def wrapper(): start = time.time() res = func() end = time.time() print(f"{func} time is {start-end}") return res return wrapper index = time_count(index) res = index() print(f"res: {res}") 如果原始的index()方法需要传参,那么我们之前的装饰器是无法实现该功能的,由于有wrapper()=index(),所以给wrapper()方法传参即可。 import time def index(): print('welcome to index') time.sleep(1) return 123 def home(name): print(f"welcome {name} to home page") time.sleep(1) return name def time_count(func): # func = 最原始的index def wrapper(*args,**kwargs): start = time.time() res = func(*args,**kwargs) end = time.time() print(f"{func} time is {start-end}") return res return wrapper home = time_count(home) res = home('egon') print(f"res: {res}") 1.5 装饰器语法糖在被装饰函数正上方,并且是单独一行写上 import time def time_count(func): # func = 最原始的index def wrapper(*args,**kwargs) end = time.time() print(f"{func} time is {start-end}") return res return wrapper @time_count # home = time_count(home) def home(name): print(f"welcome {name} to home page") time.sleep(1) return name @time_count # index = time_count(index) def index(): print('welcome to index') time.sleep(1) return 123 res = home('egon') print(f"res: {res}") 1.6 装饰器模板def deco(func): def wrapper(*args,**kwargs): res = func(*args,**kwargs) return res return wrapper 二、有参装饰器无参装饰器只套了两层,本节将讲一个套三层的装饰器——有参装饰器,但现在我们先实现一个用户登录注册的装饰器。 import time current_user = {'username': None} def login(func): # func = 最原始的index def wrapper(*args,**kwargs): if current_user['username']: res = func(*args,**kwargs) return res user = input('username: ').strip() pwd = input('password: ').strip() if user == 'nick' and pwd == '123': print('login successful') current_uesr['usre'] = user res = func(*args,**kwargs) return res else: print('user or password error') return wrapper @login def home(name): print(f"welcome {name} to home page") time.sleep(1) return name @login def index(): print('welcome to index') time.sleep(1) return 123 res = index() 对于上面的登录注册,我们把用户登录成功的信息写入内存当中。但是在工业上,用户信息可以存在文本中、mysql中、mongodb当中,但是我们只让用户信息来自于 import time current_user = {'username': None} def login(func): # func = 最原始的index def wrapper(*args,**kwargs): if current_user['username']: res = func(*args,**kwargs) return res user = input('username: ').strip() pwd = input('password: ').strip() engine = 'file' if engine == 'file': print('base of file') if user == 'nick' and pwd == '123': print('login successful') current_uesr['usre'] = user res = func(*args,**kwargs) return res else: print('user or password error') elif engine == 'mysql': print('base of mysql') elif engine == 'mongodb': print('base of mongodb') else: print('default') return wrapper @login def home(name): print(f"welcome {name} to home page") time.sleep(1) @login def index(): print('welcome to index') time.sleep(1) res = index() 2.1 三层闭包我们首先看看闭包,包三层怎么运用。 def f1(y): def f2(): x = 1 def f3(): print(f"x: {x}") print(f"y: {y}") return f3 return f2 f2 = f1(2) f3 = f2() f3() 现在需求改了,我们需要判断用户动态的获取用户密码的方式,如果是 import time current_uesr = {'username': None} def auth(engine='file'): def login(func): # func = 最原始的index def wrapper(*args,**kwargs): if current_user['username']: res = func(*args,**kwargs) return res user = input('username: ').strip() pwd = input('password: ').strip() if engine == 'file': print('base of file') if user == 'nick' and pwd == '123': print('login successful') current_uesr['usre'] = user res = func(*args,**kwargs) return res else: print('user or password error') elif engine == 'mysql': print('base of mysql,please base of file') elif engine == 'mongodb': print('base of mongodb,please base of file') else: print('please base of file') return wrapper return login @auth(engine='mysql') def home(name): print(f"welcome {name} to home page") time.sleep(1) @auth(engine='file') def index(): print('welcome to index') time.sleep(1) res = index() 由于两层的装饰器,参数必须得固定位 三、迭代器迭代器:迭代的工具。迭代是更新换代,如你爷爷生了你爹,你爹生了你,迭代也可以说成是重复,并且但每一次的重复都是基于上一次的结果来的。如计算机中的迭代开发,就是基于软件的上一个版本更新。以下代码就不是迭代,它只是单纯的重复 while True: print('*'*10) 一、可迭代对象python中一切皆对象,如 x = 1 name = 'nick' lis = [1,2] tup = (1,2) dic = {'name': 'nick'} s1 = {'a','b'} def func(): pass f = open('49w.txt','w',encoding='utf-8) 对于这一切的对象中,但凡有 # x = 1.__iter__ # SyntaxError: invalid syntax # 以下都是可迭代的对象 name = 'nick'.__iter__ lis = [1,2].__iter__ tup = (1,2).__iter__ dic = {'name': 'nick'}.__iter__ s1 = {'a','b'}.__iter__ f = open('49w.txt',encoding='utf-8') f.__iter__ f.close() 1.1 总结可迭代的对象:Python内置str、list、tuple、dict、set、file都是可迭代对象。 特点:
二、迭代器对象只有字符串和列表都是依赖索引取值的,而其他的可迭代对象都是无法依赖索引取值的。因此我们得找到一个方法能让其他的可迭代对象不依赖索引取值。 在找到该方法前,首先我们给出迭代器对象的概念:可迭代的对象执行 # 不依赖索引的数据类型迭代取值 dic = {'a': 1,'b': 2,'c': 3} iter_dic = dic.__iter__() print(iter_dic.__next__()) print(iter_dic.__next__()) print(iter_dic.__next__()) # print(iter_dic.__next__()) # StopIteration: a b c # 依赖索引的数据类型迭代取值 lis = [1,2,3] iter_lis = lis.__iter__() print(iter_lis.__next__()) print(iter_lis.__next__()) print(iter_lis.__next__()) # print(iter_lis.__next__()) # StopIteration: 1 2 3 上述的方法是非常繁琐的,我们可以使用while循环精简下。其中使用的 s = 'hello' iter_s = s.__iter__() while True: try: print(iter_s.__next__()) except StopIteration: break h e l l o 2.1 总结迭代器对象:执行可迭代对象的 特点:
缺点:
三、for循环原理for循环称为迭代器循环,in后必须是可迭代的对象。 lis = [1,3] for i in lis: print(i) 1 2 3 因为迭代器使用 由于对可迭代对象使用 Python2中 print(range(10)) # [0,1,6,7,8,9] Python3中 print(range(10)) # range(0,10) 今日总结今日还未悟透,这些知识点,等我悟透了再回来总结!20190812 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |