文章目录

  • 函数进阶(2)
    • 可迭代对象
      • 什么是可迭代对象
      • 可迭代对象的意义
      • 可迭代对象的使用
    • 迭代器
      • 什么是迭代器
        • 迭代器的优势
        • 迭代器的劣势
      • 怎么使用迭代器
    • 生成器
      • 什么是生成器
      • 怎么使用生成器
        • 以函数的形式使用生成器
        • 生成器表达式
    • for循环的原理介绍

函数进阶(2)

这是函数进阶2.0版本,
将会介绍的就是关于可迭代对象、迭代器、生成器三个概念以及使用方式,
只有将这三者弄明白我们才能够加深对序列的了解。

可迭代对象

在前文之中我们讲到了很多的可迭代对象,
比如说使用zipfiltermap这三个函数,我们将会得到的分别是压缩对象、过滤器对象以及映射对象,但是这三者都是可迭器,

Tip:刚兴趣的小伙伴可以看看我上一篇文章的内容

下方链接直达
函数进阶(1)

这所有的一切都指向迭代器,为了弄清楚什么是迭代器
我们需要先解锁前置知识,什么是可迭代对象?

什么是可迭代对象

先上教科书定义:

可迭代对象就是一群拥有 __iter__()方法的类实例对象

以上就是可迭代对象的定义,over。

没错定义就是这么言简意赅,但是类实例又是什么鬼呢?
果然,要解释一个问题,就会引出另外一个问题,可真麻烦呢。
那么就让我娓娓道来:

Python 是一个面向对象的编程语言,
而面向对象的语言最大的特点就是 —— 类,
类中被封装了大量的属性以及方法,但是却无法直接使用,
需要创建一个实例化的类对象,这就被我们称作为类实例啦

OK,继续回到原本的话题,既然知道了拥有__iter__()方法的就是可迭代对象,
那么究竟有哪些类实例拥有这个方法呢?
我们众所周知的序列都是可迭代对象,但可迭代对象远远不止于此,这一点我将再后续深入浅出地说明,
但首先我们要知道该如何查看这个类拥有__iter__方法

# 我们使用__dict__就可以查看类对象是否拥有这个方法,
# 如果类对象本身就拥有__iter__方法的话,那么其实例化后的类实例也是拥有的
list.__dict__{'__new__': <built-in method __new__ of type object at 0x00007FFA921F7610>, '__repr__': <slot wrapper '__repr__' of 'list' objects>, '__hash__': None, '__getattribute__': <slot wrapper '__getattribute__' of 'list' objects>, '__lt__': <slot wrapper '__lt__' of 'list' objects>, '__le__': <slot wrapper '__le__' of 'list' objects>, '__eq__': <slot wrapper '__eq__' of 'list' objects>, '__ne__': <slot wrapper '__ne__' of 'list' objects>
'__iter__': <slot wrapper '__iter__' of 'list' objects>.....(省略N多属性、方法)

可迭代对象的意义

在阐述意义之前,我们必须要提出一个问题,那就是for循环的原理是怎样的?
让我们抛弃for循环,使用while实现跟他一样的效果;

list_1 = [1,3,5,7,9]
for element in list_1:print(element)
# 这将会依次得到 1 , 3 , 5 , 7 , 9count = 0                       # 定义一个计数器
length = len(list_1)
while count <= length:print(list_1[count])count += 1
# 这将会依次得到 1 , 3 , 5 , 7 , 9

我们使用while循环达到了跟for循环同样的功能,
但是代码却多了很多行,
而且最为重要的一点是,我们是通过索引来访问列表中的元素,

(集合小声逼逼:我是无序序列,我不配有索引)

那么如果我们需要依次遍历出字典的键该怎么办呢?
for循环能够轻易实现,可是对于用while循环却十分困难。

因此,Python提供了一个统一的方法 —— 可迭代对象,

这提供了巨大的便捷性,让我们不再受到索引的限制,
可以随心所欲地对可迭代对象进行取值。

可迭代对象的使用

接下来就要介绍一下可迭代对象的使用了,

dict_1 = {'Jonasen': 'Jostar', 'Joseph': 'Jostar', 'Kujo': 'Jotaro'}
# 这是一个可迭代对象,接下来我们要让其变成迭代器
iter_dict = dict_1.__iter__()print(iter_dict)
<dict_keyiterator object at 0x00000204EC58E840>

OK,这样就完成了迭代器的转换,
是不是异常简单,但是如果仅仅只是这样的话我们只完成了迭代器而已,

dict_1 = {'Jonasen': 'Jostar', 'Joseph': 'Jostar', 'Kujo': 'Jotaro'}
iter_dict = dict_1.__iter__()# 更新我们的代码
print(iter_dict.__next__())             # 这将会取出第一个键, Jonasen
print(iter_dict.__next__())             # Joseph
print(iter_dict.__next__())             # Kujo
print(iter_dict.__next__())             # 报错,StopIteration'先将拥有__iter__()方法的可迭代对象转换成迭代器,然后再使用__next__()不断迭代'
'如果超出超过原本元素的数量,则会报错 StopIteration '

迭代器

什么是迭代器

迭代器这个概念在上文之中其实就已经完成了介绍了,

迭代器就是可迭代对象使用__iter__()转换而来的对象,
并且拥有__next__()的方法,能够让我们不断进行迭代

迭代器的优势

1)不需要使用索引就能够不断进行重复的取值操作;
2)因为迭代器采用的惰性计算的原理,因此占用内存极小;

