【Python学习笔记】列表生成式和生成器

一、列表生成式
      列表生成式是Python内置的能够用来建立list的生成式python

      列表生成式, 它的基础语法是: [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 )

运行结果:app

二、生成器函数

# ★★★先搞清与列表生成式的区别及生成器的原理★★★
经过列表生成式,咱们能够直接建立一个列,当表达式的结果数量较少的时候, 使用列表生成式还好, 一旦数量级过大, 那么将占用很大的内存,若是仅仅访问前面一部分的元素,则后面的绝大部分占用的空间就浪费了。
而生成器并非当即把结果写入内存,generator自己保存的一种计算方式(算法),经过不断的获取到相应的位置的值,是一边循环一边计算的机制,因此占用的内存仅仅是对计算对象的保存,即解决使用列表生成式建立包含超级多的元素时形成的内存空间浪费的问题。
在Python中,能够简单地把列表生成式改为generator,也能够经过函数实现复杂逻辑的generator。
generator的工做原理:在for 循环的过程当中不断计算出下一个元素,并在适当的条件结束for 循环。对于函数改为的generator来讲,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令, for 循环随之结束。spa

#!/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
# 从返回结果能够看出,列表生成式直接返回的是结果值,生成器返回的是一个包含了对表达式结果的计算引用的对象
# 区别:一、list生成式生成的list能够直接打印,generator生成器没法直接打印。二、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

运行结果:code

                  

生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的全部局部变量都保持不变,便是说,在整个全部函数调用的参数都是第一次所调用时保留的,而不是新建立的对象

相关文章
相关标签/搜索