Python函数之三:迭代器和生成器

Python函数之三:迭代器和生成器

一、函数名的运用

函数名是一个特殊的变量,他除了具有变量的功能,还有最主要一个特点就是加上() 就执行,其实他还有一个学名叫第一类对象。

1、指向内存地址
def func():
    print('这是一个函数')
print(func)#<function func at 0x000002B9AC36D1E0>

函数名指向了内存地址:0x000002B9AC36D1E0

2、当做变量传递
def func():
    print('这是一个函数')
a = func
print(a is func)#True

函数名当做变量赋值给了a变量,他们指向同一个内存地址

3、当做容器类的元素

用容器类元素:

a = "in func1: 嘻嘻"
b = "in func2: 哈哈"
c = "in func3: 咯咯"
d = "in func4: 吱吱"
lst = [a, b, c, d]
for i in lst:
    print(i)

用函数名:

def func1():
    print("in func1: 嘻嘻")
def func2():
    print("in func2: 哈哈")
def func3():
    print("in func3: 咯咯")
def func4():
    print("in func4: 吱吱")
lst = [func1, func2, func3, func4]
for i in lst:
    i()
4、当做函数的参数和返回值

前文的文章总结过,即:高阶函数

二、f-strings格式化输出

f-strings 是python3.6开始加入标准库的格式化输出新的写法,这个格式化输出比之前的%s 或者 format 效率高并且更加简化

1、结构

他的结构就是F(f)+ str的形式,在字符串中想替换的位置用{}展位,与format类似,但是用在字符串后面写入替换的内容,而他可以直接识别。

name = '晴朗'
age = 18
sex = '男'
print(f'我叫{name},今年{age}岁,我是{sex}生!')
# 我叫晴朗,今年18岁,我是男生!
2、使用方法
大括号{}内可以插入任意表达式:
#整数
print(f'{3 * 8}')  # 24

#字符串
name = 'abcde'
print(f"全部大写:{name.upper()}")  # 全部大写:ABCDE

# 字典
person = {'name': '晴朗', 'age': 18}
msg = f"I am {person['name']}, age {person['age']}"
print(msg)  # I am 晴朗, age 18

# 列表
l1 = ['晴朗', 18]
msg = f'姓名:{l1[0]},年龄:{l1[1]}.'
print(msg)  # 姓名:晴朗,年龄:18.

#函数
def sum(a, b):
    return a + b
msg = f'3和5的和是:{sum(3, 5)}'
print(msg)#3和5的和是:8

三、迭代器

1、可迭代对象

在python中,但凡内部含有__iter__方法的对象,都是可迭代对象。
例如:

st = 'abcde'
li = [1, 2, 3]
tu = (1, 5, 9)
m = 55
print('__iter__' in dir(st))#True
print('__iter__' in dir(li))#True
print('__iter__' in dir(tu))#True
print('__iter__' in dir(m))#False

结论:字符串、列表、元组等都是可迭代对象,而整数不是可迭代对象

2、迭代器的简介

1、迭代是Python最强大的功能之一,是访问集合元素的一种方式。
2、迭代器是一个可以记住遍历的位置的对象。
3、迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
4、迭代器有两个基本的方法:iter() 和 next()。

li = [1, 2, 3, 8, 12]
it = iter(li)#创建迭代器对象
for i in it:
    print(i)
2、判断对象是否迭代器

通过判断iter() 和 next()方法是否属于被判断对象方法列表中,从而判断对象是否迭代器

if ('__iter__' in dir(判断对象)) and ('__next__' in dir(判断对象)):
    print('判断对象是迭代器')
else:
    print('判断对象不是迭代器')
li = [1, 2, 3, 8, 12]
print('__iter__' in dir(li))#True
print('__next__' in dir(li))#False

结论:li不是迭代器,是迭代对象

3、迭代对象转换成迭代对象

使用iter() 方法直接转换:

l1 = [1, 2, 3, 4, 5, 6]
obj = iter(l1)
if ('__iter__' in dir(obj)) and ('__next__' in dir(obj)):
    print('判断对象是迭代器')
