一,生成器

2.1初始生成器

我们知道的迭代器有两种:一种是调用方法直接返回的,一种是可迭代对象通过执行iter方法得到的,迭代器有的好处是可以节省内存。

如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器。

 

Python中提供的生成器:

1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行

2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

 

生成器Generator:

  本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)

  特点:惰性运算,开发者自定义

2.2 生成器函数

一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

import time
def genrator_fun1():
    a = 1
    print('现在定义了a变量')
    yield a
    b = 2
    print('现在又定义了b变量')
    yield b

g1 = genrator_fun1()
print('g1 : ',g1)       #打印g1可以发现g1就是一个生成器
print('-'*20)   #我是华丽的分割线
print(next(g1))
time.sleep(1)   #sleep一秒看清执行过程
print(next(g1))
初识生成器函数

生成器有什么好处呢?就是不会一下子在内存中生成太多数据

假如我想让工厂给学生做校服,生产2000000件衣服,我和工厂一说,工厂应该是先答应下来,然后再去生产,我可以一件一件的要,也可以根据学生一批一批的找工厂拿。
而不能是一说要生产2000000件衣服,工厂就先去做生产2000000件衣服,等回来做好了,学生都毕业了。。。

def produce():
    """生产衣服"""
    for i in range(2000000):
        yield "生产了第%s件衣服"%i

product_g = produce()
print(product_g.__next__()) #要一件衣服
print(product_g.__next__()) #再要一件衣服
print(product_g.__next__()) #再要一件衣服
num = 0
for i in product_g:         #要一批衣服,比如5件
    print(i)
    num +=1
    if num == 5:
        break
View Code
# 生成器:就是自己python用代码写的迭代器,生成器的本质就是迭代器。
l1 = [1,2,3]
iter1 = iter(l1)
# 用以下两种方式构建一个生成器:
# 1,通过生成器函数。
# 2,生成器表达式。

# 生成器函数:
    # 函数
def func1(x):
    x += 1
    return x
func1(5) #函数的执行命令,并且接受函数的返回值。
print(func1(5))

   # 生成器函数
def func1(x):
    x += 1
    print(1111)
    print(1111)
    print(1111)
    print(1111)
    print(1111)
    print(1111)
    yield x
    x +=2
    print(2222)
    yield 'alex'

    x +=3

g_obj = func1(5)  # 生成器函数对象
# print(g_obj)  # <generator object func1 at 0x0000025E5D618780>
print(g_obj.__next__())
print(g_obj.__next__())
#一个next 对应一个 yield
#yield 将值返回给  生成器对象.__next__()

#yield return
#return 结束函数,给函数的执行者返回值
#yield 不会结束函数,一个next对应一个yield,给  生成器对象.__next__() 返回值。


# 生成器函数 vs 迭代器
# 区别1:自定制的区别
# l1 = [1,2,3,4,5]
# l1.__iter__()

# def func1(x):
#     x += 1
#     yield x
#     x += 3
#     yield x
#     x += 5
#     yield x
# g1 = func1(5)
# print(g1.__next__())
# print(g1.__next__())
# print(g1.__next__())
# 区别1:内存级别的区别。
# 迭代器是需要可迭代对象进行转化。可迭代对象非常占内存。
# 生成器直接创建,不需要转化,从本质就节省内存。
# def func1():
#     for i in range(1000000):
#         yield i
# g1 = func1()
# for i in range(50):
#     print(g1.__next__())
课堂笔记

 

2.3 send

def generator():
    print(123)
    content = yield 1
    print('=======',content)
    print(456)
    yield2

g = generator()
ret = g.__next__()
print('***',ret)
ret = g.send('hello')   #send的效果和next一样
print('***',ret)

#send 获取下一个值的效果和next基本一致
#只是在获取下一个值的时候,给上一yield的位置传递一个数据
#使用send的注意事项
    # 第一次使用生成器的时候 是用next获取下一个值
    # 最后一个yield不能接受外部的值
