Python3
1.上节内容回顾
递归:
- 明确的结束条件
- 问题规模每递归一次都应该比上一次的问题规模有所减少
- 效率低
高阶函数
文件:
rb、wb、ab
一般用在不同系统之间传数据,和传视频流的时候用到,一般以这种形式打开的需要制定encoding=‘utf-8’的字符编码形式
其他:
- f.seek()
- f.tell()
- f.truncate()
- f.flush()
2.装饰器
定义:装饰器本质是函数,(装饰其他函数)就是为其他函数添加附加功能
原则:
- 不能修改被装饰的函数的源代码
- 不能修改被装饰的函数的调用方式
言外之意就是说被装饰的函数在装饰器前都是完全透明的
实现装饰器知识储备:
- 函数即“变量”
- 高阶函数
-
-
- 把一个函数名当做实参传给另外一个函数(不修改被装饰函数源代码的情况下为期添加功能)
- 返回值中包含函数名(不修改函数的调用方式)
-
3.嵌套函数
一、函数的调用顺序:函数就像变量一样,在定义的时候就是把函数体赋值给函数名这样子,Python在调用函数之前,该函数一定要先被声明
1 def foo(): 2 print(foo) 3 bar() 4 foo() 5 def bar(): 6 print(bar) 7 #报错,bar函数还未声明
改正:
1 def foo(): 2 print('foo') 3 bar() 4 def bar(): 5 print('bar') 6 foo()
二、 高阶函数
1 def bar(): 2 print 'in the bar' 3 def foo(func): 4 res=func() 5 return res 6 foo(bar)
三、嵌套函数
1 def foo(): 2 def bar(): 3 print 'in the bar' 4 5 bar() 6 7 foo()
四、装饰器
装饰器的语法以@开头,接着就是装饰器要装饰的函数的声明
装饰器就是一个函数,一个用来包装函数的函数,装饰器在函数声明完成的时候被调用,调用之后声明的函数被换成一个被装饰器装饰过后的函数。
当函数有形参时,在装饰的函数中也需要有相应的形参;
当原函数有return返回值时,在装饰的函数中也要萹蓄有return func(args);
函数参数固定:
1 def decorator(func): 2 def wrapper(n): 3 print('atarting') 4 func(n) 5 print('stopping') 6 return wrapper 7 def test(n): 8 print('in the test arg is %s'%n) 9 decorator(test)('alex')
函数参数不固定
1 def decorator(func): 2 def wrapper(*args,**kwargs): 3 print('starting') 4 func(*args,**kwargs) 5 print('stopping') 6 return wrapper 7 def test(n,x=1): 8 print('in the test arg is %s,he is %d'%(n,x)) 9 decorator(test)('alex',x=2)
1.无参装饰器
1 import time 2 def decorator(func): 3 def wrapper(*args,**kwargs): 4 start =time.time() 5 func(*args,**kwargs) 6 stop = time.time() 7 print('run time is %s'%(stop-start)) 8 return wrapper 9 @decorator #test=decorator(test) 10 def test(list_test): 11 for i in list_test: 12 time.sleep(0.1) 13 print('_'*20,i) 14 test(range(10))
2.有参装饰器
1 import time 2 def timer(timeout =0): 3 def decorator(func): 4 def wrapper(*args,**kwargs): 5 start = time.time() 6 func(*args,**kwargs) 7 stop = time.time() 8 print("run time is %s"%(stop-start)) 9 print(timeout) 10 return wrapper 11 return decorator 12 @timer(2) #test=timer(2)(test) 13 def test(list_test): 14 for i in list_test: 15 time.sleep(0.1) 16 print('-'*20,i) 17 test(range(10))
高阶函数+嵌套函数=》装饰器
举一个复杂的例子:
1 import time 2 user,passwd = 'alex','abc123' 3 def auth(auth_type): 4 print("auth func:",auth_type) 5 def outer_wrapper(func): 6 def wrapper(*args, **kwargs): 7 print("wrapper func args:", *args, **kwargs) 8 if auth_type == "local": 9 username = input("Username:").strip() 10 password = input("Password:").strip() 11 if user == username and passwd == password: 12 print("\033[32;1mUser has passed authentication\033[0m") 13 res = func(*args, **kwargs) # from home 14 print("---after authenticaion ") 15 return res 16 else: 17 exit("\033[31;1mInvalid username or password\033[0m") 18 elif auth_type == "ldap": 19 print("搞毛线ldap,不会。。。。") 20 21 return wrapper 22 return outer_wrapper 23 24 def index(): 25 print("welcome to index page") 26 @auth(auth_type="local") # home = wrapper() 27 def home(): 28 print("welcome to home page") 29 return "from home" 30 31 @auth(auth_type="ldap") 32 def bbs(): 33 print("welcome to bbs page") 34 35 index() 36 print(home()) #wrapper() 37 bbs()
3.列表生成式,迭代器&生成器
生成器只有在调用时才会生成相应的数据
只记录当前的位置
只有一个__next__()方法,next()
列表生成式:
需求:将列表[0,1,2,3,4,5,6,7,8,9]将列表里的每个值加1、
三种写法:
1 a =[0,1,2,3,4,5,6,7,8,9] 2 b =[] 3 for i in a: 4 b.append(i+1) 5 a =b 6 print(a)
1 a = [1,2,3,4,5,6,7,8,9] 2 a =map(lambda x:x+1,a) #map(f(x),列表名) 3 for i in a: 4 print(i)
1 a= [i+1 for i in range(10)] 2 for i in a: 3 print(i)
第三种即就是列表生成式
生成器:
通过列表生成式,我们可以直接创建一个列表,但是要创建100万个元素的列表,那么存储空间很庞大,因此,我们只需要生成式,它就是不必创建完整的list,从而节省大量空间,这种一遍循环一边计算的机制,称为生成器:generator
创建generetor有以下几种方法:
第一种:把列表生成式的[]改为(),就创建了一个generator
1 >>> L = [x * x for x in range(10)] 2 >>> L 3 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 4 >>> g = (x * x for x in range(10)) 5 >>> g 6 <generator object <genexpr> at 0x1022ef630>
此时g已经是一个生成器
如何一个个打印出来,用next()函数即可
1 >>> next(g) 2 0 3 >>> next(g) 4 1 5 >>> next(g) 6 4 7 >>> next(g) 8 9 9 >>> next(g) 10 16 11 >>> next(g) 12 25 13 >>> next(g) 14 36 15 >>> next(g) 16 49 17 >>> next(g) 18 64 19 >>> next(g) 20 81 21 >>> next(g) 22 Traceback (most recent call last): 23 File "<stdin>", line 1, in <module> 24 StopIteration
generator保存的是算法,每次调用next(),就计算出g的下一个元素的值,直到计算出最后一个元素,没有更多的元素时,跑出StopIteration错误
不断调用next()方法太麻烦,因此用for循环,此种方法也不需要考虑StopIteration错误
1 >>> g = (x * x for x in range(10)) 2 >>> for n in g: 3 ... print(n) 4 ... 5 0 6 1 7 4 8 9 9 16 10 25 11 36 12 49 13 64 14 81
打印斐波拉契数列:
斐波拉契数列(Fibonacci):1, 1, 2, 3, 5, 8, 13, 21, 34, ...
1 def fib(max): 2 n,a,b=0,0,1 3 while n<max: 4 print(b) 5 a,b=b,a+b 6 n =n+1 7 return 'done'
fib函数实际上定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑很类似generator。
要把fib()变成generator,只需要把print(b)改为yield(b)即可
1 def fib(max): 2 n,a,b=0,0,1 3 while n<max: 4 #print(b) 5 yield b 6 a,b=b,a+b 7 n =n+1 8 return ‘done'
>>> f = fib(6) >>> f <generator object fib at 0x104feaaa0>
generator,在每次调用next()执行,遇到yield就返回,再次执行则从上次返回的yield语句处继续执行
data = fib(10) print(data) print(data.__next__()) print(data.__next__()) print("干点别的事") print(data.__next__()) print(data.__next__()) print(data.__next__()) print(data.__next__()) print(data.__next__()) #输出 <generator object fib at 0x101be02b0> 1 1 干点别的事 2 3 5 8 13
在循环过程中不断调用yield,就会不断中断,当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。
把函数变成generator之后,基本不会用next()来获取下一个返回值,而是直接使用for循环来迭代:
1 >>> for n in fib(6): 2 ... print(n) 3 ... 4 1 5 1 6 2 7 3 8 5 9 8
在用for循环调用generator时,发现拿不到generator的return语句的返回值,如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:
1 >>> g = fib(6) 2 >>> while True: 3 ... try: 4 ... x = next(g) 5 ... print('g:', x) 6 ... except StopIteration as e: 7 ... print('Generator return value:', e.value) 8 ... break 9 ... 10 g: 1 11 g: 1 12 g: 2 13 g: 3 14 g: 5 15 g: 8 16 Generator return value: done
还可以使用yield实现单线程的情况下并发运算的效果
1 #_*_coding:utf-8_*_ 2 __author__ = 'Alex Li' 3 4 import time 5 def consumer(name): 6 print("%s 准备吃包子啦!" %name) 7 while True: 8 baozi = yield 9 10 print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) 11 12 13 def producer(name): 14 c = consumer('A') 15 c2 = consumer('B') 16 c.__next__() 17 c2.__next__() 18 print("老子开始准备做包子啦!") 19 for i in range(10): 20 time.sleep(1) 21 print("做了2个包子!") 22 c.send(i) 23 c2.send(i) 24 25 producer("alex") 26 27 #通过生成器实现协程并行运算
迭代器:
直接作用于for循环的数据类型以下几种:
一类是集合数据类型:列表(list),元组(tuple),字典(dict),集合(set),字符串(str)等
一类是generator,包括生成器和带yield的generator function。
这类可直接作用于for循环的对象统称为可迭代对象:Tterable
可以使用isinstance()判断一个对象是是否是Iterrator对象:
1 >>> from collections import Iterable 2 >>> isinstance([], Iterable) 3 True 4 >>> isinstance({}, Iterable) 5 True 6 >>> isinstance('abc', Iterable) 7 True 8 >>> isinstance((x for x in range(10)), Iterable) 9 True 10 >>> isinstance(100, Iterable) 11 False
而生成器不但可以作用于for循环,还可以被next()函数不断调用并但会下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
可以被next()函数调用并不断返回下一值的对象称为迭代器:Iterator
可以使用isinstance()判断一个对象是否是Iterator对象:
1 >>> from collections import Iterator 2 >>> isinstance((x for x in range(10)), Iterator) 3 True 4 >>> isinstance([], Iterator) 5 False 6 >>> isinstance({}, Iterator) 7 False 8 >>> isinstance('abc', Iterator) 9 False
由此可知:生成器都是Iterator对象,但列表、字典、字符串虽然是Iterable但不是Iterator
小结:
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,他们表示一个惰性极端的序列(即只有在需要的时候才会计算,不需要则不会计算);
集合数据类型如:列表、字典、字符串,集合等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
如for新欢本质上是通过不断调用next()函数实现的:
for x in [1, 2, 3, 4, 5]: pass
实际上等价于:
1 # 首先获得Iterator对象: 2 it = iter([1, 2, 3, 4, 5]) 3 # 循环: 4 while True: 5 try: 6 # 获得下一个值: 7 x = next(it) 8 except StopIteration: 9 # 遇到StopIteration就退出循环 10 break
4.内置函数
见博客地址:
5.软件目录结构规范