![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def func(*args): # ma, mi = args[0], args[0] # for e in args: # if ma < e: # ma = e # if mi > e: # mi = e ma = max(args) mi = min(args) return {"最大值":ma,"最小值":mi} print(func(*[2,6,5,7,9,4,99,66]))
函数的闭包,内存函数使用外层函数的变量。正常情况下函数执行完后,会销毁变量以及局部命名空间。但是使用闭包后,因为内部函数会调用外部函数的变量,所以变量不会被销毁。在某些情况下会节省大量的时间
# # # # 闭包就是内层函数对外层函数的变量(非全局)的引用 # # # # # # def func1(): # # # name = "de" # # # def func2(): # # # print(name) # 闭包 # # # # # # func2() # # # print(func2.__closure__) #(<cell at 0x0000026922089558: str object at 0x0000026921F7A4C8>,) # # # # # # func1() # # # # # 在函数外调用内部函数 # # # 利用返回值 # # def outer(): # # name = "ly" # # def inner(): # # print(name) # # return inner # # # # fn = outer() # # fn() # # # # 如果是多层嵌套,只需要一层一层的往外返回就好了 # # # 由它我们可以引出闭包的好处. 由于我们在外界可以访问内部函数. 那这个时候内部函 # 数访问的时间和时机就不⼀定了, 因为在外部, 我可以选择在任意的时间去访问内部函数. 这 # 个时候. 想⼀想. 我们之前说过, 如果⼀个函数执⾏完毕. 则这个函数中的变量以及局部命名 # 空间中的内容都将会被销毁. 在闭包中. 如果变量被销毁了. 那内部函数将不能正常执⾏. 所 # 以. python规定. 如果你在内部函数中访问了外层函数中的变量. 那么这个变量将不会消亡. # 将会常驻在内存中. 也就是说. 使⽤闭包, 可以保证外层函数中的变量在内存中常驻. 这样做 # 有什么好处呢? 非常⼤的好处. 我们来看⼀个关于爬⾍的代码: # from urllib.request import urlopen # def but(): # content = urlopen("http://www.xiaohua100.cn/index.html").read() # def get_content(): # return content # return get_content # fn = but() # 这个时候就开始加载校花100的内容 # # 后⾯需要⽤到这⾥⾯的内容就不需要在执⾏⾮常耗时的⽹络连接操作了 # content = fn() # 获取内容 # print(content) # content2 = fn() # 重新获取内容 # print(content2) # #综上, 闭包的作⽤就是让⼀个变量能够常驻内存. 供后⾯的程序使⽤.
迭代器
# # # # #常见的可迭代对象 list set tuple str dict # # # # # int 是不可迭代的 # # # # # 验证数据类型是否可迭代,用dir函数查看类中定义好的所有方法 # # # # s = "Ly" # # # # i = 123 # # # # print(dir(s)) #含有iter表示该数据类型是可迭代的对象 # # # # print(dir(i)) # # # # # # # # # # 也可以通过isinstence()函数来查看一个对象是什么类型 # # # l = [1, 2, 3] # # # l_iter = l.__iter__() # # # from collections import Iterable # # # from collections import Iterator # # # print(isinstance(l, Iterable)) # # # print(isinstance(l, Iterator)) # # # print(isinstance(l_iter, Iterable)) # # # print(isinstance(l_iter, Iterator)) # # # True # # # False # # # True # # # True # # # # # # # 综上. 我们可以确定. 如果对象中有__iter__函数. 那么我们认为这个对象遵守了可迭代协议. # # # 就可以获取到相应的迭代器. 这⾥的__iter__是帮助我们获取到对象的迭代器. 我们使⽤迭代 # # # 器中的__next__()来获取到⼀个迭代器中的元素. 那么我们之前讲的for的⼯作原理到底是什 # # # 么? 继续看代码 # # # # s = "我爱北京天安⻔" # # c = s.__iter__() # 获取迭代器 # # print(c.__next__()) # 使⽤迭代器进⾏迭代. 获取⼀个元素 我 # # print(c.__next__()) # 爱 # # print(c.__next__()) # 北 # # print(c.__next__()) # 京 # # print(c.__next__()) # 天 # # print(c.__next__()) # 安 # # print(c.__next__()) # ⻔ # # print(c.__next__()) # StopIteration # # # # # for 循环机制 # # for i in [1, 2, 3]: # # print(i) # # # # lst = [1, 2, 3] # # lst_iter = lst.__iter__() # # while True: # # try: # # print(lst_iter.__next__()) # # except StopIteration: # # break # # # # 总结: # Iterable: 可迭代对象. 内部包含__iter__()函数 # Iterator: 迭代器. 内部包含__iter__() 同时包含__next__(). # 迭代器的特点: # 1. 节省内存. # 2. 惰性机制 # 3. 不能反复, 只能向下执⾏. # 我们可以把要迭代的内容当成⼦弹. 然后呢. 获取到迭代器__iter__(), 就把⼦弹都装在弹夹 # 中. 然后发射就是__next__()把每⼀个⼦弹(元素)打出来. 也就是说, for循环的时候. ⼀开始的 # 时候是__iter__()来获取迭代器. 后⾯每次获取元素都是通过__next__()来完成的. 当程序遇到 # StopIteration将结束循环.
函数名的应用
# # # def func(): # # # print("你吃了嘛") # # # # # # # print(func) # 打印的是函数的内存地址 # # # # a = func # # # # print(a) # # # # func() # # # # a() # # # # # # def a(): # # # print("我吃了") # # # # # # func = a # # # func() # # # # # # # # # a = 8 # # # b = 7 # # # c = 1 # # # d = 3 # # # lst = [a, b, c, d] # # # print(lst) # # # # # # def f1(): # # print("f1") # # # # def f2(): # # print("f2") # # # # def f3(): # # print("f3") # # # # def f4(): # # print("f4") # # # # lst = [f1, f2, f3, f4] # # print(lst) # # # # lst = [f1(), f2(), f3(), f4()] # # print(lst) # # # def func(fn): # fn() # # def gn(): # print("刚才有人想吃我") # func(gn) def func(): def inner(): print("我是火锅") return inner ret = func() ret() # 函数可以作为变量名,返回值,可以赋值等等
一 . 生成器
生成器就是迭代器
生成器的特点和迭代器一样.
1.省内存
2.惰性机制
3.只能向前
在python中有三种方式获取生成器
1.通过生成器函数
2.通过各种推导式来实现生成器
3.通过数据的转换也可以获取生成器
生成器
# g = (i for i in range(10)) # print(g) # print(list(g)) # # print(g.__next__()) # # print("a") # # for i in g: # # print(i) # 生成器表达式和列表表达式 # 列表推导式比较耗费内存,生成器几乎不占用内存 # 得到的值是不一样的,生成器得到的是一个生成器,列表得到的是一个列表 # 生成器的惰性机制 def func(): print(111) yield 222 g = func() # 生成生成器g g1 = (i for i in g) # 生成器g1 g2 = (i for i in g1) # 生成器g2 print(list(g)) # 获取g1中的数据. g1的数据来源是g. 但是g已经取完了. g1也就没有数据了
print(list(g1)) #这里的g1 来自与g,但yield已经没有了 print(list(g2)) # 111 # [222] # [] # []
print(list(g2)) # 同理g1
# 一定要知道什么时候才取值,什么时候不能取值
send()的相关应用
# def func(): # print("大闸蟹") # a = yield "11" # print(a) # print("狗不理") # b = yield "22" # print(b) # print("大麻花") # c = yield "3 3" # print(c) # g = func() # print(g.__next__()) # print(g.send(1)) # print(g.send(2)) # # print(g.send(3)) # # send() 和__next__() 都可以让生成器向下执行一次 # # send()还会给上一个yield传值,所以第一个使用__next__(),最后一个也不使用send会报错 def func(): yield 11 yield 22 yield 33 yield 44 g = func() lst = list(g) print(lst)
推导式
# 生成列表里面1-14的数据 # lst = [] # for i in range(1,15): # lst.append("python%s" % i) # print(lst) # 列表推导式 # 语法 [最终结果(变量) for 变量 in 可迭代对象 条件] # lst = ["python%s" % i for i in range(1,15)] # print(lst) # lst = [i for i in range(1,101) if i % 3 == 0] # print(lst) # lst = [i**2 for i in range(101) if i % 3 == 0] # print(lst) # names = [["Tom", "shcoo","qqkj", "ccwww", "zzeee", "wwee"], ["for", "eeaa", "aaexce", "saaa"]] # lst = [name for first in names for name in first if name.count("e") == 2] # print(lst) # 列表生成式的缺点比较占内存 # 推导式 [结果 for 变量 in 可迭代对象 if 条件] g = [i for i in range(10)] print(g) # 生成器表达式和列表推导式的语法基本上是一样的,只是把[]替换成() gen = (i for i in range(10)) # 生成器 print(gen)
字典推导式
# dic = {"a":"b","c":"d"} # # 把字典的k,v互换 # new_dic = {dic[k]:k for k in dic} # print(new_dic) # lst1 = ["al","wu","ly","ri"] # lst2 = ["1", "2", "3", "4"] # # 要求一一对应 # # dic = {lst1[i]:lst2[i] for i in range(len(lst1))} # print(dic) # # 集合推导式可以直接生成一个集合,无序,不重复,集合自带去重功能 # lst = ["a", "b", "a", "d"] # st = {i for i in lst} # print(st) # 推导式有列表,字典集合,没有元组,因为元组不可变,且()是生成器 # 生成器推导式(结果 for x in 可迭代对象 if条件 )
生成器函数
# def funs(): # print("我爱周杰伦") # yield "昆凌" # 函数中包含yield,那么当前这个函数就是生成器函数 # print("王力宏") # yield "李云迪" # # # print(funs()) #<generator object funs at 0x000002679184D468> # g = funs() # print(g.__next__()) # # print(g.__next__()) # # yield 和return 的区别,return 是直接返回函结果,函数停止。yield则会使函数分段执行 # #print(g.__next__()) # 会报错,同时最后一个yield后面最好不要再写程序,因为找不到下一个yield会报错 def func(): yield 11 yield 22 yield 33 yield 44 g = func() # 拿到的相当于生成器,生成器本质上相当于迭代器,可以被迭代 for i in g: print(i) # 本质上相当于__next__() it = g.__iter__() while True: try: print(it.__next__()) except StopIteration: break # 这里上面的for已经将yield执行玩,这里直接执行break
练习
def add(a, b): return a+b def test456(): for r_i in range(4): yield r_i g = test456() for n in [2,10]: g = (add(n,i) for i in g) print(list(g)) # [20, 21, 22, 23] 因为在n = 2时没有取值,生成器因为惰性机制也不会去计算,在n = 10时,list(g)取值,此时根据n=10去取值