# send 与 next

def func1():
    # print(1)
    count = yield 6
    print(count)
    # print(2)
    count1 = yield 7
    print(count1)
    # print(3)
    yield 8

# g = func1()
# next(g)
# # g.send('alex')
# g.send('alex')
# g.send('太白')
# g.send('太白')


# send 与next一样,也是对生成器取值(执行一个yield)的方法。
# send 可以给上一个yield 传值。
# 第一次取值永远都是next。
# 最后一个yield 永远也得不到send传的值。


# def cloth1(n):
#     for i in range(n+1):
#         print('衣服%s号' % i)
# cloth1(100000)
def cloth2(n):
    for i in range(1,n+1):
        yield '衣服%s号' % i
g = cloth2(10000)
for i in range(50):
    print(g.__next__())
for i in range(50):
    print(g.__next__())
send 与next 课堂笔记

 

三,列表推导式和生成器表达式

l = [i for i in range(10)]
print(l)
l1 = ['选项%s'%i for i in range(10)]
print(l1)

1.把列表解析的[]换成()得到的就是生成器表达式

2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:

sum(x ** 2 for x in range(4))
# l1 = []
# for num in range(1,101):
#     l1.append(num)
# print(l1)
# 列表推导式:一行代码几乎搞定你需要的任何的列表。
    # 循环模式  [变量(加工后的变量) for 变量 in iterable]
# l = [i for i in range(1,101)]
# print(l)
# l2 = ['python%s期' % i for i in range(1,16)]
# print(l2)
# print([i*i for i in range(1,11)])
    # 筛选模式 [变量(加工后的变量) for 变量 in iterable if 条件]
# l3 = [i for i in range(1,31) if i % 2 == 0]
# print(l3)
# print([i for i in range(1,31) if i % 3 == 0])
# print([i**2 for i in range(1,31) if i % 3 == 0])
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
print([j for i in names for j in i if j.count('e') == 2])

# 列表推导式
# 优点:一行解决,方便。
# 缺点:容易着迷,不易排错,不能超过三次循环。
# 列表推导式不能解决所有列表的问题,所以不要太刻意用。

# 生成器表达式:将列表推导式的 []  换成() 即可。
# g = (i for i in range(100000000000))
# print(g)
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())
#
# mcase = {'a': 10, 'b': 34}
# mcase_frequency = {mcase[k]: k for k in mcase}
# print(mcase_frequency)

# squared = {x**2 for x in [1, -1, 2]}
# print(squared)
列表推导式,生成器表达式

 

 

各种推导式玩法 

推导式套路

之前我们已经学习了最简单的列表推导式和生成器表达式。但是除此之外,其实还有字典推导式、集合推导式等等。

下面是一个以列表推导式为例的推导式详细格式,同样适用于其他推导式。

variable = [out_exp_res for out_exp in input_list if out_exp == 2]
  out_exp_res:  列表生成元素表达式,可以是有返回值的函数。
  for out_exp in input_list:  迭代input_list将out_exp传入out_exp_res表达式中。
  if out_exp == 2:  根据条件过滤哪些值可以。

列表推导式

例一:30以内所有能被3整除的数

multiples = [i for i in range(30) if i % 3 is 0]
print(multiples)
# Output: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
View Code

例二:30以内所有能被3整除的数的平方

 

def squared(x):
    return x*x
multiples = [squared(i) for i in range(30) if i % 3 is 0]
print(multiples)
View Code

例三:找到嵌套列表中名字含有两个‘e’的所有名字

 

names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]

print([name for lst in names for name in lst if name.count('e') >= 2])  # 注意遍历顺序,这是实现的关键
View Code

字典推导式

例一:将一个字典的key和value对调

mcase = {'a': 10, 'b': 34}
mcase_frequency = {mcase[k]: k for k in mcase}
print(mcase_frequency)
View Code