else:
    print('判断对象不是迭代器')
#判断对象是迭代器
4、迭代器的取值

迭代器是利用__next__()进行取值:

l1 = [1, 2, 3, 4, 5, 6]
obj = iter(l1)
print(obj.__next__())#1
print(obj.__next__())#2
print(obj.__next__())#3
print(obj.__next__())#4
print(obj.__next__())#5
5、 while模拟for的循环原理

循环原理:
1.先调用in后对象的__iter__方法,将其变成一个迭代器对象
2.调用next(迭代器),将得到的返回值赋值给变量名
3.循环往复直到next(迭代器)抛出异常,for会自动捕捉异常然后结束循环

6、迭代器的优缺点
1、优点

1、提供了一种通用不依赖索引的迭代取值方式
2、同一时刻在内存中只存在一个值,更节省内存

2、缺点

1、取值不如按照索引的方式灵活,不能取指定的某一个值,只能往后取,不能往前去
2、无法预测迭代器的长度

三、生成器

1、生成器简介

1、生成器就是一种自定义的迭代器,本质为迭代器
2、在 Python 中,使用了 yield 的函数被称为生成器(generator)
3、跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器
4、在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行
5、调用一个生成器函数,返回的是一个迭代器对象

def func():
    print(1)
    yield 2
res = func()
print(res)#<generator object func at 0x000002597F606B10>
print(res.__next__())#1 2

以上代码中,func就是一个生成器,调用func()时,获取的生成器对象(其实就是一个迭代器),通过next方法取值

2、创建生成器
2.1生成器的结构
def func():
    ...
    yield ...
    ...
    yield ...
    ...
2.2 yield与return的区别

1、yield 的作用:
1.1、yield提供了一种自定义迭代器的解决方案
1.2、yield可以保存函数的暂停的状态
2、两者区别:
相同点:都可以返回值,值得类型与个数没有限制
不同点:yield可以返回多次值,而return只能返回一次值函数就会结束;yield可以有多个,而return一般只有一个

2.3 生成器的优点

例:假设要小明向自行车厂定制了一千辆自行车给员工发放福利,自行车厂boss一口气全部生产出来了,后来小明只发放了200辆

一般代码实现发放:

for i in range(1, 1001):
    print(i)

迭代器实现发放:

def func():
    for i in range(1, 1001):
        yield '自行车'+str(i)

by = func()
for i in range(1, 201):
    print(next(by))

通过以上两种方式得出结论:
1、第一种是直接把自行车全部生产出来,占用内存。
2、第二种是发放一辆,生产一辆,非常的节省内存,而且还可以保留上次的发放位置。

2.4 send方法:主要是用于外部与生成器对象的交互
def func1():  # 生成器函数
    x = yield 1
    yield x
    yield x

res = func1()
print(next(res))#1
m = res.send('888')
print(m)#888
print(next(res))#888

send与next的异同:
相同点:send 和 next()都可以让生成器对应的yield向下执行一次,都可以获取到yield生成的值。
不同点: 第一次获取yield值只能用next不能用send(可以用send(None)), send可以给上一个yield置传递值。

2.5 yield from

yield会将可迭代对象当做一个整体传出来,而yield from则是将可迭代对象中的每一个元素传出来

li = [1, 2, 5, 6, 4, 3, 9]
def func1():
    yield li

def func2():
    yield from li

res1 = func1()
print(next(res1))#[1, 2, 5, 6, 4, 3, 9]

res2 = func2()
print(next(res2))#1
print(next(res2))#2
print(next(res2))#5
print(next(res2))#6
print(next(res2))#4

注意:如果要访问两个可迭代对象的数据,则可以使用两个yield from

li = [1, 2, 5, 6, 4, 3, 9]
tu = ('a', 'b', 'm')
def func2():
    yield from li
    yield from tu

res2 = func2()
for i in res2:
    print(i)
#1, 2, 5, 6, 4, 3, 9, a, b, m
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值