生成器的创建方法:
(1)通过列表生成式创建
可以通过将列表生成式的 [] 改成()
- eg:
- # 列表生成式
- L = [ x*2 for x in range(5)] # L = [0, 2, 4, 6, 8]
- # 生成器
- G = ( x*2 for x in range(5)) # 此时的 G 是,<generator object <genexpr> at 0x7f626c132db0>
创建列表生成式和生成器的区别只是最外层的 () 和[], 列表生成式是一个列表, 而生成器事宜个可迭代对象. 生成器对象可以通过 for 语句遍历每个元素.
- for each in G:
- print(each) # 打印结果是 0 2 4 6 8
(2)通过函数来实现
generator 非常强大, 如果推算的算法比较复杂, 用类似的列表生成式的 for 循环无法实现的时候, 可以通过函数来实现.
以著名的斐波拉契数列(Fibonacci), 除第一个和第二个数外, 任意一个数都可以由前两个数相加得到: 1,1,2,3,5,8,13....
斐波拉契数列用列表生成式不容易写出来, 但是用函数把它打印出来很容易:
- def fib(times):
- n = 0
- a, b = 0, 1
- while n < times:
- yield b # 这里用的 yield 将 b 的值返回到生成器中.
- a, b = b, a+b
- n += 1
- return 'done'
- f = fib(5)
- for each in f:
- print(each)
上述例子中, 在循环过程中不断调用 yield, 就不会中断函数, 但是必须要指定一个结束循环的条件, 不然会产生一个无限循环的数列出来.
上述中, 用 for 循环是拿不到 return 语句的返回值的, 如果想拿到返回值, 必须捕获 StopIteration 错误, 返回值包含在 StopIteration 的 value 中:
- g = fib(5)
- while True:
- try:
- x = next(g)
- print('value: %d' % x)
- except StopIteration as e:
- print('生成器返回值:%s' % e.value)
- break
这样就可以取到 return 的返回值了.
(3)生成器的特点
生成器是这样一个函数, 它记住上一次返回时在函数体中的位置. 对生成器函数的第二次 (或第 n 次) 调用跳转至该函数中间, 而上次调用的所有局部变量都保持不变.
生成器不仅 "记住" 了它数据状态; 生成器还 "记住" 了它在流控制构造 (在命令式编程中, 这种构造不只是数据值) 中的位置.
生成器的特点:
节约内存
迭代到下一次的调用时, 所使用的参数都是第一次所保留下的, 即是说, 在整个所有函数调用的参数都是第一次所调用时保留的, 而不是新创建的
2, 迭代器
迭代是访问集合的一种方式. 迭代器是一个可以记住遍历的位置的对象, 迭代器对象从第一个元素开始访问, 直到所有的元素被访问完结束, 迭代器只能往前不能后退.
(1)可迭代对象
可迭代对象可以直接用户 for 循环的数据类型:
第一类是集合数据类型: 如 list,tuple,set,dict,str 等等.
第二类是 generator, 包括生成器和代 yield 的生成器函数.
(2)判断是否为可迭代对象
可以使用 isinstance()函数来判断一个对象是否是可迭代对象.
- from collections import Iterable
- isinstance([], Iterable) # 如果是可迭代对象则返回 True, 反之返回 False.
生成器不但可以作用于 for 循环, 而且还可以被 next()函数不断调用, 知道抛出 StopIteration 错误, 表示无法继续返回下一个值了.
(3)迭代器
可以被 next()函数调用并不断返回下一个值得对象称为迭代器(Iterator)
可以使用 isinstance()函数来判断一个对象是否是迭代器对象.
- from collections import Iterator
- isinstance((x for x in range(10)), Iterator) # 如果是迭代器则返回 True, 反之 False
(4)iter()函数
生成器都是 Iterator 对象, 但是 list,dict,str 虽然是 Iterable, 但是不是 Iterator. 如果想把 list,dict,str 等可迭代对象变成迭代器, 可以使用 iter()函数.
isinstance 大专栏 python 语法生成器, 迭代器, 闭包, 装饰器总结 (iter([]), Iterator) # 返回值是 True, 证明 iter([]) 是迭代器.
(5)总结
凡是可以用 for 循环的对象, 都是可迭代对象类型(iterable)
凡是可用于 next()函数的对象, 都是 iterator(迭代器)类型.
集合数据类型, 如 list,dict,str 等是可迭代对象, 但不是迭代器, 可以通过 iter()函数获得一个迭代器对象.
3, 闭包
闭包是在函数内部再定义一个函数, 并且这个函数用到了外部函数的变量, 就将这个函数以及用到的一些变量称之为闭包. 简言之, 内部函数对外部函数作用域里变量的引用(非全局变量), 则称内部函数为闭包.
闭包示例:
- def line_conf(a, b):
- def line(x):
- return a*x + b
- return line
- line1 = line_conf(1, 1)
- line2 = line_conf(4, 5)
- print(line1(5))
- print(line2(5))
上例中, 函数 line 与变量 a, b 构成闭包. 在创建闭包的时候, 我们通过 line_conf 的参数 a, b 说明了这两个变量的取值, 这样, 我们就确定了函数的最终形式(y = x + 1 和 y = 4x + 5). 我们只要变换参数 a, b 就可以得到不同的曲线表达函数, 由此, 闭包也具有提高代码可重复用性的作用.
如果没有闭包, 我们需要每次创建直线函数的时候同时说明 a, b, x. 这样, 我们需要更多的参数传递, 也减少了代码的可移植性.
闭包总结:
闭包优化了变量, 原来需要类对象完成的工作, 闭包也可以完成.
由于闭包引用的外部函数的局部变量, 则外部函数的局部变量没有及时释放, 消耗内存.
4, 装饰器
装饰器其实就是一个闭包, 把一个函数当做参数然后返回一个替代的函数. 这个替代的函数可以增添新的功能.
(1)装饰器 (decorator) 功能
引入日志
函数执行时间统计
执行函数前的预处理
执行函数后的清理功能
权限校验等场景
缓存
(2)装饰器示例
1. 无参数函数
- from time import sleep, ctime
- def timefun(func):
- def wrappedfunc():
- print('%s is called at %s'%(func.__name__, ctime())
- func()
- return wrappedfunc
- @timefunn
- def foo():
- print('I am foo')
- foo()
- sleep(2)
- foo()
2. 被修饰的函数有参数
- from time import ctime, sleep
- def timefunc(func):
- def wrappedfunc(a, b):
- print('%s is called at %s'%(func.__name, ctime())
- print(a, b)
- func(a, b)
- return wrappedfunc
- @timefunc
- def foo(a, b)
- print(a+b)
- foo(3, 5)
- sloop(2)
- foo(2, 4)
3. 被修饰函数带有不定长参数
- from time import ctime, sleep
- def timefunc(func):
- def wrappedfunc(*args, **kwargs):
- print('%s is called at %s'%(func.__name__, ctime())
- func(*args, **kwargs)
- return wrappedfunc
- @timefunc
- def foo(a, b, c):
- print(a+b+c)
- foo(3,5,2)
- sleep(2)
- foo(2, 4, 9)
4. 装饰器中带有 return
- from time import ctime, sleep
- def timefunc(func):
- def wrappedfunc():
- print('%s called at %s'%(func.__name__, ctime())
- func()
- return wrappedfunc
- @timefunc
- def foo():
- print('i am foo')
- @timefunc
- def getInfo():
- return '----hahahah-----'
- foo()
- sleep(2)
- foo()
- print(getInfo())
- # 执行结果是
- foo called at ....
- I am foo
- foo called at .....
- I am foo
- getInfo called at ...
- None
有结果可见, 带有 return 的修饰器, 如果还是按照上述的写法, 则不会返回值. 如果把修饰器函数中的 func(), 改为 return func(), 则 print(getInfo())的执行结果是:
getInfo called at ...
--hahahah--
这样 return 能正确返回.
来源: http://www.bubuko.com/infodetail-3412499.html