迭代器,生成器,面向过程编程思想

今日内容:

  一、迭代器

  二、生成器

  三、面向过程的编程思想

 

 

一、迭代器:

  迭代器基础:

#1.迭代是个什么概念:
#迭代器重点在迭代二字,器是工具的意思,
#迭代是一个重复的过程,每次执行重复过程就是一次迭代,并且每次迭代的结#果都是下一迭代的初始值

#有人说重复的过程不就可以用,while或者for循环来搞定么?

#while循环只是单纯的循环,因而不是迭代

#而for循环其实底层是用的迭代的方式去实现for循环的功能


2. 为什么要用迭代器
    对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器

3. 怎么用迭代器
    可迭代的对象?
        在python中,但凡内置有__iter__方法的对象,都是可迭代的对象
    迭代器对象?
        执行可迭代对象下__iter__方法得到的返回值就是一个迭代器对象
        迭代器对象内置__next__方法,

# l = ['a', 'b', 'c', 'b']
#
# iter_obj = l.__iter__()
# print (iter_obj)

        也内置__iter__方法,执行该方法得到的仍然是迭代器本身,之所以有个iter方法是为了顺应for循环的工作机制
        f=open('aa.py', rb) 文件类型本身就是一个迭代器对象
        
        注意:
        迭代器对象一定是可迭代的对象
        可迭代对象不一定是迭代器对象


总结迭代器的特点
1. 是一次性的,值取干净后就无法再次取值,除非重新得到新的迭代器对象
    不如按照索引取值的方式灵活
    值取不干净,永远无法预测迭代器的长度
2. 提供了一种不依赖索引的迭代取值方式
3. 更加的节省内存



4.迭代器的优缺点:
#优点:
  - 提供一种统一的、不依赖于索引的迭代方式
  - 惰性计算,节省内存
#缺点:
  - 无法获取长度(只有在next完毕才知道到底有几个值)
  - 一次性的,只能往后走,不能往前退

  迭代对象的使用:

 

dic={'a':1,'b':2,'c':3}
iter_dic=dic.__iter__() #得到迭代器对象,迭代器对象即有__iter__又有__next__,但是:迭代器.__iter__()得到的仍然是迭代器本身,这个是为了符合for的工作机制,for循环其实是把循环体执行__iter__转化为迭代器对象,万一循环的是一个迭代器对象呢,所以迭代器也有__iter__方法
iter_dic.__iter__() is iter_dic #True

print(iter_dic.__next__()) #等同于next(iter_dic)
print(iter_dic.__next__()) #等同于next(iter_dic)
print(iter_dic.__next__()) #等同于next(iter_dic)
# print(iter_dic.__next__()) #抛出异常StopIteration,或者说结束标志

#有了迭代器,我们就可以不依赖索引迭代取值了
dic = {'k1': 1, 'k2': 2, 'k3': 3}

iter_obj = dic.__iter__()
while True:
    try:
        print(next(iter_obj))
    except StopIteration:
        break

 

  for循环机制介绍:

#基于for循环,我们可以完全不再依赖索引去取值了
dic={'a':1,'b':2,'c':3}
for k in dic:
    print(dic[k])

#for循环的工作原理
#1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
#2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
#3: 重复过程2,直到捕捉到异常StopIteration,结束循环

二、生成器:

  生成器基本概念:

 

1. 什么是生成器
    在函数内但凡有yield关键字,在调用函数就不会执行函数体代码,得到返回值就是一个生成器对象

def func():
    print('====>first')
    yield 1
    print('====>second')
    yield 2
    print('====>third')
    yield 3
    print('====>end')

g=func()
print(g) #<generator object func at 0x0000000002184360>

 强调:生成器本身就是自定义的迭代器
g.__iter__
g.__next__
#所以生成器就是迭代器,因此可以这么取值
res=next(g)
print(res)

    next(g)的过程:
        会触发生成器g所对应的函数的执行,知道遇到yield才停下来,然后把yield后的返回值当做本次next操作结果,如果没有返回值默认返回None

2. 为何要用生成器:
    学习生成器是为了掌握一种自定义迭代器的方式


3. 总结yield:
    1. yield提供一种自定义迭代器的方式
    2. 与return对比,都能返回值,都能返回多个值,都没有类型限制,而return只能返回一次值,yield可以返回多次值,(yield可以帮我们保存函数的执行状态)


4. yield关键字表达式形式的应用
    x = yield

  生成器练习:

1.自定义函数模拟range(1.7.2)

2.模拟管道,实现功能:tailf access.log | grep '404'

#题目一:
def my_range(start,stop,step=1):
    while start < stop:
        yield start
        start+=step

#执行函数得到生成器,本质就是迭代器
obj=my_range(1,7,2) #1  3  5
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj)) #StopIteration

#应用于for循环
for i in my_range(1,7,2):
    print(i)

#题目二
import time
def tail(filepath):
    with open(filepath,'rb') as f:
        f.seek(0,2)
        while True:
            line=f.readline()
            if line:
                yield line
            else:
                time.sleep(0.2)

def grep(pattern,lines):
    for line in lines:
        line=line.decode('utf-8')
        if pattern in line:
            yield line

for line in grep('404',tail('access.log')):
    print(line,end='')

#测试
with open('access.log','a',encoding='utf-8') as f:
    f.write('出错啦404\n')

  send方法,实现协程函数:

def dog(name):
    print('狗[%s]准备开吃了' %name)
    food_list = []
    while True:
        food = yield food_list# food=yield='骨头'
        print('狗哥[%s]吃了:%s' %(name, food))
        food_list.append(food)
#       print (food_list)


dg = dog('alex')

next(dg)
#print(dg1)
#send方法有两个功能:
#1. 为当前暂停位置的yield赋值
#2. 与next的效果一样
#强调:针对表达式形式的yield,在使用生成器时必先send(None),相当于先完成一个初始化操作


dg2 = dg.send('骨头')
print(dg2)
dg3 = next(dg)

print(dg3)
 
 

  生成器表达式:

 

'''
生成器表达式
三元表达式外面换位()小括号,并不是元组的生成式,生成的是一个生成器(迭代器对象)
'''

names = ['gr', 'zc', 'xx', 'kk']

g = (name.upper() for name in names if name != 'gr')

print(g) #打印出一个生成器对象内存地址

 

三、面向过程的编程思想

#1、首先强调:面向过程编程绝对不是用函数编程这么简单,面向过程是一种编程思路、思想,而编程思路是不依赖于具体的语言或语法的。言外之意是即使我们不依赖于函数,也可以基于面向过程的思想编写程序

#2、定义
面向过程的核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么

基于面向过程设计程序就好比在设计一条流水线,是一种机械式的思维方式

#3、优点:复杂的问题流程化,进而简单化

#4、缺点:可扩展性差,修改流水线的任意一个阶段,都会牵一发而动全身

#5、应用:扩展性要求不高的场景,典型案例如linux内核,git,httpd

#6、举例
流水线1:
用户输入用户名、密码--->用户验证--->欢迎界面

流水线2:
用户输入sql--->sql解析--->执行功能

 

ps: 函数的参数传入,是函数接收了这个参数,而函数return的返回值,是函数给出的结果,面向过程的思路就是把程序的执行当做一串首尾相连的功能,该功能可以是函数的形式,然后一个函数return值,另个一个函数接收这个值,然后数据处理后又return一个值,下一个函数又接收处理。。。。以此类推

 

 

 

posted @ 2018-08-06 21:53  V小高  阅读(83)  评论(0)    收藏  举报