例二:合并大小写对应的value值,将k统一成小写

 

mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()}
print(mcase_frequency)
View Code

集合推导式

例:计算列表中每个值的平方,自带去重功能


squared = {x**2 for x in [1, -1, 2]}
print(squared)
# Output: set([1, 4])
View Code

练习题:

例1:  过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母

例2:  求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元祖列表

例3:  求M中3,6,9组成的列表M = [[1,2,3],[4,5,6],[7,8,9]]

 

    生成器:自己用python代码写的,本质上迭代器。
        生成器函数。
            yield
            yieldreturn 区别:
                return 结束函数,返回给函数的执行者返回值。
                yield 不会结束函数,会将值返回给生成器对象。
            next 与 send 区别。
                共同点:都可以从生成器(迭代器)里取值。
                不同点:
                    send给上一个yield发送一个值。
                    第一个一定要用next,因为他上一个没有yield ,会报错。最后一个yield 永远得不到send值。
        生成器表达式。
        列表推导式。
            两种模式:
                1,循环模式。[变量(加工后的变量) for 变量 in iterable]
                2,筛选模式。[变量(加工后的变量) for 变量 in iterable if 条件]

        生成器表达式。
            列表推导式 与生成器表达式的不同。
                1,形式上不同 []      ()
                2,内存级别不同。生成器表达式非常节省内存。
内容总结

 

#
# Day12作业默写
# 1,整理今天的博客,写课上代码,整理流程图。
# 2,用列表推导式做下列小题
# (1)    过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母
# (2)    求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的 元祖 列表
# l1 = [(),(),....]
# print([(2*x,2*x+1) for x in range(0,3)])
# print([(x,y) for x in range(0,6) if x % 2 == 0 for y in range(0,6) if y % 2 == 1])
# print([(x,y) for x in range(0,5,2)for y in range(1,6,2)])
# (3)    求M中3,6,9组成的列表M = [[1,2,3],[4,5,6],[7,8,9]]
# M = [[1,2,3],[4,5,6],[7,8,9]]
# print([x[-1] for x in M])
# print([[x-2,x-1,x] for x in [3,6,9]])

# (4)    求出50以内能被3整除的数的平方,并放入到一个列表中。
# (5)    构建一个列表:
# ['python1期', 'python2期', 'python3期', 'python4期', 'python6期', 'python7期', 'python8期', 'python9期', 'python10期']
# (6)    构建一个列表:[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
# (7)    构建一个列表:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# (8)    有一个列表l1 = ['alex', 'WuSir', '老男孩', '太白']
# 将其构造成这种列表['alex0', 'WuSir1', '老男孩2', '太白3']
# (9)有以下数据类型:
x = {
    'name':'alex',
    'Values':[{'timestamp':1517991992.94,
         'values':100,},
        {'timestamp': 1517992000.94,
        'values': 200,},
        {'timestamp': 1517992014.94,
         'values': 300,},
        {'timestamp': 1517992744.94,
         'values': 350},
        {'timestamp': 1517992800.94,
         'values': 280}
        ],}
# 将上面的数据通过列表推导式转换成下面的类型:
# [[1517991992.94, 100], [1517992000.94, 200], [1517992014.94, 300], [1517992744.94, 350], [1517992800.94, 280]]
# print([[i['timestamp'],i['values']] for i in x['Values']])


# 3,求结果:
# v = [i % 2 for i in range(10)]
# print(v)
#
#
# 4,求结果:
# v = (i % 2 for i in range(10))
# print(v)
#
# 5,求结果:
#
# def func1():
#     for i in range(5):
#         print(i)
# print(i)
#
#
#
作业讲解

 

