python内置的生成器_python 生成器

## 生成器

#### 创建生成器

#### 方法一

~~~

In [15]: L = [ x*2 for x in range(5)]

In [16]: L

Out[16]: [0, 2, 4, 6, 8]

In [17]: G = ( x*2 for x in range(5))

In [18]: G

Out[18]: at 0x7f626c132db0>

注:其中L是一个列表 G是一个生成器,我们可以直接打印出L 的每一个元素。则 G可以通过next()函数获取生成器的下一个返回值,没有最后一个元素,则抛出异常。

In [19]: next(G)

Out[19]: 0

In [20]: next(G)

Out[20]: 2

In [21]: next(G)

Out[21]: 4

In [22]: next(G)

Out[22]: 6

In [23]: next(G)

Out[23]: 8

In [24]: next(G)

---------------------------------------------------------------------------

StopIteration Traceback (most recent call last)

in ()

----> 1 next(G)

StopIteration:

~~~

#### 方法二

带有 yield 的函数在 Python 中被称之为 generator(生成器)

生成斐波那契

~~~

#!/usr/bin/python

# -*- coding: UTF-8 -*-

def fab(max):

n, a, b = 0, 0, 1

while n < max:

print b

a, b = b, a + b

n = n + 1

fab(5)

~~~

面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:

~~~

In [30]: def fib(times):

....: n = 0

....: a,b = 0,1

....: while n

....: yield b // 用yield来声明为生成器函数

....: a,b = b,a+b

....: n+=1

....: return 'done'

....:

In [31]: F = fib(5) #创建一个生成器对象

In [32]: next(F)

Out[32]: 1

In [33]: next(F)

Out[33]: 1

In [34]: next(F)

Out[34]: 2

In [35]: next(F)

Out[35]: 3

In [36]: next(F)

Out[36]: 5

In [37]: next(F)

---------------------------------------------------------------------------

StopIteration Traceback (most recent call last)

in ()

----> 1 next(F)

StopIteration: done

~~~

#### 其中next(F) 与F.\_\_next()\_\_方法一样

函数改成generator后,我们基本上从来不会用 next() 来获取下一个返回值,而是直接使用 for 循环来迭代:

~~~

In [38]: for n in fib(5):

....: print(n)

....:

1

1

2

3

5

In [39]:

~~~

但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:

~~~

In [39]: g = fib(5)

In [40]: while True:

....: try:

....: x = next(g)

....: print("value:%d"%x)

....: except StopIteration as e:

....: print("生成器返回值:%s"%e.value)

....: break

....:

value:1

value:1

value:2

value:3

value:5

生成器返回值:done

In [41]:

~~~

2. ### [](https://note.youdao.com/md/?defaultMode=view&fileId=WEB67cf250cd280c428a4d3eca330bb66a6#send)send

例子:执行到yield时,gen函数作用暂时保存,返回i的值;temp接收下次c.send("python"),send发送过来的值,c.next()等价c.send(None)

~~~

In [43]: f = gen()

In [44]: f.__next__()

Out[44]: 0

In [45]: f.send('haha')

haha

Out[45]: 1

In [46]: f.__next__()

None

Out[46]: 2

In [47]: f.send('haha')

haha

Out[47]: 3

~~~

## 迭代器

代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

#### 判断是否可以跌代

~~~

In [50]: from collections import Iterable

In [51]: isinstance([], Iterable)

Out[51]: True

In [52]: isinstance({}, Iterable)

Out[52]: True

In [53]: isinstance('abc', Iterable)

Out[53]: True

In [54]: isinstance((x for x in range(10)), Iterable)

Out[54]: True

In [55]: isinstance(100, Iterable)

Out[55]: False

~~~

## iter()函数

生成器都是 Iterator 对象,但 list 、 dict 、 str 虽然是 Iterable ,却不是 Iterator 。

把 list 、 dict 、 str 等 Iterable 变成 Iterator 可以使用 iter() 函数:

~~~

In [62]: isinstance(iter([]), Iterator)

Out[62]: True

In [63]: isinstance(iter('abc'), Iterator)

Out[63]: True

~~~

## 闭包

~~~

#定义一个函数

def test(number):

#在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包

def test_in(number_in):

print("in test_in 函数, number_in is %d"%number_in)

return number+number_in

#其实这里返回的就是闭包的结果

return test_in

#给test函数赋值,这个20就是给参数number

ret = test(20)

#注意这里的100其实给参数number_in

print(ret(100))

#注意这里的200其实给参数number_in

print(ret(200))

运行结果:

in test_in 函数, number_in is 100

120

in test_in 函数, number_in is 200

220

~~~

### 闭包再理解

内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包。

~~~

# closure.py

def counter(start=0):

count=[start]

def incr():

count[0] += 1

return count[0]

return incr

启动python解释器

>>>import closeure

>>>c1=closeure.counter(5)

>>>print(c1())

6

>>>print(c1())

7

>>>c2=closeure.counter(100)

>>>print(c2())

101

>>>print(c2())

102

nonlocal访问外部函数的局部变量(python3)

def counter(start=0):

def incr():

nonlocal start

start += 1

return start

return incr

c1 = counter(5)

print(c1())

print(c1())

