QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3739|回复: 2
打印 上一主题 下一主题

[国赛经验] Python 迭代器、生成器

[复制链接]
字体大小: 正常 放大

326

主题

32

听众

1万

积分

  • TA的每日心情
    慵懒
    2020-7-12 09:52
  • 签到天数: 116 天

    [LV.6]常住居民II

    管理员

    群组2018教师培训(呼和浩

    群组2017-05-04 量化投资实

    群组2017“草原杯”夏令营

    群组2018美赛冲刺培训

    群组2017 田老师国赛冲刺课

    跳转到指定楼层
    1#
    发表于 2020-6-16 10:18 |只看该作者 |倒序浏览
    |招呼Ta 关注Ta
    一、可迭代对象
    % h/ ?0 [7 `( G$ T! _字面意思:
    7 k- N8 v& B1 Q0 l- }/ F对象:Python 中一切皆为对象(巧了 Java 也是(手动滑稽))
    3 {) f7 ]) N/ ~0 N+ n) l可迭代:可更新迭代,重复、循环的一个过程,每次更新迭代都会获得新的内容7 a! N$ l! j- O, I- x
    专业角度:内部含有 '__iter__‘ 方法的对象
    : v' j6 N+ }3 b. `! o9 x目前学过的可迭代对象:str、list、tuple、dict、set、range、文件句柄等
    " c* Y" l$ k0 ]+ r. e9 f/ O判断一个对象是否是可迭代对象:看是否有 '__iter__' 方法,dir() 可以获取一个对象的所有方法;或者使用 isinstance(object, collections.iterable) 来判断对象是否是可迭代对象的一个实例' V6 B! X+ W) q

    ; e+ i  \/ G* D3 }. Q( l
    $ ?' D' r6 [# Z* q0 e( U优点:
    % t" m2 y- n7 c* h存储的数据直接能显示,比较直观:比如直接 print 一个可迭代对象,就会调用 __str__ 方法(相当于 Java 中的 toString),把可迭代对象的值打印出来4 z3 P: J3 N' y
    拥有较多的方法,操作方便:增删查改等
    * e% T. I' y4 w" B# }4 H缺点:
    1 k4 h, `5 Y6 }5 G" ]2 G占用内存:一旦创建了一个可迭代对象,就会将该对象的内容全部加载到内存中
    3 H; J5 J' L! b2 e不能直接通过 for 循环,不能直接取值(通过索引、key等)。诸如通过 for i in iterable 这种形式获取元素实际上也是调用了 __iter__ 方法先将可迭代对象转换成迭代器再进行获取4 o2 ^' u+ P$ d& X9 Z; O6 j
    二、迭代器# S; T: J( H+ A& i& ?& ~
    字面意思:器,工具,迭代器也就是可以一直更新迭代取值的工具) g  ]3 Z0 @' u/ j! g) S- @: ~& x) w
    专业角度:内部含有 __iter__ 方法且含有 __next__ 方法的对象就是迭代器;或者使用 isinstance(object, collections.iterator) 来判断对象是否是可迭代对象的一个实例+ j1 R  B! C6 D5 g
    把一个可迭代对象转换成迭代器:使用 iter() 方法或使用对象的 __iter__ 方法+ p, N- x; a1 Z; y( k  y  o- n

    ' k) C1 ~( `, t: g% X: T迭代器取值:使用 next() 方法或对象的 __next__ 方法;当迭代器的值去玩了继续取,就会报StopIteration异常,所以一般使用迭代器需要做异常处理
    # Y  K( m+ Q, {, u7 e& L& g) o% M  B( z& `5 }
    优点
      G( h6 [# ~+ Z$ V8 m" O: L节省内存:迭代器并不会一次性将对象的值全部加载到内存中,而是需要时才加载(类似 sed). e( L& n! [% G8 S, v* U
    惰性机制:next 一次只取一个值,绝对不多取( a* E/ u  y4 Z; P' ~9 i
    缺点:5 T) n) z' C( s5 @0 `# ^7 Y% ~6 ?: ~
    速度慢:需要一直 next9 O! y3 ^" r9 S- k  v' D
    不能回头:只能一直往下取值,取过的值没保存就没了`/ \- R8 p2 l& Y! l# U8 Z) c5 h
    不能直观的看到里面的数据
    & E  ~5 T/ j7 K. Z3 [3 q$ g* \' P三、可迭代对象与迭代器对比( d. G* b3 k8 I3 i& R
    可迭代对象:
    % q7 r+ o: X3 v2 A+ k私有方法多,操作灵活(比如列表,字典的增删改查,字符串的常用操作方法等)
    1 J* ]6 K+ Q  c8 \$ F* i0 Z直观,可以直接看到里面的数据7 W/ J! A! @3 W! q* ]# W9 `
    占用内存
    , {' N4 E  \3 [+ `2 R不能直接通过循环迭代取值; h4 b/ M  j; x7 ~; {
    应用:当你侧重于对于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择
    + Q- ]+ D* @( N/ u% G3 v6 X迭代器:
    3 Y/ @3 p3 K4 C9 C4 h/ S节省内存,按需取值  |- h% p+ {! f# Y
    可以直接通过循环迭代取值& n# }$ l7 Y0 P
    数据不直观,操作方法单一
      e$ S  c& x5 H1 I6 c: j: |应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择0 R  r- H* F, _
    四、生成器
    ! Q! Y" z: r2 g: C生成器的本质就是迭代器,唯一的区别是生成器是我们自己用代码构建的数据结构,迭代器是 Python 提供的,或者通过可迭代对象转化得来的
    1 b8 Q/ Z" h/ e, j/ K7 H  V  ?# g3 a% |# J
    定义生成器的方式:
    * T. k* L7 [( }& t. X通过生成器函数构建生成器
      i+ I* h6 Y7 E: G/ J 111.png
    # @& R8 G3 o+ g% M. \3 t2 L
    ; h8 M) Z9 O2 b1 N' `/ ]5 B* X0 Y6 l0 W' Z4 L
    这就是最简单的生成器函数。实际上这个 yield 就替代了 return,不仅将函数变成了生成器函数,还会将后面的值在调用 __next__ 的时候返回出来$ g% n8 j+ e) d( j  x# r! |
    * M6 {, r% S1 f5 n: D
    也可以在一个函数里定义多个 yield. L6 |/ a! u! e" b# D9 t+ T
    & L- D. K- _# \
    之前说过,生成器本质上还是迭代器,一个 yield 对应一个 next,当 next 的数量超过了 yield,就会报 StopIteration
    % t, o' P, Z0 r) W" R! s2 G7 a
    6 ?9 A3 _) d5 T9 K: _  d# @# pyield 与 return 的区别( V$ _* K2 o! R. t
    " z8 `. r1 }) s1 V) b& G2 z' V
    return一般在函数中只设置一个,他的作用是终止函数,并且给函数的执行者返回值" Z- j0 S& z8 A! t/ ~# u( P1 R
    yield在生成器函数中可设置多个,他并不会终止函数,next会获取对应yield生成的元素' o5 P1 a2 ~% h2 y0 T8 R
    应用举例:6 `  L( E5 p  t& x9 B1 s
    , L: y+ [/ ~1 r  e* u" L1 X
    买 5000 个包子,假设这个老板很厉害,一下子就把 5000 个包子做出来卖给我们,可是我们只有 5 个人,一下子吃不完,那包子就会冷掉、臭掉、被丢掉浪费了
    3 }) U9 A8 h" q; |9 ` 222.png
    ; E2 C# m2 F  a8 K/ N9 U
    ! b, w9 `6 M- Y& c4 w1 A5 [& r如果这个老板可以在我们需要多少个包子就做出来多少个包子的话,这样做出来的包子就不会被浪费了(比如我们每个人一口气能吃 40 个包子,那每次就做 200 个包子):4 ~* O8 O0 X5 i( u" M
    3333.png
    / M3 z) `- ]1 z) G! }3 T. r) J$ x. L6 ^$ {/ G. R& p
    除了 使用 next() 触发 yield 之外,生成器还有一种方法 send(),这个方法可以在调用 yield 的同时传值给生成器内部8 a8 w; n3 {4 K7 o& x: v0 z

    . p" V) c5 O0 o1 t2 ~+ F2 R可以看到在使用 next() 的时候,只能获取到 yield 的值,但不能传递值
    & O5 k6 q7 }  {. X/ ], Y/ t1 G# F5 f5 g" o8 f6 b$ L$ \
    在使用 send() 的时候,可以将参数传入生成器中使用
    ! V% X( Y8 k4 o" q* B2 |' }) z) b
    需要注意的是第一次不能直接调用 send() 传参,因为每次调用生成器的时候,实际上只会返回 yield 后面的内容,然后生成器就停止了(睡眠了?),而 send() 传入的参数要通过 yield 传入生成器中(每次调用生成器在 yield 停止,然后在 yield 恢复继续允许),第一次调用并没有 yield 给我们传入参数,可以使用 send(None),可以打断点自己分析一下
    1 p$ m1 [8 G2 n, f3 _) L4 d0 {3 ?
    0 m4 d' H4 G9 _yield 会将它后面跟着的对象直接返回,如果它后面跟着的是可迭代对象,也可以使用 yield from 将这个可迭代对象变成迭代器返回
    3 g" ^" ?/ t, J; s9 k1 U$ A6 ~; z: M  E$ d
    ' x6 l% K" W7 |5 C; K5 w
    yield from 是将列表中的每一个元素返回,所以写两个 yield from 并不会有交替执行的效果! T) A. Y; b7 t* Q' v+ W
    ' [2 Q/ H. V$ b, C

    * f4 o8 U' {$ u& n4 u
      w' ^: j" S' z2 o! `通过推导式构建生成器
    : e1 i1 [  g! l( ^! `3 C列表推导式:4 S( ^5 C( w+ ~1 H5 U

    9 q8 D" y- }5 v生成器表达式:和列表推导式差不多,把 [] 改成 () 即可
    2 Z0 ^0 T8 Z7 x& y' ~) ?( O) p) I1 ^+ W% j

    + ?5 L9 ^' D7 O+ H/ R  _列表推导式和生成器推导式的区别:6 \/ J2 T: T: Z/ H+ z$ p% m

    6 b! `& o) C; Q; y  _0 t2 q列表推导式比较耗内存,所有数据一次性加载到内存;而生成器表达式遵循迭代器协议,逐个产生元素
    & [. m: u) P& L9 p3 {5 A8 P0 ?得到的值不一样:列表推导式得到的是一个列表;生成器表达式获取的是一个生成器
      s7 A  b- b! s* e7 A列表推导式一目了然,生成器表达式只是一个内存地址* N9 f7 p2 @2 m, Y& y! q; z. W: E7 C
    ————————————————( p* d& M% x, ]0 |* D7 B8 I
    版权声明:本文为CSDN博主「阿玮d博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    - q$ ^3 r7 d( c# N0 j% h5 f- `  Q原文链接:https://blog.csdn.net/weixin_42511320/article/details/1056761434 B5 m9 f- I6 @" [9 X$ Z; _: |

    . G# U: M3 v* E' l. S- w0 F, o9 j3 l! N6 p
    zan
    转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
    dwadasd        

    0

    主题

    1

    听众

    54

    积分

    升级  51.58%

    该用户从未签到

    网络挑战赛参赛者

    自我介绍
    dasd asdasd
    回复

    使用道具 举报

    dwadasd        

    0

    主题

    1

    听众

    54

    积分

    升级  51.58%

    该用户从未签到

    网络挑战赛参赛者

    自我介绍
    dasd asdasd
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 注册地址

    qq
    收缩
    • 电话咨询

    • 04714969085
    fastpost

    关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

    手机版|Archiver| |繁體中文 手机客户端  

    蒙公网安备 15010502000194号

    Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

    GMT+8, 2026-6-22 16:27 , Processed in 0.507812 second(s), 63 queries .

    回顶部