# l1 = []
# for i in range(1,101):
#     l1.append(i)
#
# print(l1)
# l2 = ['python%s期'%i for i in range(1,16)]
# print(l2)
# l3 = [i*i for i in range(1,11)]
# print(l3)
#例一:30以内所有能被3整除的数
# l4 = [i for i in range(1,31) if i % 3 ==0]
# print(l4)
#例二:30以内所有能被3整除的数的平方
# l5 = [i**2 for i in range(1,31) if i % 3  == 0 ]
# print(l5)

# #例三:找到嵌套列表中名字含有两个‘e’的所有名字
# names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
#          ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
# l6 = [j for i in names for j in i if j.count('e') ==2 ]
# print(l6)
#
#

#
# Day12作业默写
# 1,整理今天的博客,写课上代码,整理流程图。
# 2,用列表推导式做下列小题
# (1)    过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母
# (2)    求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的 元祖 列表

# l1 = ['abcd','ab','bded','a','c','eee']
# ret = [i.upper() for i in l1 if len(i) >= 3]
# print(ret)
#
# x = [i for i in range(0,6) if i % 2 ==0]
# y = [i for i in range(0,6) if i % 2 ==1]
# print(x)
# print(y)
# l2 = [(xx,yy) for xx in x for yy in y]
# print(l2)
#
# l3 = [(yy,xx) for xx in x for yy in y]
# print(l3)



# l1 = [(),(),....]
# print([(2*x,2*x+1) for x in range(0,3)])
# print([(x,y) for x in range(0,6) if x % 2 == 0 for y in range(0,6) if y % 2 == 1])
# print([(x,y) for x in range(0,5,2)for y in range(1,6,2)])





# (3)    求M中3,6,9组成的列表M = [[1,2,3],[4,5,6],[7,8,9]]
M = [[1,2,3],[4,5,6],[7,8,9]]
#print([[x-2,x-1,x] for x in [3,6,9]])



# M = [[1,2,3],[4,5,6],[7,8,9]]
# print([x[-1] for x in M])
# print([[x-2,x-1,x] for x in [3,6,9]])

# (4)    求出50以内能被3整除的数的平方,并放入到一个列表中。
# ret = [x**2 for x in range(0,51) if x % 3 ==0]
# print(ret)
# (5)    构建一个列表:
# ['python1期', 'python2期', 'python3期', 'python4期', 'python6期', 'python7期', 'python8期', 'python9期', 'python10期']

# (6)    构建一个列表:[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
# print([(x,x+1) for x in range(0,6)])

# (7)    构建一个列表:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
#print([x*2 for x in range(0,10)])

# (8)    有一个列表l1 = ['alex', 'WuSir', '老男孩', '太白']
# 将其构造成这种列表['alex0', 'WuSir1', '老男孩2', '太白3']
l1 = ['alex', 'WuSir', '老男孩', '太白']

#print([i+str(l1.index(i)) for i in l1])
# (9)有以下数据类型:
x = {
    'name':'alex',
    'Values':[{'timestamp':1517991992.94,
         'values':100,},
        {'timestamp': 1517992000.94,
        'values': 200,},
        {'timestamp': 1517992014.94,
         'values': 300,},
        {'timestamp': 1517992744.94,
         'values': 350},
        {'timestamp': 1517992800.94,
         'values': 280}
        ],}
# 将上面的数据通过列表推导式转换成下面的类型:
# [[1517991992.94, 100], [1517992000.94, 200], [1517992014.94, 300], [1517992744.94, 350], [1517992800.94, 280]]
#print([[xx['timestamp'],xx['values']] for xx in x['Values']])






# print([[i['timestamp'],i['values']] for i in x['Values']])


# 3,求结果:
v = [i % 2 for i in range(10)]
print(v)
#
#
# 4,求结果:
v = (i % 2 for i in range(10))
print(v)
#
# 5,求结果:
#
def func1():
    for i in range(5):
        print(i)
print(i)
#
#
#
作业答案

 

 posted on 2022-03-20 19:01  编程之路任重道远  阅读(63)  评论(0)    收藏  举报