惰性计算
迭代器本身是一个数据流,同一时间只会保存一个数值,正因为这种储存方式,即使原本的
列表拥有的元素多达成百上千个,在转换成迭代器对象后其本身只会保存一个数值,并且在
使用__next__()就会丢弃原来的,使用下一个(迭代)。

迭代器的劣势

1)因为惰性计算同一时间只会保存一个值的原因,迭代器只能够依次取值,并且同时无法
回溯到上一个值;
2)无法测量迭代器的长度,除非将所有元素遍历一遍,否则我们无法知悉长度(因为迭代器不支持使用len()

怎么使用迭代器

接下来继续介绍迭代器的使用方式,
什么?
你认为就介绍完了?
哦,那我只能说你以后都必须在使用迭代器和可迭代对象的时候总会比别人多敲8个下划线。

老规矩,让Python小姐自己告诉我们,__iter__的原理是怎样的。

help(list.__iter__)# 你会得到如下的信息
'''
__iter__(self, /)Implement iter(self).     ===>  中文: 对自己使用iter()函数
'''

原来所谓的__iter__()只不过是对自己使用函数iter()
等于说,每当我们使用 list.__iter__()的时候,其实跟iter(list)效果是一样的!

(如果有兴趣的话还可以使用help(iter),让Python自己告诉你iter函数)

那么接下里的__next__()其实也是一样的,
有一个名为next()的函数……

生成器

OK,接下来就是全新的东西 —— 生成器。

什么是生成器

生成器:
由我们自己定义的迭代器

没错,就如此简洁,
生成器其实就是有我们自己定义的迭代器,

前文中我们介绍了使用iter()或者__iter__()将可迭代对象转化成迭代器,
而现在我们要自己编写一个迭代器(我们称为生成器)

怎么使用生成器

以函数的形式使用生成器

def new_range(start:int,end:int,step=3):while end >= start:yield endend -= stepyield '运行结束'
generator = new_range(1,9)             # 初始化生成器
print(next(generator))                  # 9
print(next(generator))                  # 6
print(next(generator))                  # 3
print(next(generator))                  # 运行结束

当函数与yield结合使用的时候,就达到了现在这种效果,
关于yiled需要注意的是以下几点:

1)使用了yield的函数,必须要进行初始化,即使这个函数不需要任何参数;
2)yield在函数中的作用效果与return类似,当执行到其的时候会给出一个返回值,但后续的代码会暂时挂起(return是直接终止后续代码的执行);
3)yield可以用于接收外部输入;

接下来就介绍一下yield该如何接收外部输入,

def power(num):while True:x = yieldprint(x**num)power_2 = power(2)
power_2.send(None)                  # 初始化函数,相当于next(power_2),让其执行到yiled等待接收参数
power_2.send(2)                     # 将 2 赋值给 x , 相当于 x = 2
power_2.send(3)                     # 打印输出后,重新执行到yield,接收参数3

以上就实现了如何接收外部的输入,
但是为了完成这个,我们必须要注意以下几点:

1)必须使用循环,否则的话接收一个参数后就会报错
2)不可在循环中使用return,否则的话会终止整个循环

让我来用代码示范一遍即可,

def power(num):x = yieldprint(x ** num)pow_2 = power(2)
next(pow_2)
pow_2.send(3)'''
9
StopIteration
'''

先是输出了一个9,然后就给出StopIteration的错误,
因为使用了pow_2.send()这个方法后,函数会自动去寻找到下一个yiel
而不使用循环,则会给出一个停止迭代的报错。

def power(num):while True:x = yieldreturn x**numpow_2 = power(2)
next(pow_2)
pow_2.send(3)'''
StopIteration: 9
'''

有了返回值也是会破坏整个while循环,
当使用pow_2.send()后执行到了return便给出了一个停止循环的错误。

生成器表达式

生成器表达式其实就是列表解析,
感兴趣的朋友可以直接戳下方链接跳转到我以前的文章,详细了解。
Python — 列表解析

generator = ( i for i in range(5))
print(generator)
# <generator object <genexpr> at 0x0000026D4FD75E70>generator = [i for i in range(5)]
print(generator)
# [0, 1, 2, 3, 4]

当使用列表解析的时候需要格外注意的就是该使用小括号还是中括号,
因为这两者是截然不同的。

for循环的原理介绍

在完成了可迭代对象、迭代器、生成器的介绍之后,
就十分有必要介绍一下for循环的原理,
因为for循环其实就是iter()next()while以及try……except的组合使用

