闭包函数
闭包
闭包:闭是封闭(函数内部函数),包是包含(该内部函数对外部作用域而非全局作用域的变量的引用)。闭包指的是:函数内部函数对外部作用域而非全局作用域的引用。
额。。。这里提示一下闭包!=自闭
为函数传参的两种方式
使用参数的方式
def func(x): print(x) func(1) func(1) func(1)
1
1
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}")
1 1 1 f.__closure__[0].cell_contents: 1
装饰器
什么是装饰器
器指的是工具,而程序中的函数就是具备某一功能的工具,所以装饰器指的是为被装饰器对象添加额外功能。因此定义装饰器就是定义一个函数,只不过该函数的功能是用来为其他函数添加额外的功能。
需要注意的是:
- 装饰器本身其实是可以任意可调用的对象
- 被装饰的对象也可以是任意可调用的对象
为什么要用装饰器
如果我们已经上线了一个项目,我们需要修改某一个方法,但是我们不想修改方法的使用方法,这个时候可以使用装饰器。因为软件的维护应该遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能指的是开放的。
装饰器的实现必须遵循两大原则:
- 不修改被装饰对象的源代码
- 不修改被装饰对象的调用方式
装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。
如果我们已经上线了一个项目,我们需要修改某一个方法,但是我们不想修改方法的使用方法,这个时候可以使用装饰器。因为软件的维护应该遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能指的是开放的。
装饰器的实现必须遵循两大原则:
- 不修改被装饰对象的源代码
- 不修改被装饰对象的调用方式
装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。
如果我们已经上线了一个项目,我们需要修改某一个方法,但是我们不想修改方法的使用方法,这个时候可以使用装饰器。因为软件的维护应该遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能指的是开放的。
装饰器的实现必须遵循两大原则:
- 不修改被装饰对象的源代码
- 不修改被装饰对象的调用方式
装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。
如果我们已经上线了一个项目,我们需要修改某一个方法,但是我们不想修改方法的使用方法,这个时候可以使用装饰器。因为软件的维护应该遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能指的是开放的。
装饰器的实现必须遵循两大原则:
- 不修改被装饰对象的源代码
- 不修改被装饰对象的调用方式
装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。
如果我们已经上线了一个项目,我们需要修改某一个方法,但是我们不想修改方法的使用方法,这个时候可以使用装饰器。因为软件的维护应该遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能指的是开放的。
装饰器的实现必须遵循两大原则:
- 不修改被装饰对象的源代码
- 不修改被装饰对象的调用方式
装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。
怎么用装饰器
改变源代码
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() welcome to index index run time is -1.0008180141448975
编写重复代码
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}") welcome to index index run time is -1.0046868324279785 welcome to index f2 run time is -1.000690221786499
第一种传参方式:改变调用方式
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) welcome to index <function index at 0x102977378> time is -1.000748872756958
第二种传参方式:包给函数-外包
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() welcome to index <function index at 0x102977730> time is -1.0038220882415771
完善装饰器
上述的装饰器,最后调用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}")## welcome to index <function index at 0x102977620> time is -1.0050289630889893 res: 123
如果原始的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}")## welcome egon to home page <function home at 0x102977378> time is -1.0039079189300537 res: egon
装饰器语法糖
在被装饰函数正上方,并且是单独一行写上@装饰器名
import time 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 @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}")## welcome egon to home page <function home at 0x102977620> time is -1.0005171298980713 res: egon
有参装饰器
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()
username: nick password: 123 base of file login successful welcome to index
三层闭包
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()
username: nick password: 123 base of file login successful welcome to index
由于两层的装饰器,参数必须得固定位func
,但是三层的装饰器解除了这个限制。我们不仅仅可以使用上述单个参数的三层装饰器,多个参数的只需要在三层装饰器中多加入几个参数即可。也就是说装饰器三层即可,多加一层反倒无用。
装饰器叠加
def outter1(func): # func = wrapper2 def wrapper1(*args, **kwargs): # wrapper是未来要运行的函数 print('------------') res = func(*args, **kwargs) # func是被装饰的函数 # wrapper2 print('------------') return res return wrapper1 def outter2(func): # func = index def wrapper2(*args, **kwargs): # wrapper是未来要运行的函数 print('11111111111111') res = func(*args, **kwargs) # func是被装饰的函数 # index() print('11111111111111') return res return wrapper2 # @outter1 # index = outter1(index) # @outter2 # index = outter2(index) # 先运行最下面的装饰器 # # index def index(): print('index') # index重新定义的index = outter2(index 真正的index) index = outter2(index) # index = wrapper2 # index再一次重新定义的index = outter1(index重新定义的index,即wrapper2) index = outter1(index) # index = wrapper1 index() # wrapper1()
兄弟自求多福!!!(切勿钻牛角尖)
迭代器
迭代器:迭代的工具。迭代是更新换代,如你爷爷生了你爹,你爹生了你,迭代也可以说成是重复,并且但每一次的重复都是基于上一次的结果来的。如计算机中的迭代开发,就是基于软件的上一个版本更新。以下代码就不是迭代,它只是单纯的重复
可迭代对象
python中一切皆对象,对于这一切的对象中,但凡有__iter__
方法的对象,都是可迭代对象。
# 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', 'w', encoding='utf-8') f.__iter__ f.close()
迭代器对象
只有字符串和列表都是依赖索引取值的,而其他的可迭代对象都是无法依赖索引取值的。因此我们得找到一个方法能让其他的可迭代对象不依赖索引取值。
在找到该方法前,首先我们给出迭代器对象的概念:可迭代的对象执行__iter__
方法得到的返回值。并且可迭代对象会有一个__next__
方法。
# 不依赖索引的数据类型迭代取值 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
for循环原理
for循环称为迭代器循环,in后必须是可迭代的对象
is = [1, 2, 3] for i in lis: print(i)
1
2
3
因为迭代器使用__iter__
后还是迭代器本身,因此for循环不用考虑in后的对象是可迭代对象还是迭代器对象。
由于对可迭代对象使用__iter__
方法后变成一个迭代器对象,这个迭代器对象只是占用了一小块内存空间,他只有使用__next__
后才会吐出一个一个值。如lis = [1,2,3,4,5,...]
相当于一个一个鸡蛋,而lis = [1,2,3,4,5,...].__iter__
相当于一只老母鸡,如果你需要蛋,只需要__next__
即可。