三分钟搞懂Python生成器

关注我的微信公众号:pythonislover,领取python,大数据,SQL优化相关视频资料!~

Python大数据与SQL优化笔 QQ群:771686295

生成器

生成器:函数中只要有yield,这个函数就会变成生成器。每次运行到yield的时候,函数会暂停,并且保存当前的运行状态,返回返回当前的数值,并在下一次执行next方法的时候,又从当前位置继续往下走。概念

简单用法

举个例子:

def gen():
    yield 1
    # 返回一个对象,这个对象的值是1
def ret():
    return 1
    # 返回一个数字1
g = gen()
r = ret()
print(g,r)
print(next(g))

返回结果:

<generator object gen at 0x000001487FDA2D58> 1
1

可以看到return是直接返回数值1,yield是返回的一个生成器对象,这个对象的值是1,使用next(g)或者for x in g:print x 都是可以获取到他的内容的,这个对象是在python编译字节码的时候就产生。

def gen():
    yield 1
    yield 11
    yield 111
    yield 1111
    yield 11111
    yield 111111
    # 返回一个对象,这个对象内的值是1和11,111...
def ret():
    return 1
    return 3
    # 第二个return是无效的
g = gen()
r = ret()
print(g,r)
print(next(g))
for x in g:
    print(x)

返回结果:

<generator object gen at 0x000002885FE32D58> 1
1
11
111
1111
11111
111111

就像迭代器的特性一样,获取过一遍的值是没法再获取一次的,并且不是那种一次把所有的结果求出放在内存或者说不是一次性读取所有的内容放在内存中。

梳理特性:

  1. 使用yield的函数都是生成器函数

  2. 可以使用for循环获取值,也可以使用next获取生成器函数的值

下面是一个生产者,消费者的案例

def consumer(name):    print('我是[%s],开始消费数据' %name)    while True:        data=yield        time.sleep(1)        print('%s 消费了【%s】' %(name,data))
def producer():    c1=consumer('test1')    c2=consumer('test2')    c1.__next__()    c2.__next__()    for i in range(10):        time.sleep(1)        c1.send('数据%s' %i)        c2.send('数据 %s' %i)producer()

 

应用场景

读取文件,使用open(‘xxx’).read(2019)//打开一个文件,每次读取2019个偏移量。文件a.txt是一行文字,但是特别长,这一行文字根据|符号分开,如何读取?

写入文件代码:

# -*- coding:utf-8 -*-
import random
import threading
import string
import time
t1 = time.time()
def write(x):
    with open('a.txt','a+')as a:
        a.write(x + '||')

def run():
    for x in range(10000000):
        strs = str(random.randint(1000,2000)) +random.choice(string.ascii_letters)*10
        write(strs)
for x in range(10):
    t = threading.Thread(target=run)
    t.start()
t2 = time.time()
print(t2 - t1)

读取文件代码:

# -*- coding:utf-8 -*-
def readbooks(f, newline):
    # f为传入的文件名,newline为分隔符
    buf = ""
    # 缓存,处理已经读出来的数据量
    while 1:
        while newline in buf:
            # 缓存中的数据是否存在分隔符
            pos = buf.index(newline)
            # 如果存在就找到字符的位置,比如0或者1或者2
            yield buf[:pos]
            # 暂停函数,返回缓存中的从头到字符的位置
            buf = buf[pos + len(newline):]
            # 缓存变成了,字符的位置到末尾
        chunk = f.read(2010 * 10)
        # 读取2010*10的字符
        if not chunk:
            # 已经读取到了文件结尾
            yield buf
            break
        buf += chunk
        # 加到缓存
 with open('a.txt','r')as f:
     for line in readbooks(f,'||'):
         print(line)

猜你喜欢

转载自blog.csdn.net/yrg5101/article/details/88948654