Python函数进阶、生成器、推导式、内置函数、匿名函数、递归
-
一、装饰器进阶
-
1、装饰标准写法,可以应对各种情况(带参数,带返回值)
# 普通装饰器标准写法,可以满足传参和有返回值的情况 def wrapper(f): def inner(*args, **kwargs): print("start_wrapper") res = f(*args, **kwargs) print("end_wrapper") return res return inner @wrapper # func_test = wrapper(func_test) def func_test(): print("我是func_test") func_test() # func_test = inner
-
2、装饰器带参数
# 带参数的装饰器,假如有500个函数需要反复添加装饰器,可以通过装饰器传参来实现 FLAG = True def outer(FLAG): def wrapper(func): def inner(*args, **kwargs): if FLAG == True: print("start_wrapper") res = func(*args, **kwargs) print("end_wrapper") return res else: res = func(*args, **kwargs) return res return inner return wrapper @outer(FLAG) # @outer(FLAG) = @wrapper def func1(): print("我是funcl!!!") func1()
-
3、2个装饰器装饰一个函数
# 多个装饰器装饰一个函数 def wrapper1(f): # f = inner2 def inner1(): print("我是wrapper1") f() # inner2() print("我是wrapper1") return inner1 def wrapper2(f): # f = func def inner2(): print("我是wrapper2") f() # func() print("我是wrapper2") return inner2 @wrapper1 # func = wrapper1(func)= wrapper1(inner2) = inner1 @wrapper2 # func = wrapper2(func) = inner2 def func(): print("我是func") func() # func = inner1 = inner1()
# 多个装饰器装饰一个函数,实现用户登录和性能测试 import time user_status = {"alex": False} # 登录装饰器 def login(f): # f = inner2 def inner1(name): if user_status[name] == False: user = input("请输入用户名:") pwd = input("请输入密码:") if user == "alex" and pwd == "123": print("登录成功") user_status[name] = True f(name) # inner2(name) else: print("登录成功") f(name) # inner2(name) return inner1 # 性能测试装饰器 def timmer(f): # f = func def inner2(*args, **kwargs): start_time = time.time() res = f(*args, **kwargs) # f = func end_time = time.time() print(end_time - start_time) return res return inner2 @login # func = login(func) = login(inner2) = inner1 @timmer # func = timer(func) = inner2 # 向上传完值以后销毁 def func(name): print("start_func") print("我是函数func") time.sleep(0.1) print("end_func") func("alex") # func = inner1
-
-
二、迭代器和生成器
-
1、迭代器
# 迭代器 iterator # 凡是可以使用for循环取值的都是可迭代的 # 列表,字典,元组,字符串,集合,range,文件句柄,enumerate等都是可迭代对象 # 如何查看对象是否可迭代 dir lst = [1, 2, 3] print(dir(lst)) # 含有'__iter__'方法就是可迭代的 # 怎么把可迭代对象变成迭代器 lst_iter = iter(lst) lst_iter1 = lst.__iter__() # 备注:上面lst_iter 和 lst_iter1是两个生成器 # 如何查看lst_iter是不是迭代器 print(dir(lst_iter)) # 含有__iter__方法和__next__方法的就是迭代器 # 如何迭代器中取值? # 第一种 :next 随时都可以停止 最后一次会报错 print(next(lst_iter)) # 结果 1 print(lst_iter.__next__()) # 结果 2 print(next(lst_iter)) # 结果 3 # 解决取不到值会报错StopIteration, try except异常捕捉 while True: try: print(next(lst_iter)) # lst_iter.__next__() except StopIteration: break # 第二种 :for循环 从头到尾遍历一次 不遇到break、return不会停止 for i in lst_iter: print(i) # 第三种 :list tuple 数据类型的强转 会把所有的数据都加载到内存里 非常的浪费内存 print(lst_iter) print(list(lst_iter)) # 问题 : ranger(100)是迭代器吗? # range(100) 不是迭代器,但是一个可迭代对象。使用iter可以变成迭代器 # py2 range 不管range多少 会生成一个列表 这个列表将用来存储所有的值 # py3 range 不管range多少 都不会实际的生成任何一个值 # 可迭代协议 :内部含有__iter__方法的都是可迭代的 # 迭代器协议 :内部含有__iter__方法和__next__方法的都是迭代器 # 迭代器的优势: # 节省内存 # 取一个值就能进行接下来的计算 ,而不需要等到所有的值都计算出来才开始接下来的运算 —— 快 # 迭代器的特性:惰性运算
-
2、生成器
# 生成器 Generator # 自己写的迭代器 就是一个生成器 # 两种自己写生成器(迭代器)的机制:生成器函数 生成器表达式 # 生成器函数 def generator(): for i in range(10): yield i g = generator() while True: # 通过循环取生成器里面的所有值 try: print(next(g)) except StopIteration: break # 示例,生产20000件衣服。 def generator(): for i in range(1, 20001): yield "制作第%s件衣服" % (i,) g = generator() # 取10件衣服 for i in range(1, 11): print(next(g)) # 凡是带有yield的函数就是一个生成器函数 def func(): print('****') yield 1 print('^^^^') yield 2 # 记录当前所在的位置,等待下一次next来触发函数的状态 g = func() print('--',next(g)) print('--',next(g)) # 生成器函数的调用不会触发代码的执行,而是会返回一个生成器(迭代器) # 想要生成器函数执行,需要用next def cloth_g(num): for i in range(num): yield 'cloth%s'%i g = cloth_g(1000) print(next(g)) print(next(g)) print(next(g))
# 生成器示例 文件监听 # 监听函数 import time def listen_file(filename): with open(filename) as f1: while True: # f1.seek(0, 2) # 光标移到文件尾部 res = f1.readline() # 每次只读一行,readline 会一直读如果已经到最后一行则返回空。readline不会停止所以用readline if res.strip(): f1.seek(0, 2) yield res.strip() time.sleep(0.1) # 0.5秒获取一次监听 g = listen_file("tmp") for i in g: print(i) # 循环写文件 import time count = 1 while True: with open("tmp", mode="a") as f1: f1.write("我是第%s行\n" % (count,)) count += 1 time.sleep(1)
# send关键字 def func(): print(11111) ret1 = yield 1 print(22222, 'ret1 :', ret1) ret2 = yield 2 print(33333, 'ret2 :', ret2) yield 3 g = func() print(next(g)) # 结果是 11111 print(g.send('alex')) # 在执行next的过程中 传递一个参数给yield1 print(g.send('金老板')) # 在执行next的过程中 传递一个参数给yield2 #send 获取下一个值的效果和next基本一致 #只是在获取下一个值的时候,给上一yield的位置传递一个数据 #使用send的注意事项 # 第一次使用生成器的时候 是用next获取下一个值 # 最后一个yield不能接受外部的值 # 想生成器中传递值 有一个激活的过程 第一次必须要用next触发这个生成器
def func_g(num = 0): sums = 0 day = 0 avg = 0 while True: money = yield avg # 返回avg,并接受seed传进来的money sums += money # sums = sums + money day += 1 avg = sums/day g = func_g() print(next(g)) print(g.send(50)) print(g.send(100)) print(g.send(300))
# 示例:生成器预激活,使用send必须next预激活一下,可以用装饰器来操作预激活 def wrapper(f): # f = func_g def inner(*args, **kwargs): g = f(*args, **kwargs) # f = func_g next(g) return g # 必须返回生成器 return inner @wrapper # func_g = wrapper(func_g) def func_g(num = 0): sums = 0 day = 0 avg = 0 while True: money = yield avg # 返回avg,并接受seed传进来的money sums += money # sums = sums + money day += 1 avg = sums/day g = func_g() # func_g = inner () print(g.send(50)) print(g.send(100)) print(g.send(300))
# yield from # 普通生成器函数 def func_g(): for i in range(5): yield i print("----------") for i in range(10): yield i g = func_g() # 装逼版生成器函数 def func_g(): yield from range(5) print("----------") yield from range(10) g = func_g() while True: try: print(g.__next__()) except StopIteration: break
-
3、列表推导式生成器表达式
# 开篇 #老男孩由于峰哥的强势加盟很快走上了上市之路,alex思来想去决定下几个鸡蛋来报答峰哥 agg_list = ["鸡蛋%s" % i for i in range(1, 10)] # 列表推导式 print(agg_list) #峰哥瞅着alex下的一筐鸡蛋,捂住了鼻子,说了句:哥,你还是给我只母鸡吧,我自己回家下 laomuji = ("鸡蛋%s" % i for i in range(1, 10)) # 生成器表达式 print(laomuji) print(laomuji.__next__()) # 下一个鸡蛋 print(laomuji.__next__()) # 下二个鸡蛋 print(laomuji.__next__()) # 下三个鸡蛋 ... # 总结: # 1.把列表解析的[]换成()得到的就是生成器表达式 # 2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存 # 3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。 # 例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和: res = sum(i for i in range(1, 101)) print(res) res1 = sum([i for i in range(1, 101)]) print(res1) # # 列表解析 sum([i for i in range(100000000)]) # 内存占用大,机器容易卡死 # 生成器表达式 sum(i for i in range(100000000)) # 几乎不占内存
# 面试题1 def demo(): for i in range(4): yield i g=demo() # g 是生成器 g1 = (i for i in g) # g1 是生成器 g2 = (i for i in g1) # g2 也是生成器 print(list(g1)) # 从g1生成器取值,g1又从g生成器中取值,用list会取出生成器内的所有值 print(list(g2)) # 从g2生成器取值,g2又从g1生成器中取值,g1又从g中取值。g生成器已经被取完,所以取不到值
# 面试题2 def add(n,i): # 定义一个求和函数 return n+i # 返回和 def test(): # 生成器函数,里面有4个值0,1,2,3 for i in range(4): yield i g=test() # g = 生成器 for n in [1,10]: # 列表里面有2个数字 1 和 10 g = (add(n, i) for i in g) # n = 1 # g=(add(n,i) for i in g) # n = 10 # g=(add(n,i) for i in g) print(list(g)) # g = (add(n,i) for i in (add(10,i) for i in g)) --> (add(n,i) for i in (add(10,i) for i in (0,1,2,3,4))) --> # (add(10,i) for i in (10,11,12,13) --->(20,21,22,23) --->[20,21,22,23]
-
-
三、内置函数
-
1、基础数据类型相关
- 1)和数字相关
# bool print(bool(1)) # True print(bool(0)) # False print(bool("")) # False print(bool(" ")) # True print(bool([])) # False # int a = "123" print(type(int(a))) # <class 'int'> # float a = 100 print(float(a)) # 100.0 转换成浮点类型
# 进制转换 # bin 二进制 a = 100 print(bin(a)) # 0b1100100 # oct 八进制 print(oct(a)) # 0o144 # hex 十进制 print(hex(a)) # 0x64
# abs 绝对值 a = -100 print(abs(a)) # 100 # divmod 返回(除,余) print(divmod(100, 3)) # (33, 1) # round 小数精确 a = 3.145236 print(round(a)) # 3 print(round(a, 2)) # 3.15 可以指定精确位数,四舍五入 # pow 幂运算(x,y,z) # print(pow(2,3,5)) # (2**3)%5 # print(pow(3,2,2)) # sum 求和 res = sum(i for i in range(10)) # 生成器表达式可以用在sum求值 print(res) lst = [1,2,3,4,5] print(sum(lst)) # 所有可迭代int类型对象都可以求和 print(sum([1,2,3,4,5],10)) # min 最小值 print(min(lst)) print(min(lst, key=lambda x: abs(x - 5))) print(min(1,-2,3,-4,key=abs)) def func(num): return num%2 print(min(-2,3,-4,key=func)) # max 最大值 print(max(lst))
- 2)和数据结构相关
- 序列
# 元组和列表不做详细说明 list() tuple()
# reversed 反转可迭代对象,返回一个迭代器 lst = [1, 2, 3, 4, 5] res = reversed(lst) print(dir(reversed(lst))) print(res.__next__()) print(res.__next__()) print(res.__next__()) print(res.__next__()) print(res.__next__())
# str 字符串 # bytes s = "abcd" s1 = s.encode(encoding="utf-8") # unicode转换成bytes(utf-8)的类型 print(s1) # b'abcd' s2 = s1.decode(encoding="utf-8") # 把 bytes(以utf-8存储)转换成unicode类型 print(s2) # abcd # repr print(1) print('1') print(repr(1)) print(repr('1')) # ord 和 chr 对应ascii码表 # print(ord('a')) # 小写的a-z 97+26 A-Z 65+26 # print(chr(97)) # format print(format('test', '<20')) print(format('test', '>20')) print(format('test', '^20'))
- 数据集合
dict() # 字典 set() # 集合 frozenset() # 不可变集合
- 相关内置函数
# numerate l = ['苹果', '香蕉'] ret = enumerate(l, 1) # 枚举 接收两个参数:一个容器类型,一个序号起始值 返回值:可迭代的 print(ret) for num, item in enumerate(l, 1): print(num, item) # all 和 any print(all([1,2,3,4,5])) print(all([0,1,2,3,4,5])) print(all(['a',1,2,3,4,5])) print(all(['',1,2,3,4,5])) print(any([0,None,False])) # zip ret = zip([1,2,3,4,5],('a','b','c','d'),(4,5)) #拉链方法 print(ret) for i in ret: print(i) # filter 对元素进行处理过滤,返回处理前的元素 # 过滤所有偶数 lst = [1, 4, 6, 7, 9, 12, 17] def func(num): if num % 2 == 0:return True filter(func,lst) for i in filter(func, lst): print(i) # 过滤所有None或者空元素 l = ['test', None, '', 'str', ' ', 'END'] def func(item): if item and item.strip():return True for i in filter(func,l): print(i) # map 把元素进行处理,并返回处理过的元素 def func(num): return num ** 2 for i in map(func,range(10)):print(i) # sorted 和 sort一样 排序功能 l = [1,-4,-2,3,-5,6,5] l.sort(key = abs) print(l) l = [1,-4,-2,3,-5,6,5] new_l = sorted(l,key=abs,reverse=True) print(new_l) l = [[1,2],[3,4,5,6],(7,),'123'] print(sorted(l,key=len))
- 序列
- 1)和数字相关
-
2、作用域相关
def func(): a = 1 b = 2 print(locals()) print(globals()) # 全局命名空间中的名字 print(locals()) # 本地的命名空间 print(globals()) # 全局的命名空间 func()
-
3、迭代器生成器相关
range() next() iter()
-
4、其他:
# eval 和 exec 区别是前者可以执行运算,其他均一样 eval() eval('print(123)') exec('print(123)') print(eval('1+2-3*20/(2+3)')) print(exec('1+2-3*20/(2+3)'))
# input() # print() print(123, end="") # 不换行 print(123, end="") # 进度条 import time for i in range(1,101): print("\r%s %%%s" % (i, "#"*i), end="") time.sleep(0.3)
# hash() print(hash("1231231")) #1231231236604643238473253898 # 对可hash的数据类型进行hash之后会得到一个数字 # 在一次程序的执行过程中 对相同的可哈希变量 哈希之后的结果永远相同的 # 在一次程序的执行过程中 对不相同的可哈希变量 哈希之后的结果几乎总是不相同的 # id () 查看对象的内存地址
dir()
-
-
四、匿名函数
# lambda 表达式 # 普通函数 def func(a, b): return a + b #lambda 表达式 func1 = lambda a,b: a + b print(func(1, 2)) print(func1(1, 2)) # 示例1 # 普通写法 def func(num): return num ** 2 for i in map(func,range(10)):print(i) # lambda写法 for i in map(lambda num: num ** 2, range(10)): print(i) # 示例2 # 普通写法 def func(num): return num % 2 print(min(-2,3,-4,key=func)) # lambda写法 print(min(-2, 3, -4, key=lambda num: num % 2)) # 示例3 d = lambda p: p*2 t = lambda p: p*3 x = 2 x = d(x) # x = 4 x = t(x) # x = 12 x = d(x) # x = 24 print(x) # x = 24 # 练习1 # 现有两元组(('a'), ('b')), (('c'), ('d')), 请使用python中匿名函数生成列表[{'a': 'c'}, {'b': 'd'}] def func1(t): return {t[0]:t[1]} res = map(func1,zip((('a'), ('b')), (('c'), ('d')))) print(list(res)) res = map(lambda t: {t[0]: t[1]}, zip((('a'), ('b')), (('c'), ('d')))) print(list(res)) # 练习2 # 以下代码的输出是什么?请给出答案并解释。 def multipliers(): return [lambda x:i*x for i in range(4)] # print([m(2) for m in multipliers()]) # 解析: # 第一步分解 def multipliers(): def multipliers(): lst = [] for i in range(4): lst.append(lambda x:i*x) return lst # 第二步展开 def multipliers(): def multipliers(): lst = [] i = 0 lst.append(lambda x:i*x) i = 1 lst.append(lambda x:i*x) i = 2 lst.append(lambda x:i*x) i = 3 lst.append(lambda x:i*x) return lst # 第三步 分解[m(2) for m in multipliers()] lst1 = [] for m in multipliers(): # multipliers() = lst[lambda x:i*x,lambda x:i*x,lambda x:i*x,lambda x:i*x] m(2) # m = lambda x:i*x # m(2) 执行函数传参2
-
五、递归
# 递归的定义——在一个函数里再调用这个函数本身,实际操作中递归必须要有个可停止的条件。 # 递归解析为递推和回溯两步,先递推当满足条件以后开始回溯 # 递归的最大深度—997 # RecursionError: maximum recursion depth exceeded while calling a Python object def func(): print(1) func() func() # 测试递归的最大深度 def foo(n): print(n) n += 1 foo(n) foo(1) import sys # 修改递归的最大深度,一般不修改,如果默认递归深度解决不了 说明这个问题不能用递归解决 sys.setrecursionlimit(2000) # 用递归计算6*5*4*3*2*1的乘积 print(6*5*4*3*2*1) def fn(n): if n == 1:return 1 return n*fn(n-1) print(fn(6)) # 第一次fn(6) # 返回值 6*fn(6-1)= 720 def fn(n): # n = 6 if 6 == 1:return 1 return 6*fn(6-1) # 第二次fn(6-1) # 返回值 5*fn(5-1) = 120 def fn(n): # n = 5 if 5 == 1:return 1 return 5*fn(5-1) # 第三次fn(5-1) # 返回值 4*fn(4-1) = 24 def fn(n): # n = 4 if 4 == 1:return 1 return 4*fn(4-1) # 第四次fn(4-1) # 返回值 3*fn(3-1) = 6 def fn(n): # n = 3 if 3 == 1:return 1 return 3*fn(3-1) # 第五次fn(3-1) # 返回值 2*fn(2-1) = 2 def fn(n): # n = 2 if 2 == 1:return 1 return 2*fn(2-1) # 第六次fn(2-1) 返回值 fn(2-1)= 1 def fn(n): # n = 2 if 1 == 1:return 1 return 2*fn(2-1) # 练习 打印列表的元素 li = [1, [2, [3, [4, [5]]]]] def fun(li): for i in li: if type(i) == list: fun(i) else: print(i) fun(li)