1、列表生成式
列表生成式是Python内置的可以用来创建list的生成式
列表生成式, 它的基础语法是: [exp for iter_var in iterable]
首先迭代 iterable 里所有内容, 每一次迭代, 都把 iterable 里相应内容放到 iter_var 中, 再在表达式 exp 中应用该 iter_var 的内容, 最后用表达式的计算值生成一个新的列表.
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import math# 导入数学公式模块
from collections import Iterable# 判断是否为可迭代对象
import os# 导入os模块
# 生成L1[0,1,2,3....,9]可以使用range(0,10)
L1 = range(0,10)
print L1
# 生成L2[0*0,1*1,2*2,,,,,9*9]可以使用range(0,10)和循环
L2 = []
for n in range(0,10):
L2.append(n*n)
print L2
# 利用列表生成式可以更方便的实现上面两个例子
L1 = [m for m in range(0,10)]
print L1
L2 = [n*n for n in range(0,10)]
print L2
# 除此之外,还可以使用两层,三层等多层循环,但一般只用到两层
L_Sum = [(x + y) for x in range(0,10) for y in range(10,20)]# 全排列,共有100种结果
print L_Sum
L_Cat = [(x,y) for x in '012' for y in "abc"]
print L_Cat
# 可以在列表生成式的循环之后加上if,实现筛选功能,筛选的结果是一个新的list
L_Sel = [i for i in range(1,21) if i % 2 == 0]
print L_Sel
# 列表生成式中的for循环可以同时使用两个变量甚至多个变量
# 将dict变成对应的list,将key和values连接起来
D = {0:'a',1:'b',2:'c'}
L_L = [str(k) + '-' + v for k,v in D.iteritems()]
print L_L
# 将list中的所有字符串元素的大写变成小写
# 当list中包含字符串与整数时,使用lower()函数会报错,所以,可以使用内置函数先判断一个元素是否是字符串
L = ['Abcd','aBcd',1,'abCd','abcD']
L_low = [s.lower() for s in L if (isinstance(s,str))]
print L_low
# 将list中的所有字符串元素的大写变成小写,其他元素不变
L_l = [s.lower() if (isinstance(s,str)) else s for s in L ]
print L_l
# 运用列表生成式可以列出某目录下额所有文件名和目录名
L_file1 = [f for f in os.listdir('.')]# 当前目录
print L_file1
L_file2 = [f for f in os.listdir(r'd:\\python')]# 指定目录
print L_file2
# os.listdir('.')不能访问其子文件夹
# 可以通过os.path.walk递归遍历,可以访问子文件夹,但是未进行格式化
L_file3 = [f for f in os.walk(r'd:\\python\\workspace')]# 当前目录
print L_file3,'\n'
# 自定义格式化函数
def processDirectory ( args, dirname, filenames ):
print 'Directory:',dirname
for filename in filenames:
print 'File\\\\:',filename
os.path.walk(r'd:\\python\\workspace', processDirectory, None )
运行结果:
2、生成器
# ★★★先搞清与列表生成式的区别及生成器的原理★★★
通过列表生成式,我们可以直接创建一个列,当表达式的结果数量较少的时候, 使用列表生成式还好, 一旦数量级过大, 那么将占用很大的内存,如果仅仅访问前面一部分的元素,则后面的绝大部分占用的空间就浪费了。
而生成器并不是立即把结果写入内存,generator本身保存的一种计算方式(算法),通过不断的获取到相应的位置的值,是一边循环一边计算的机制,所以占用的内存仅仅是对计算对象的保存,即解决使用列表生成式创建包含超级多的元素时造成的内存空间浪费的问题。
在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。
generator的工作原理:在for 循环的过程中不断计算出下一个元素,并在适当的条件结束for 循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令, for 循环随之结束。
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import math# 导入数学公式模块
from collections import Iterable# 判断是否为可迭代对象
import os# 导入os模块
# ★★使用生成器创建list列表时,与列表生成式很相似,即把中括号改为圆括号:即[]->()
L = [l ** 3 for l in range(0,10)]# 中括号[]
print L
G = (g ** 3 for g in range(0,10))# 小括号()
print G
# 从返回结果可以看出,列表生成式直接返回的是结果值,生成器返回的是一个包含了对表达式结果的计算引用的对象
# 区别:1、list生成式生成的list可以直接打印,generator生成器无法直接打印。2、list生成式使用的是[],generator生成器使用的是()
# ★可以通过调用generator的next()方法打印各元素
G = (g ** 3 for g in range(0,10))
for i in range(0,10):#for i in range(0,11):
print G.next()
# generator保存的是算法,每次调用next() ,就计算出下一个元素的值,直到计算到最后一个元素.
# 如果此时再使用next(),抛出StopIteration的错误。而且此时generator对象以为空
# ★generator也是可迭代对象,所以基本上不会调用其next()方法,而是通过for 循环来迭代它
G = (g ** 3 for g in range(0,10))
if isinstance(G,Iterable):
for i in G:
print i
# 在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator
# ★★如果一个函数定义中包含yield 关键字,那么这个函数就不再是一个普通函数,而是一个generator
# 如果推算的算法比较复杂,用类似列表生成式的for 循环无法实现的时候,还可以用函数来实现
# 例:斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到
def fib(N):# 打印前N个元素
n, a, b = 0, 0, 1
while n < N:
print b
a, b = b, a + b# ★对应连续赋值
n = n + 1
fib(10)
# fib()函数实际上是定义了斐波拉契数列的推算规则,这种逻辑其实非常类似generator
# ★要把fib()函数变成generator,只需要把print b 改为yield b
def fib(N):# 打印前N个元素
n, a, b = 0, 0, 1
while n < N:
yield b
a, b = b, a + b# ★对应连续赋值
n = n + 1
f = fib(10)
print f.next()
print f.next()
print f.next()
print f.next()
# ★generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。
# 而变成generator的函数,在每次调用next() 的时候执行,遇到yield 语句返回,再次执行时从上次返回的yield 语句处继续执行。
# ★把函数改成generator后,基本上不会用到其next()方法来调用它,而是直接使用for 循环来迭代
for n in fib(10):
print n
运行结果:
生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的