1、列表生成式,也叫列表推导式
即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。
优点:构造简单,一行完成
缺点:不能排错,不能构建复杂的数据结构
1.1、循环模式[i for i in iterable]
l1 = [i for i in range(1,101)]
print(l1)
l2 = ['python第%s天'%i for i in range(1,11)] print(l3) 结果:
['python第1天', 'python第2天', 'python第3天', 'python第4天', 'python第5天', 'python第6天', 'python第7天', 'python第8天', 'python第9天', 'python第10天']
10以内的数的平方
l3 = [i*i for i in range(11)]
print(l3)
结果:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
1.2、筛选模式[i for i in iterable if 判断式]
a = [i for i in range(1,100) if i%2==1] print(list(a))或print(a) 结果:
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99]
或一句话输出
print([i for i in range(1,100) if i%2==0]) 结果:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98]
30以内能被3整除的数的平方
l4 = [i*i for i in range(31) if i%3 == 0] print(l4) 结果:
[0, 9, 36, 81, 144, 225, 324, 441, 576, 729, 900]#
过滤掉非字符串类型和长度小于3的字符串,并将剩下的转成大写字母
lst = ['mike', 'tom', 'jack', 're', 'ab', 123] l5 = [i.upper() for i in lst if isinstance(i, str) and len(i) >= 3] print(l5) 结果: ['MIKE', 'TOM', 'JACK']
列出当前目录下的所有文件和目录名,可以通过一行代码实现:
import os
print([d for d in os.listdir('.')]) # os.listdir可以列出文件和目录
['.emacs.d', '.ssh', '.Trash', 'Adlm', 'Applications', 'Desktop', 'Documents', 'Downloads', 'Library', 'Movies', 'Music', 'Pictures', 'Public', 'VirtualBox VMs', 'Workspace', 'XCode']
3、两层循环,可以生成全排列
print([m + n for m in 'ABC' for n in 'XYZ']) ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
列表生成式也可以使用两个变量来生成list:
d = {'x': 'A', 'y': 'B', 'z': 'C' } print([k + '=' + v for k, v in d.items()]) ['y=B', 'x=A', 'z=C']
一句话生成九九乘法表
print (' '.join([' '.join(['%s*%s=%-3s'%(y,x,x*y) for y in range(1,x+1)]) for x in range(1,10)]))
2、迭代器
1、可迭代对象
内部含有'__iter__'方法的数据就是可迭代对象
可迭代对象:list、str、tuple、set、dict、range()、文件句柄
print(dir(对象名))
如果打印结果里面有'__iter__',则这个对象就是可迭代对象
print('__iter__' in dir([1,2,3]))
True
如果结果为True,就表示对象是可迭代对象
2、迭代器
内部含有'__iter__'方法,并且含有'__next__'方法的对象就是迭代器
文件句柄就是一个迭代器
f1 = open('1.txt', encoding='utf-8'): print('__iter__' in dir(f1)) True print('__next__' in dir(f1)) True
l1 = [1,2,3,'a'] iter1 = iter(l1) 或 iter1 = l1.__iter__() print(iter1.__next__()) print(iter1.__next__()) print(iter1.__next__()) print(iter1.__next__()) 1 2 3 a #迭代完了之后如果再取值,就会报错StopIteration
迭代器特点:
1、非常节省内存
2、满足惰性机制
3、一条路走到黑
利用while循环模拟for循环
1、将可迭代对象转化成迭代器
2、利用next进行取值
3、利用异常处理终止循环
l1 = [1,2,3,'a'] iter1 = l1.__iter__() while 1: try: print(iter1.__next__()) except StopIteration: break
3、生成器,自己用python代码写的迭代器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
有两种方式:
1、函数式写法
2、生成器表达式
函数式写法,构建生成器
只要函数中出现yield,那么他就不是一个函数了,他是生成器函数
def func1(): yield 3 yield 4 func1() #这样不会调用该函数 g = func1() print(g.__next__()) #一个next对应一个yield的值 print(g.__next__()) #再一个next对应下一个yield的值 3 4
yield和return的区别
return 结束函数,给函数返回值
yield不会结束生成器函数,一个next对应一个yield进行取值
例子:如果循环打印一个列表,可以同时打印出来
def num1(): for i in range(1,11): print('编号%s'%(i)) num1() 编号1 编号2 编号3 编号4 编号5 编号6 编号7 编号8 编号9 编号10
也可以不一次性打印出来,需要打印几个就先打印出几个
def num2(): for i in range(1,11): yield ('编号%s'%(i)) g = num2() #这里需要将函数执行重新赋值给一个变量,不能用print(num2().__next__(),否则每次打印都是第一个值1 print(g.__next__()) #编号1 for i in range(3): print(g.__next__()) #编号2 #编号3 #编号4 for i in range(6): print(g.__next__()) #编号5 #编号6 #编号7 #编号8 #编号9 #编号10
4、生成器表达式
只需要将列表推导式用小括号表示即可生成一个生成器迭代器
g1 = (i*i for i in range(10000)) print(g1.__next__()) print(g1.__next__()) print(g1.__next__()) print(g1.__next__()) print(g1.__next__()) 0 1 4 9
如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
def fib(max): n,a,b = 0,0,1 while n<max: print(b) a,b = b, a+b n+=1 fib(6) 1 1 2 3 5 8 13
仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。
也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 print('done') g = fib(6) print(g.__next__()) print(g.__next__()) print(g.__next__()) print(g.__next__()) print(g.__next__()) 1 1 2 3 5
把函数改成generator后,如果用next()来获取下一个返回值有点麻烦,也可以直接使用for循环来迭代:
for n in fib(6): print(n) 1 1 2 3 5 8
例子:
杨辉三角定义如下:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
把每一行看做一个list,试写一个generator,不断输出下一行的list: def triangel(max): n,L=0,[1] #定义一个list[1] while n<max: yield L #打印出该list L=[1]+[L[x]+L[x+1] for x in range(len(L)-1)]+L[1] #计算下一行中间的值,两边再各添加一个[1] #生成一个generator对象,然后通过for循环迭代输出每一行 a=triangel(10) for i in a: print(i)
或者
def triangles(max): L=[1] i = 0 while n<max: yield L L.append(0) L = [L[i-1]+L[i] for i in range(len(L))] a=triangel(10) for i in a: print(i)
注:普通函数和generator生成器的区别:
1.普通函数调用直接返回结果,generator函数的调用,返回一个generator对象;
(调用generator时可以先创建一个对象,再用next()方法不断获得下一个返回值,但实际中通常用for循环实现)
2.generator在执行过程中,遇到yield就中断,下次又继续执行