c2 = counter(50)

print(c2())

print(c2())

print(c1())

print(c1())

print(c2())

print(c2())

~~~

#### 看一个闭包的实际例子:

~~~

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))

~~~

#### 装饰器

~~~

#定义函数:完成包裹数据

def makeBold(fn):

def wrapped():

return "" + fn() + ""

return wrapped

#定义函数:完成包裹数据

def makeItalic(fn):

def wrapped():

return "" + fn() + ""

return wrapped

@makeBold #当python解释器执行到这行代码的时候,那么就自动进行了装饰,而不是调用的时候才进行装饰

def test1():

return "hello world-1"

@makeItalic

def test2():

return "hello world-2"

@makeBold #test3 = makeBold(test3)

@makeItalic #test3 = makeItalic(test3)

def test3():

return "hello world-3"

print(test1()))

print(test2()))

print(test3()))

运行结果:

hello world-1

hello world-2

hello world-3

~~~

#### 装饰器(decorator)功能

1. 引入日志

2. 函数执行时间统计

3. 执行函数前预备处理

4. 执行函数后清理功能

5. 权限校验等场景

6. 缓存

### 装饰器示例

1. 无参数的函数

~~~

from time import ctime, sleep

def timefun(func):

def wrappedfunc():

print("%s called at %s"%(func.__name__, ctime()))

func()

return wrappedfunc

@timefun

def foo():

print("I am foo")

foo()

sleep(2)

foo()

~~~

上面代码理解装饰器执行行为可理解成 foo = timefun(foo) #foo先作为参数赋值给func后,foo接收指向timefun返回的wrappedfunc foo() #调用foo(),即等价调用wrappedfunc() #内部函数wrappedfunc被引用,所以外部函数的func变量(自由变量)并没有释放 #func里保存的是原foo函数对象

2. 被装饰的函数有参数

~~~

from time import ctime, sleep

def timefun(func):

def wrappedfunc(a, b):

print("%s called at %s"%(func.__name__, ctime()))

print(a, b)

func(a, b)

return wrappedfunc

@timefun

def foo(a, b):

print(a+b)

foo(3,5)

sleep(2)

foo(2,4)

~~~

3. 被装饰的函数有不定长参数

~~~

from time import ctime, sleep

def timefun(func):

def wrappedfunc(*args, **kwargs):

print("%s called at %s"%(func.__name__, ctime()))

func(*args, **kwargs)

return wrappedfunc

@timefun

def foo(a, b, c):

print(a+b+c)

foo(3,5,7)

sleep(2)

foo(2,4,9)

~~~

4. 装饰器中的return

~~~

from time import ctime, sleep

def timefun(func):

def wrappedfunc():

print("%s called at %s"%(func.__name__, ctime()))

func()

return wrappedfunc

@timefun

def foo():

print("I am foo")

@timefun

def getInfo():

return '----hahah---'

foo()

sleep(2)

foo()

print(getInfo())

~~~

5. 装饰器带参数,在原有装饰器的基础上,设置外部变量

~~~

from time import ctime, sleep

def timefun_arg(pre="hello"):

def timefun(func):

def wrappedfunc():

print("%s called at %s %s"%(func.__name__, ctime(), pre))

return func()

return wrappedfunc

return timefun

@timefun_arg("itcast")

def foo():

print("I am foo")

@timefun_arg("python")

def too():

print("I am too")

foo()

sleep(2)

foo()

too()

sleep(2)

too()

可以理解为

foo()==timefun_arg("itcast")(foo)()

~~~

注释 :通用装饰器的使用

~~~

# !usr/bin/python3

# -*-coding:utf8 -*-

# 通用装饰器

def func(functionName):

def func_in(*args,**kwargs):

return functionName(*args,**kwargs)

return func_in

# ① 不带返回值的装饰器

@func

def test1():

print('----test1----')

test1()

# ② 带返回值的装饰器

@func

def test2():

print("----test2------")

return "带装饰器的返回值"

ret = test2()

print(ret);

# ③ 带参数的装饰器

@func

def test3(a):

print("-----test3的参数值为%s"%a)

test3(11)

~~~

6. 类装饰器(扩展,非重点)

装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。只要某个对象重写了**call**() 方法,那么这个对象就是callable的。

~~~

class Test():

def __call__(self):

print('call me!')

t = Test()

t() # call me

~~~

类装饰器demo

~~~

class Test(object):

def __init__(self, func):

print("---初始化---")

print("func name is %s"%func.__name__)

self.__func = func

def __call__(self):

print("---装饰器中的功能---")

self.__func()

#说明:

#1. 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象

# 并且会把test这个函数名当做参数传递到__init__方法中

# 即在__init__方法中的func变量指向了test函数体

#

#2. test函数相当于指向了用Test创建出来的实例对象

#

#3. 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__方法

#

#4. 为了能够在__call__方法中调用原来test指向的函数体,所以在__init__方法中就需要一个实例属性来保存这个函数体的引用

# 所以才有了self.__func = func这句代码,从而在调用__call__方法中能够调用到test之前的函数体

@Test

def test():

print("----test---")

test()

showpy()#如果把这句话注释,重新运行程序,依然会看到"--初始化--"

~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值