python-迭代器、生成器

迭代器

可迭代

可迭代协议:含有__iter__方法

可迭代的,一定可以被for循环

可被for循环(可迭代的)

  • 1, list
  • 2, dic
  • 3, str
  • 4, set
  • 5, tuple
  • 6, f = open()
  • 7, range()
  • 8, enumerate (枚举)
  • 迭代器
  • 生成器

 

# list
l = [1, 2, 3, 4]
for i in l:
    print('i', i)

# dic
d = {'id': 1, 'name': 'sun', 'age': 19}
for key, value in d.items():
    print(key, value)

# str
s = 'hello world'
for i in s:
    print(i)

# set
se = {1, 2, 4, 6, 6}
for i in se:
    print(i)

# tuple
t = (1, 2, 3, 4)
for i in t:
    print('t', i)

# f = open()
f = open('content.txt', 'r')
for i in f:
    print('f', i)

# range()
for i in range(1, 10):
    print('range', i)

# enumerate() 每当你需要向上计数时,每次一个数字,同时循环遍历一个迭代器, enumerate函数就会派上用场。
bank_names = [
    "工商银行",
    "农业银行",
    "中国银行",
    "建设银行",
    "招商银行",
    "浦发银行",
    "广发银行",
    "广州银行",
    "邮储银行",
    "平安银行",
    "农商银行",
    "兴业银行",
    "华夏银行",
    "交通银行",
    "光大银行",
    "中信银行",
]

banks = [{"id": i, "name": v} for i, v in enumerate(bank_names, 1)]
print(banks)

# 迭代器
# 生成器

 

迭代器

迭代器协议, 含有__iter__和__next__方法

迭代器一定可迭代, 可迭代的通过调用__iter__方法就能得到一个迭代器 

"""
迭代器协议, 含有__iter__和__next__方法
"""

# 把列表变成一个迭代器
"""
构建迭代器的时候,不像列表把所有元素一次性加载到内存,而是以一种延迟计算(lazy evaluation)方式返回元素,这正是它的优点。
比如列表含有中一千万个整数,需要占超过400M的内存,而迭代器只需要几十个字节的空间。
因为它并没有把所有元素装载到内存中,而是等到调用 next 方法时候才返回该元素(按需调用 call by need 的方式,本质上 for 循环就是不断地调用迭代器的next方法)
"""
L = [i for i in range(10)]
iterator = iter(L)
print(iterator)
for i in iterator:
    print('iterator', i)

for i in iterator:
    print('iterator xx', i)  # 没有了


# 以斐波那契数列为例实现一个迭代器
class Fib(object):
    def __init__(self, n):
        self.previous = 0
        self.current = 1
        self.n = n

    def __iter__(self):
        return self

    def __next__(self):
        if self.n > 0:
            value = self.current
            self.current = self.current + self.previous
            self.previous = value
            self.n -= 1  # this is a flag
            return value
        else:
            raise StopIteration()


f1 = Fib(10)
print([i for i in f1])

生成器

本质上就是迭代器,不过更简洁

 

"""
知道迭代器之后,就可以正式进入生成器的话题了。
普通函数用 return 返回一个值,和 Java 等其他语言是一样的,然而在 Python 中还有一种函数,用关键字 yield 来返回值,这种函数叫生成器函数,函数被调用时会返回一个生成器对象,
生成器本质上还是一个迭代器,也是用在迭代操作中,因此它有和迭代器一样的特性,唯一的区别在于实现方式上不一样,后者更加简洁
"""


# 最简单的生成器函数
def generator(n):
    yield n * 2


# 1
g = generator(2)
print(g)
print(next(g))

# 2
g = generator(5)
for i in g:
    print(i)


# 用生成器实现斐波那契数列
def fib(n):
    previous, current = 0, 1
    while n > 0:
        n -= 1
        yield current
        previous, current = current, previous + current


f = fib(10)
print([i for i in f])

# 生成器表达式
g = (x * 2 for x in range(10))
print([i for i in g])
# print(next(g))    # 取完值再取会报错

 

表现形式

生成器函数

1,只有含有yield关键字的函数就是生成器函数

,2,特点

  • 1, 调用函数之后不执行, 返回一个生成器
  • 2, 每次调用next取得一个值
  • 3, 取完最后一个, 再执行next会报错

生成器表达式

主要特征:()

g = (i for i in range(1,11))    # 生成一个生成器
for i in g:     # 通过for循环取值
    print(i)

特点

1,调用函数之后不执行,返回一个生成器

2,每次调用next取得一个值

3,取完最后一个值,再调next会报错

4,数据只能取一次,取完就没了

5,惰性运算

取值

1,for循环

g = (i for i in range(1,11))  # g是一个生成器
for i in g:                 # 通过for循环取值
    print(i)

2,__next__

g = (i for i in range(1,11))  # g是一个生成器
print(g.__next__())     # 1
print(g.__next__())     # 2
print(g.__next__())     # 3

3, send

1,send获取下一个值的效果和next效果一致

2,只是在获取下一个值的时候, 给上一个值的位置传递一个新的值

3,注意

  • 第一次使用的时候, 用next获取下一个值
  • 最后一个yield不能接收外部的值

简单例子

def generator():
    print('begin')
    ret = yield 'this is beginning'
    print('receive content', ret)
    print('end')
    yield 'b'


g = generator()
print(next(g))
b = g.send("hi, I'm sending")
print('this is should b :', b)

求移动平均值且预激活装饰器

def init_generator(func):
    """
    # 有预激活生成器作用的装饰器
    :param func:
    :return:
    """

    def inner(*args, **kwargs):
        g = func(*args, **kwargs)
        g.__next__()
        return g

    return inner



@init_generator
def generator():
    total = 0  # =0用来做初始化的
    count = 0  # =0用来做初始化的
    __avg = 0  # =0用来做初始化的
    while True:
        num = yield __avg  # num 是通过send传过来的
        total += num
        count += 1
        __avg = total / count


_avg = generator()
print(_avg.send(10))  # 10 / 1
print(_avg.send(20))  # (10 + 20) / 2
print(_avg.send(30))  # (10 + 20 + 30) / 3

4,数据类型的强转

g = (i for i in range(100))
print(g)
print(list(g))

 

posted @ 2018-08-16 18:07  孙昌恒  阅读(160)  评论(0编辑  收藏  举报