一、闭包:
1,闭包存在于函数中。
2,闭包就是内层函数对外层函数(非全局变量)的引用。
3,最内层函数名会被逐层的返回直至返回给最外层。
def func(): name = 'alex' def inner(): print(name) return inner ret = func() # inner # ret() print(ret.__closure__) # 只要返回cell 它就是闭包 print(ret.__closure__[0])# 只要返回cell 它就是闭包 print(ret.__closure__[0].cell_contents) # 只要返回cell 它就是闭包 name = 'barry' def func(): def inner(): print(name) return inner ret = func() # inner # ret() print(ret.__closure__) # 只要返回None它就不是闭包 #不是闭包 name = 1 def func(): print(name) func() #是闭包 n1虽然是外部全局变量,但当时传参数时 name = n1 ,那就是相当于外层函数有个name的变量 def func(name): def inner(): print(name) return inner n1 = 'barry' ret = func(n1) # inner print(ret.__closure__)
# 闭包的作用是什么? def func(step): num = 1 num += step print(num) for i in range(5): func(2) # 闭包的作用:解释器遇到闭包,会触发一个机制,这个闭包不会随着它的结束而释放。 def func(step): num = 1 def inner(): nonlocal num num += step print(num) return inner f = func(2) for i in range(5): f() f() f()
闭包的应用(网页爬取)
from urllib.request import urlopen def func(): content = urlopen("http://www.cnblogs.com/jin-xin/articles/8259929.html").read() return content #print(func()) print(func().decode('utf-8')) from urllib.request import urlopen def but(a): content = urlopen(a).read() def get_content(): return content return get_content fn = but('http://www.cnblogs.com/jin-xin/articles/8259929.html') #fn = but('http://www.cnblogs.com/jin-xin/articles/8254334.html') con = fn() # 获取内容 print(con.decode('utf-8')) print(con.decode('utf-8')) print(con.decode('utf-8')) print(con.decode('utf-8')) #中文显示 content2 = fn() # 重新获取内容 print(content2.decode('utf-8'))
二、装饰器
其实装饰器本质是闭包,在不改变原函数的调用指令情况下,给原函数增加额外的功能。它的传参,返回值都是借助内层函数inner,
它之所以借助内层函数inner 就是为了让被装饰函数 在装饰器装饰前后,没有任何区别,看起来没有变化。
进化序列:
# 第一版:写一个功能测试其他同事的函数的执行效率 import time def func(): time.sleep(0.2) print('非常复杂') def func1(): time.sleep(0.3) print('超级复杂') start_time = time.time() func() end_time = time.time() print('此函数的执行效率为%s' % (end_time - start_time)) # 第二版: import time def func(): time.sleep(0.2) print('非常复杂') def func1(): time.sleep(0.3) print('超级复杂') def timmer(f): start_time = time.time() f() end_time = time.time() print('此函数的执行效率为%s' % (end_time - start_time)) timmer(func) timmer(func1) # func() # 如果在实际项目中测试函数, # 假如函数有1500个,那么你1500个timmer(func),工作量很大。 # 你要在不改变函数执行的指令下,同时测试效率。 # 第三版:在不改变函数的执行方式下,同时测试执行效率。 # 装饰器的雏形 import time def func(): time.sleep(0.2) print('非常复杂') def func1(): time.sleep(0.3) print('超级复杂') def timmer(f): def inner(): start_time = time.time() f() end_time = time.time() print('此函数的执行效率为%s' % (end_time - start_time)) return inner func = timmer(func) # 语法糖 @ func() func1 = timmer(func1) func1() # 装饰器的雏形的优化 # timmer 就是装饰器: 在不改变原函数的调用指令情况下,给原函数增加额外的功能。 import time def timmer(f): def inner(): start_time = time.time() f() end_time = time.time() print('此函数的执行效率为%s' % (end_time - start_time)) return inner @timmer # func = timmer(func) def func(): time.sleep(0.2) print('非常复杂') @timmer # func1 = timmer(func1) def func1(): time.sleep(0.3) print('超级复杂') func() func1() # 被装饰函数带参数 import time def timmer(f): def inner(*args,**kwargs): # 函数的定义: * 聚合。args = (1,2,3,434545,4234.) # a1 = 'wusir' # b1 = 'alex' start_time = time.time() f(*args,**kwargs) # 函数执行:* 打散。f(*(1,2,3,434545,4234.),) end_time = time.time() print('此函数的执行效率为%s' % (end_time - start_time)) return inner @timmer # func = timmer(func) def func(a,b): time.sleep(0.2) print('非常复杂%s%s'% (a,b)) func('wusir','alex') # inner() @timmer # func = timmer(func) def func(a,b,c): time.sleep(0.2) print('非常复杂%s%s%s'% (a,b,c)) func('wusir','alex','barry') # inner() # 被装饰的函数要有返回值 import time def timmer(f): # f = func def inner(*args,**kwargs): start_time = time.time() ret = f(*args,**kwargs) # func() end_time = time.time() print('此函数的执行效率为%s' % (end_time - start_time)) return ret return inner @timmer # func = timmer(func) def func(a,b): time.sleep(0.2) print('非常复杂%s%s'% (a,b)) return 666 ret = func('wusir','alex') # inner() print(ret) @timmer # func = timmer(func) def func(a,b,c): time.sleep(0.2) print('非常复杂%s%s%s'% (a,b,c)) func('wusir','alex','barry') # inner() # 装饰器的应用 flag = False def login(): username = input('用户名') password = input('密码') if username == 'alex' and password == '123': print('登陆成功') global flag flag = True def auth(f): # f = func3函数名 def inner(*args,**kwargs): while 1: if flag: ret = f(*args,**kwargs) return ret else: login() return inner @auth def comment(): print('欢迎来到评论页面') @auth def artcle(): print('欢迎来到文章页面') @auth def dairy(): print('欢迎来到日记页面') comment() artcle() dairy() dic = { 1: artcle, 2:dairy, 3:comment, }
三、迭代器
可迭代对象:这个对象由多个元素组成,它就是可迭代的。
这个对象内部只要含有"__iter__"方法,它就是可迭代的。
遵循可迭代协议。可迭代对象不一定是迭代器,但迭代器一定是可迭代对象。
# int str bool list tuple dict set bytes range 文件句柄
不可以迭代对象:int bool
可以迭代对象:str list tuple dict set bytes range 文件句柄
判断一个对象是否是可迭代的 --> 是否含有"__iter__"方法 s1 = 'alex' print(dir(s1)) i = 100 print(dir(i)) print('__iter__' in dir(range))
方法一:内部含有__iter__方法并且含有__next__方法的就是迭代器。 l1 = [1,2,3] print('__iter__' in dir(l1)) #True print('__next__' in dir(l1)) #False 方法二:判断一个对象是否是迭代器,可迭代对象的另一种方式: from collections.abc import Iterator from collections.abc import Iterable #from collections import Iterator #DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working #from collections import Iterable #DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working #列表 l1 = [1,2,3,4] print(isinstance(l1,Iterator)) #False print(isinstance(l1,Iterable)) #True # 文件句柄? with open('test.py',encoding='utf-8') as f1: print(isinstance(f1,Iterator)) #True #可迭代对象不能直接取值,必须转化成迭代器进行取值。 eg: l1 = [1,2,3] # 将一个可迭代对象 转化成迭代器 for i in l1: print(i) l1 = [1, 2, 3] # 将一个可迭代对象 转化成迭代器 obj1 = iter(l1) print(obj1) #<list_iterator object at 0x000001E7EB8A2CF8> print(next(obj1)) # 一个next对应一个值 print(next(obj1)) print(next(obj1))
# while 模拟for循环循环可迭代对象的机制。 # 1,将可迭代对象转化成迭代器。 # 2,利用next进行取值。 # 3,利用异常处理停止循环。 l1 = [1, 2, 2, 3, 4, 4, 5, 5] # obj = l1.__iter__() obj = iter(l1) while 1: try: print(next(obj)) except StopIteration: break
迭代器有什么作用?
1,节省内存。
2,一条路走到底,不反复。
3,不易看出。
四、生成器
生成器:本质就是迭代器,自己可以通过代码写出来的迭代器。
生成器的生成方式:1.函数式生成器。2.生成器表达式。
1、函数中只要有yield 它就不是函数了,它是生成器函数
yield 与 return的区别:
return直接终止函数,yield不会终止函数。
return给函数的执行者返回值,yield是给next(生成器对象)返回值。
def func(): yield 5 yield 6 yield 7 yield 8 g = func() # 生成器对象 print(g) # 一个next对应一个 yield print(next(g)) print(next(g)) print(next(g)) print(next(g)) def book(): for i in range(1,501): print('python全栈开发 编号%s' %i) def book_niu(): for i in range(1,501): yield 'python全栈开发 编号%s' %i book() gen = book_niu() for i in range(50): print(next(gen)) for i in range(30): print(next(gen))
send方法
send 与 next的区别 send不仅可以取值,还可以给上一个yield发送一个值
第一个send不可以传值只能传None,因为上面无yield可传,最后一个yield 永远不会收到send发送的值
def func(): a = 1 b = 2 c = 3 count = yield a + b + c print(count) yield 6 yield 7 yield 8 g = func() print(next(g)) print(g.send('barry')) send不仅可以取值,还可以给上一个yield(例如:yield a + b + c)发送一个值 print(g.send(None)) print(g.send(None))
yield from方法
def func(): l1 = ['barry', 'alex', 'wusir', '日天'] # yield l1 yield from l1 # 将一个可迭代对象转化成了生成器返回 g = func() print(next(g)) print(next(g)) print(next(g)) print(next(g)) # print(next(g)) for i in g: print(i)
2、生成器表达式与列表推导式 生成器表达式与列表推导式非常类似,容易着魔
列表推导式:构建一个列表
# [100以内所有的偶数],[0,2,4,6,8....100]
l1 = [] for i in range(0,101,2): l1.append(i) print(l1)
# 列表推导式分为两种模式: # 用一行代码构建一个列表,列表推导式只能构建简单的或者比较复杂的列表。 # 1,循环模式。 [变量(加工后的变量) for 变量 in iterable] print([i for i in range(0,101,2)]) [1,4,9,16,25,36,49] print([i*i for i in range(1,8)]) # ['python1期', 'python2期', .....'python20期'] print(['python%s期'%i for i in range(1,21)]) # 2,筛选模式 # [变量(加工后的变量) for 变量 in iterable if 条件] print([i for i in range(1,31) if i % 3 == 0]) # 30以内能被2整除的数的平方 print([ i*i for i in range(1,31) if i % 2 == 0]) # [1,2,3,4,6,7,8] print([i for i in range(1,9)if i != 5]) l1 = ['wusir','ba', 'aa' ,'alex'] # 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母 print([i.upper() for i in l1 if len(i) > 3]) ['WUSIR','ALEX'] names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] # 将列表中的至少含有两个'e'的人名留下来。 # l1 = [] # for l in names: # for name in l: # if name.count('e') >= 2: # l1.append(name) # print(l1) print([name for l in names for name in l if name.count('e') >= 2])
生成器表达式:生成器表达式和列表推导式的语法上一模一样,只是把[]换成()就行了。比如将十以内所有数的平方放到一个生成器表达式中
生成器表达式和列表推导式的区别:
列表推导式比较耗内存,所有数据一次性加载到内存。而.生成器表达式遵循迭代器协议,逐个产生元素。
得到的值不一样,列表推导式得到的是一个列表.生成器表达式获取的是一个生成器
列表推导式一目了然,生成器表达式只是一个内存地址。 无论是生成器表达式,还是列表推导式,他只是Python给你提供了一个相对简单的构造方式,因为使用推导式非常简单,所以大多数都会为之着迷,这个一定要深重,推导式只能构建相对复杂的并且有规律的对象,对于没有什么规律,而且嵌套层数比较多(for循环超过三层)这样就不建议大家用推导式构建。
生成器的惰性机制: 生成器只有在访问的时候才取值,说白了.你找他要才给你值.不找他要.他是不会执行的.
# print((i for i in range(1,31) if i % 3 == 0)) gen = (i for i in range(1,31) if i % 3 == 0) for i in gen: print(i)
# 匿名函数: 一句话函数 # def func(a,b): # return a + b # print(func(1,3)) # func1 = lambda x,y: x + y # # print(func1(1,3)) # print(func1) # 将 x, y 较大者返回 # func2 = lambda x,y: x if x > y else y # print(func2(100,200)) # eval 慎用 # print('1 + 2') # print(eval('1 + 2')) # n=81 # print(eval("n + 4")) # 85 # # exec # s1 = ''' # for i in range(4): # print(i) # ''' # exec(s1) # # print(1,2,3,sep='|') # 分隔符 # print(1,2,3,end=' ') # 换行符 # f = open('log','w',encoding='utf-8') # print('写入文件',file=f,flush=True) # print(help(str)) # def func(): # pass # ret = 888 # # print(callable(func)) # print(callable(ret)) # print(float(100),type(float(100))) # print(bin(100)) # print(abs(-100)) # # ret = divmod(10,3) # print(ret) # (商,余数) # sum *** # print(sum([i for i in range(101)])) # print(sum([i for i in range(101)],100)) # min 可以加key=函数 *** # max *** # l1 = [3,4,1,2,7,-5] # print(min(l1)) l1 = [('a',3),('b',2),('c',1)] # def func(x): # ''' # x = (c,1) 1 # ''' # return x[1] # 改成lambda # func = lambda x : x[1] # # # print(lambda x : x[1]) # # # print(func) # # print(min(l1,key=lambda x : x[1])) # # l1 = [i for i in range(10)] # # print(l1) # # print(reversed(l1)) *** # for i in reversed(l1): # print(i) s = 'alex' # b = s.encode('utf-8') # s1 = b.decode('utf-8') # b = s.encode('utf-8') # print(b) # bs = bytes(s,encoding='utf-8') # print(bs) # print(chr(97)) # print(chr(65)) # repr # s1 = 'alex' # # print(s1) # # print(repr(s1)) # s2 = '我叫%s'%('barry') # s2 = '我叫%r'%('barry') # print(s2) # sorted *** # l1 = [1,2,8,7,5] # print(min(l1)) # l1 = [('c',2),('b',3),('a',1)] # # print(sorted(l1)) # print(sorted(l1,key=lambda x:x[1])) # print(all([1,2,[1,2,3],'alex',True])) # print(any([1,'',[],(),False])) # zip 拉链方法 *** # l1 = [1,2,3,4] # tu1 = ('a','b','c') # tu2 = ('a1','b1','c1') # g = zip(l1,tu1,tu2) # # print(list(g)) # for i in g: # print(i) l1 = [1,2,3,4,5,6,7] # print([i for i in l1 if i > 3]) # ret = filter(lambda x:x>3,l1) # # # print(ret) # # # print(list(ret)) # [1,4,9,16,25] # map # print([i**2 for i in range(1,6)]) # ret = map(lambda x:x*x,range(1,6)) # print(list(ret)) from functools import reduce # def func(x,y): # return x + y # 3 ret = reduce(lambda x,y: x + y,[1,2,3,4,5]) print(ret)
# -*- coding: utf-8 -*- # @Time : 2019/1/27 9:42 # @Author : 景丽洋 # @Email : xxx@admin.com # @File : 3.内容回顾.py # @Software: PyCharm # 函数进阶 # 装饰器 # 在不改变函数原本调用方式的基础上添加一些功能 # @装饰器名 # 如何写一个装饰器 # 计算函数执行时间 # 用户认证 # 给函数添加日志 # def wrapper(func): # def inner(*args,**kwargs): # '''在被装饰的函数之前添加功能''' # ret = func(*args,**kwargs) # '''在被装饰的函数之后添加功能''' # return ret # return inner # # @wrapper # func = wrapper(func) # def func(): # pass # def wrapper2(func): # def inner(*args,**kwargs): # print('wrapper2 before') # ret = func(*args,**kwargs) # print('wrapper2 after') # return ret # return inner # # def wrapper1(func): # def inner(*args,**kwargs): # print('wrapper1 before') # ret = func(*args,**kwargs) # print('wrapper1 after') # return ret # return inner # # @wrapper2 # @wrapper1 # func = wrapper(func) # def func(): # print('in func') # func() # 登陆 -- 装饰器 auth # 计算函数的执行时间 -- 装饰器 timmer # @auth # @timmer # def func(): # pass # flag = False # def outer(flag): # def timmer(func): # def inner(*args,**kwargs): # if flag: # print('wrapper1 before') # ret = func(*args,**kwargs) # print('wrapper1 after') # else: # ret = func(*args, **kwargs) # return ret # return inner # return timmer # # @outer(flag) #outer(flag) = timmer @outer(flag) = @timmer # def func(): # print('in func') # # func() # 迭代器和生成器 # 可迭代对象 # 可迭代对象可以通过for/iter方法将一个可迭代对象转换成一个迭代器 ,list str range # 迭代器 # 使用迭代器 : 节省内存,迭代器一项一项的取,节省内存 文件句柄 # 生成器 # 我们自己写的迭代器 # 生成器的本质就是迭代器,所有的生成器都是迭代器 # 实现生成器的方法 : # 生成器函数 :一定带yield关键字 # g = func() # 生成器表达式 : 用小括号表示的推导式 # 生成器的特点: # 1.可以用next/send方法从中取值 # 2.生成器中的数据只能从头到尾取一次 # 3.惰性运算 :不取生成器是不工作的 # def demo(): # for i in range(4): # yield i # g=demo() # # g2=(i for i in g) # g1=(i for i in g) # # print(list(g1)) # 0,1,2,3 # 这一步才开始从g1中取值 # print(list(g2)) # # 列表推导式(排序) # [i**2 for i in lst] # [i**2 for i in lst if i%2 ==0 ] # 生成器表达式 # (i**2 for i in lst) # 匿名函数 # lambda 参数1,参数2,参数3 : 返回值/返回值相关的表达式 # 内置函数 # min max map filter sorted 单记 # reduce --> functool # zip sum enumerate