Python全栈之路Day21

初次编辑2017年10月27日,星期五

摘要

引用:Alex

  1. 迭代器
  2. 生成器
  3. 协程函数

一. 上节课复习

  1. 装饰器
    1. 无参装饰器
    2. 有参装饰器
  2. 装饰器打印原函数信息
import time
from functools import wraps        #注意这个
def timmer(func):
    @wraps(func)        #还有这个
    def wrapper():
        start_time = time.time()
        func()
        stop_time = time.time()
        print('run time is %s ' % (stop_time - start_time))
    return wrapper

@timmer        #index=timmer(index)
def index():
    'come from index'
    print('welcome to oldboy')

index()        #wrapper()
print(index.__doc__)        #.__doc__打印函数描述信息,具体不是很了解

二. 迭代器

  1. 可迭代的
    • 只要对象本身有__iter__方法,那它就是可迭代的
  2. 迭代器
    • i = a.iter() #i 即为迭代器
    • 可通过__next__ 进行取值
b = {'a':1,'b':2,'c':3}
i = iter(b)
while True:
    print(next(i))

#注意:此方法会while会无限循环,报错异常 StopIteration
  1. 异常捕捉
b = {'a':1,'b':2,'c':3}
i = iter(b)
while True:
    try:        #注意此行
        print(next(i))
    except StopIteration:        #and this
        break    # and this
  1. for 循环机制
for key in d:    #d即为d.__iter__() 迭代器放入原位置
    print(key)    #并且for循环具有异常捕捉的功能
  1. for 循环实现迭代器
b = {'a':1,'b':2,'c':3}
for i in b:
    print(i)
  1. 为什么要用迭代器
    • 优点
      1. 迭代器提供了一种不依赖于索引的取值方式,这样就可以遍历那些没有索引的可迭代对象了(字典、集合、文件)
      2. 迭代器与列表相比,迭代器是惰性计算的,更省内存(迭代器在内存中同一时刻只有一个值)
    • 缺点
      1. 无法获取迭代器的长度,使用不如列表索引取值灵活
      2. 一次性的,只能往后取值,不能倒着取值
  2. 查看可迭代对象与迭代器对象
from collections import Iterable,Iterator

s = 'hello'
l = [1,2,3]
t = (1,2,3)
d = {'a':1}
set1 = (1,2,3,4)
f = open('a.txt')

s.__iter__()
l.__iter__()
t.__iter__()
d.__iter__()
set1.__iter__()
f.__iter__()
                                                    #Iterable 为可迭代的
print(isinstance(s,Iterable))        #isinstance()  函数来判断一个对象是否是一个已知的类型,类似 type()。
print(isinstance(l,Iterable))
print(isinstance(t,Iterable))
print(isinstance(d,Iterable))
print(isinstance(set1,Iterable))
print(isinstance(f,Iterable))
  1. 查看是否是迭代器
print(isinstance(s,Iterator))        #Iterator 为迭代器
print(isinstance(l,Iterator))
print(isinstance(t,Iterator))
print(isinstance(d,Iterator))
print(isinstance(set1,Iterator))
print(isinstance(f,Iterator))

三. 生成器

  1. 定义:生成器就是一个函数,这个函数内包含有yield这个关键字,可以将函数变成具有序列性,返回多个值
  2. 生成器与return有何区别
    • return只能返回一次函数就彻底结束了,而yield能返回多次值
  3. yield到底干了什么事
    • yield把函数变成生成器(生成器其实就是迭代器)(yield将__next__和__iter__封装到函数内部)
    • 用return返回只能返回一次,而yield返回多次
    • 函数在暂停以及继续下一次运行时的状态是由yield保存
def test():
    print('one')
    yield 1
    print('two')
    yield 2
    print('three')
    yield 3

g = test()        #无输出,此时g为生成器,即把函数变成一个迭代器
print(g)        #<generator object test at 0x00000000027E91A8>
res = next(g)    #one        next触发生成器的执行
print(res)        #1
  1. yield具体应用
def countdown(n):
    print('start countdown')
    while n >0:
        yield n
        n -= 1
    print('done')

g= countdown(5)

print(next(g))        #start countdown    5
print(next(g))        #4
print(next(g))        #3
print(next(g))        #2
print(next(g))        #1
print(next(g))        #done    #会报错

#for循环写法
for i in g:
    print(i)

#while循环写法
while True:
    try:
        print(next(g))
    except    StopIteration:
        break
  1. 生成器应用
#惰性计算
def func():
    n = 0
    while True:
        yield n
        n += 1

f = func()
print(next(f))
  1. tail命令的最基本实现
import time
def tail(file_path):
    with open(file_path,'r') as f:
        f.seek(0,2)                    #光标移到最后
        while True:
                line = f.readline()            #读这一行
                if not line:
                        time.sleep(0.5)
                        continue
                else:
                        print line,        #print 输出光标不换行

tail('/tmp/a.txt')
  1. tail命令通过生成器实现(python2)
import time
def tail(file_path):
    with open(file_path,'r') as f:
        f.seek(0,2)                    #光标移到最后
        while True:
                line = f.readline()            #读这一行
                if not line:
                        time.sleep(0.5)
                        print '======='
                        continue
                else:
                        yield line

g = tail('/tmp/a.txt')        #函数变成一个生成器

for line in g:
        print line,
  1. grep命令通过生成器实现(python2)
import time
def tail(file_path):
    with open(file_path,'r') as f:
        f.seek(0,2)                    #光标移到最后
        while True:
                line = f.readline()            #读这一行
                if not line:
                        time.sleep(0.5)
                        continue
                else:
                        yield line

g = tail('/tmp/a.txt')

for line in g:
        if 'error' in line:
                print line,
  1. grep命令通过生成器实现且有水流概念
import time
def tail(file_path):
    with open(file_path,'r') as f:
        f.seek(0,2)                    #光标移到最后
        while True:
                line = f.readline()            #读这一行
                if not line:
                        time.sleep(0.5)
                        continue
                else:
                        yield line

def grep(pattern,lines):                #pattern 为grep所抓取的 lines为输入源
        for line in lines:
                if pattern in line:
                        print line,

g = tail('/tmp/a.txt')
grep('error',g)
  1. tail、grep命令最终版
import time
#定义阶段:定义两个生成器函数
def tail(file_path):
    with open(file_path,'r') as f:
        f.seek(0,2)                    #光标移到最后
        while True:
                line = f.readline()            #读这一行
                if not line:
                        time.sleep(0.5)
                        continue
                else:
                        yield line

def grep(pattern,lines):                #pattern 为grep所抓取的 lines为输入源
        for line in lines:
                if pattern in line:
                        yield line

#调用阶段:得到俩生成器对象
g1 = tail('/tmp/a.txt')
g2 = grep('error',g1)

#使用阶段:next触发执行g2生成器函数
for i in g2:
        print i,

四. 协程函数

  1. 吃包子
def eater(name):
    print('%s start to eat food '% name)
    food_list = []
    while True:
        food = yield food_list
        print('%s get %s, to start eat '% (name, food))
        food_list.append(food)
    print('Done')

e = eater('钢蛋')

print(next(e))
print(e.send('包子'))
print(e.send('韭菜包子'))    #send 等同于next 有返回值,但是会把后面的参数传给当前行的yield
print(e.send('馅饼'))

作业

今日总结

  1. 待整理

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

原文地址:https://www.cnblogs.com/sama/p/7825403.html