dict_1 = {'Jonasen': 'Jostar', 'Joseph': 'Jostar', 'Kujo': 'Jotaro'}iter_dict = iter(dict_1)
while True:try:print(next(iter_dict))except StopIteration:break

步骤拆解一下

1)将可迭代对象转换成为一个迭代器
2)放入while循环进行循环打印,并且不断调用next()
3)使用异常捕获,当检测到StopIteration的时候就停止整个循环

以上就是本篇文章的所有内容,
而最后一篇函数进阶将会介绍以下递归这个重要的编程方法。

Python — 函数进阶(2)相关推荐

  1. python 函数进阶_Python学习入门基础:一篇文章搞定函数基础、函数进阶

    一.函数基础函数的快速体验 函数的基本使用 函数的参数 函数的返回值 函数的嵌套调用 在模块中定义函数私信小编001即可获取Python学习资料01. 函数的快速体验 1.1 快速体验 所谓函数,就是 ...

  2. 好好学python·函数进阶(递归函数,回调函数,闭包函数,匿名函数,迭代器)

    函数进阶 递归函数 回调函数 闭包函数 特点 匿名函数 lambda 表达式 迭代器 iter() next() 迭代器的取值方案 迭代器取值特点,取一个少一个,直到都取完,最后再获取就会报错 检测迭 ...

  3. Python函数进阶(11)

    函数进阶 函数参数类型 不可变数据类型和可变数据类型自加的区别 1. 判断gl_num和gl_list的值 命名空间 作用域 全局变量和局部变量 global 和nonlocal关键字 内置函数 1. ...

  4. python函数进阶小结_Python-进阶-functools模块小结

    文档 地址 functools.partial 作用: functools.partial 通过包装手法,允许我们 "重新定义" 函数签名 用一些默认参数包装一个可调用对象,返回结 ...

  5. python函数进阶小结_python之函数进阶

    1. 今日内容 1.1 函数的参数 *的魔性用法 函数形参最终顺序 1.2名称空间 全局名称空间,局部名称空间,内置名称空间 取值顺序与加载顺序 作用域 内置函数:globals() locals() ...

  6. 2.3.12 Python 函数进阶-装饰器

    代码运行期间动态增加功能的方式,称之为"装饰器"(Decorator) 本质上,decorator就是一个返回函数的高阶函数 所以,我们要定义一个能打印日志的decorator,可 ...

  7. Python函数进阶

    def eat(a,b,v,f,g): print(a,b,v,f,g) eat('方便面','包子','麻团','豆浆','咸菜') def eat(a,b,*args): # 聚合 打包 prin ...

  8. 2.3.14 Python 函数进阶-生成器

    通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素 ...

  9. python函数进阶小结_python函数的进阶

    形参角度: 万能参数 如果我们在传参数时不很清楚有哪些,或者说给一个函数传了很多实参,考虑用动态参数也叫万能参数. 万能参数,即动态参数,分为两种:动态接收位置参数 *args,动态接收关键字参数** ...

最新文章

  1. 360董事长周鸿伟在新员工入职培训上的讲话
  2. keras从入门到放弃(二十)LSTM处理 电影评价预测
  3. 每日求一录~20170704
  4. paper reference
  5. linux sed举例,sed 常用命令与参数,带举例:时时更新!
  6. Java 线程多线程编程3---线程同步之生产者与消费者问题
  7. 锁屏壁纸开发 Android,Android开发自己的锁屏壁纸
  8. 算法与数据结构题目汇总
  9. 排列和组合、以及数列(五)
  10. 使用Newtonsoft.Json接受部分资源
  11. 作为开发人员,U盘32G太小了,256G才够用
  12. 视频教程-PHP开发进阶课程docker入门与进阶-PHP
  13. 为什么要学习Linux内核,如何学习?
  14. python画太阳花代码
  15. 爬虫系列学习之爬取西瓜视频
  16. MLY -- 14.Evaluating multiple ideas in parallel during error analysis
  17. git添加diff tool和merge tool
  18. php抢购问题,PHP并发抢购解决方案
  19. linux xunsou_Linux 之 xunsearch
  20. 神了!用Python预测世界杯决赛,发现准确率还挺高!

热门文章

  1. MCU基础以及RTOS原理知识分享
  2. 二类电商运营怎么选品 二类电商怎么运营?
  3. HDOJ 2080 数学
  4. 浏览器获取MAC地址
  5. 莱布尼兹三角形(OJ0082)
  6. Jmeter通过HTTP代理服务器录制脚本(二)
  7. (转载)【笨木头Lua专栏】基础补充02:函数的几个特别之处
  8. 其次坐标,以及和非其次坐标互转
  9. 计算机控制技术专业全球排名,2019QS世界大学专业排名,快来看看!
  10. 今日头条回应90亿元地产收购传闻;微信号遭公开买卖;苹果新AirPods增加黑色款 | 雷锋早报...