QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3969|回复: 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
    一、可迭代对象" }  j( {/ i8 Y- I
    字面意思:
    , ?2 r" Q, ]" f对象:Python 中一切皆为对象(巧了 Java 也是(手动滑稽))+ G0 |' _' V! j8 v. F: e' _! G1 c4 t
    可迭代:可更新迭代,重复、循环的一个过程,每次更新迭代都会获得新的内容
    # c* H, P8 d+ S, w8 G专业角度:内部含有 '__iter__‘ 方法的对象
    1 d& X) W3 M& d. A, m目前学过的可迭代对象:str、list、tuple、dict、set、range、文件句柄等
    4 n4 a8 D/ J5 G9 Q: Z判断一个对象是否是可迭代对象:看是否有 '__iter__' 方法,dir() 可以获取一个对象的所有方法;或者使用 isinstance(object, collections.iterable) 来判断对象是否是可迭代对象的一个实例9 }! f) X' n1 Q" p
    6 q6 M$ g6 n. o* a8 [
    1 Q- A; [# D  [# J  p5 ]9 E4 b
    优点:" i$ ^8 f3 d, S5 {# ]( y$ @
    存储的数据直接能显示,比较直观:比如直接 print 一个可迭代对象,就会调用 __str__ 方法(相当于 Java 中的 toString),把可迭代对象的值打印出来
    , a6 Y3 w2 j# O( {' e0 m拥有较多的方法,操作方便:增删查改等4 X6 q1 b  [" d, L" w( t6 M
    缺点:
      E' \3 ~! o. O. T( J. [占用内存:一旦创建了一个可迭代对象,就会将该对象的内容全部加载到内存中4 V0 G, t! s1 K6 ^
    不能直接通过 for 循环,不能直接取值(通过索引、key等)。诸如通过 for i in iterable 这种形式获取元素实际上也是调用了 __iter__ 方法先将可迭代对象转换成迭代器再进行获取5 A) E% Z' F! g' n
    二、迭代器. N5 B, Q( K* D) \) _! P5 X
    字面意思:器,工具,迭代器也就是可以一直更新迭代取值的工具; J6 s, K! [( D; W1 V9 r- p3 G$ I6 ~
    专业角度:内部含有 __iter__ 方法且含有 __next__ 方法的对象就是迭代器;或者使用 isinstance(object, collections.iterator) 来判断对象是否是可迭代对象的一个实例9 x6 x3 |/ [& E- W  t
    把一个可迭代对象转换成迭代器:使用 iter() 方法或使用对象的 __iter__ 方法
    9 C0 V% }5 m( ?3 F" U
    2 _! L' A" X, l# L迭代器取值:使用 next() 方法或对象的 __next__ 方法;当迭代器的值去玩了继续取,就会报StopIteration异常,所以一般使用迭代器需要做异常处理' d" W9 ]0 e! ^5 T+ g$ f7 i
    3 M1 d; W1 j) E8 p- a. _+ g3 x
    优点
    4 j( v2 Z8 a9 N+ ~- _- U节省内存:迭代器并不会一次性将对象的值全部加载到内存中,而是需要时才加载(类似 sed)
    6 V8 A9 I' O' [6 _$ ^! g1 q0 h7 i惰性机制:next 一次只取一个值,绝对不多取+ |8 R) x9 [/ I8 A/ @6 R2 X% C
    缺点:% R7 w' b( S  j8 W
    速度慢:需要一直 next
    2 u* I  V; ^2 {1 Q% V3 T9 e/ B不能回头:只能一直往下取值,取过的值没保存就没了`
    . L0 Q. _. {6 o' U3 R$ G3 ~/ k不能直观的看到里面的数据
      N# p  e* `9 E/ _0 v7 ]" E- v5 B三、可迭代对象与迭代器对比
    ! [2 }6 f! ~  C' ]; b$ @& X可迭代对象:. {* P6 \  A0 i* @5 ?0 c+ ~: m# ~
    私有方法多,操作灵活(比如列表,字典的增删改查,字符串的常用操作方法等); I5 F& U6 {, |+ S3 C
    直观,可以直接看到里面的数据) j' b$ P  c" Z, \4 u3 T, T/ @
    占用内存1 C- z# E' o. {, t+ U1 m
    不能直接通过循环迭代取值0 u( M& L9 ^! Z  [+ d( ^% c# R0 q. A
    应用:当你侧重于对于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择
    7 y2 M& K! [! p# k( B迭代器:7 G$ B0 Z; Z% B0 D, Z- c- U8 `, N2 l
    节省内存,按需取值
    ! l6 }* g# E' y可以直接通过循环迭代取值
    0 _/ s# h3 g# f, r; k数据不直观,操作方法单一% D" Q' p- c6 }, U3 ^0 B
    应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择2 U& E+ o8 P9 w- X3 M9 F( G2 K5 _
    四、生成器
    / F4 G4 D8 J  k! p3 o生成器的本质就是迭代器,唯一的区别是生成器是我们自己用代码构建的数据结构,迭代器是 Python 提供的,或者通过可迭代对象转化得来的
    - K4 D; [6 ~$ {. G" I) B. p
    & W  ~0 U& r* `( t定义生成器的方式:8 Q! l" h8 i1 ~- \
    通过生成器函数构建生成器
    / }4 _7 c2 P$ { 111.png
    / R+ g" [6 v2 |" g9 W; B, _' m; Q) v6 k) b
    . s0 G& U: I7 E8 i# s
    这就是最简单的生成器函数。实际上这个 yield 就替代了 return,不仅将函数变成了生成器函数,还会将后面的值在调用 __next__ 的时候返回出来; @8 i/ q, {+ `' A) w5 `3 \7 \
    * l2 R# T* _8 T- E6 M2 J
    也可以在一个函数里定义多个 yield: g! Y% |0 n* \  j; q
    & D- e1 F2 f$ m1 t
    之前说过,生成器本质上还是迭代器,一个 yield 对应一个 next,当 next 的数量超过了 yield,就会报 StopIteration' X4 c; x  l1 z. ^

    & f1 O* L) u( [* ?- hyield 与 return 的区别
    : E% [  t& I. O' R( y1 Z! J9 u9 {+ q" `. u9 @4 c- W
    return一般在函数中只设置一个,他的作用是终止函数,并且给函数的执行者返回值7 ]$ G* A4 {: d  N2 ]$ C5 @9 M# D  r
    yield在生成器函数中可设置多个,他并不会终止函数,next会获取对应yield生成的元素. q1 w, j6 P5 i  e/ T, X7 L
    应用举例:7 `% {) E6 e) @  T2 H6 K" e
    + w. P4 v& k! C' k
    买 5000 个包子,假设这个老板很厉害,一下子就把 5000 个包子做出来卖给我们,可是我们只有 5 个人,一下子吃不完,那包子就会冷掉、臭掉、被丢掉浪费了& q- i. o7 j6 U3 ~2 O- y' E+ c" U" }
    222.png + s8 ]7 K9 V1 u

    & h' V3 d0 L" D" o- B6 U" T" x如果这个老板可以在我们需要多少个包子就做出来多少个包子的话,这样做出来的包子就不会被浪费了(比如我们每个人一口气能吃 40 个包子,那每次就做 200 个包子):1 R8 _  d& {0 N* _9 i9 L! Z
    3333.png
    + X) t: p, u7 B6 h) w2 `
    ( }# s7 L2 _+ p除了 使用 next() 触发 yield 之外,生成器还有一种方法 send(),这个方法可以在调用 yield 的同时传值给生成器内部
    ' w, H& `' ]8 f) z: r/ k1 @9 R
    8 @8 l& G% U4 b% E0 Y可以看到在使用 next() 的时候,只能获取到 yield 的值,但不能传递值, L# y9 E" @$ y
    . x& i( ]0 j! d& v/ M" z  q1 E+ A
    在使用 send() 的时候,可以将参数传入生成器中使用
    1 {! `- G+ o, f- T7 A! J$ I  q7 t) ~/ v/ K
    需要注意的是第一次不能直接调用 send() 传参,因为每次调用生成器的时候,实际上只会返回 yield 后面的内容,然后生成器就停止了(睡眠了?),而 send() 传入的参数要通过 yield 传入生成器中(每次调用生成器在 yield 停止,然后在 yield 恢复继续允许),第一次调用并没有 yield 给我们传入参数,可以使用 send(None),可以打断点自己分析一下' N  Q8 j1 c% ~- J1 N8 D2 j9 q2 H
    * H3 v0 K' N  P+ I$ {8 _+ r
    yield 会将它后面跟着的对象直接返回,如果它后面跟着的是可迭代对象,也可以使用 yield from 将这个可迭代对象变成迭代器返回% v& _1 Y7 M( N& O1 ~6 K+ f7 v0 O6 ~
      S7 ?" `9 Q& Q9 P5 E2 L
    - s  o. ^3 j+ ?. V% e/ h* }
    yield from 是将列表中的每一个元素返回,所以写两个 yield from 并不会有交替执行的效果* w; L$ h2 f) }9 r" x9 m
    + z! l( P. O( x2 D6 v
    " V$ s- f6 @, q' r+ ~6 F- q" Y# [
    $ `$ x) z- I/ S! y
    通过推导式构建生成器  ~/ s# O4 k; b, [  `( Q
    列表推导式:
    : J% V7 N' ]- [# l* @6 X4 ~3 T, ?& p- M* n7 W% _
    生成器表达式:和列表推导式差不多,把 [] 改成 () 即可
    7 Z( L6 V7 W: e: j9 m. H% E% j: B- X. c7 N' g
    : D8 Z! a6 s3 U: v% z) B; v) E
    列表推导式和生成器推导式的区别:
    ' ^/ ]# Z/ Z+ ^. C: a! U8 E5 l- W6 ~, J5 x$ I  X& N
    列表推导式比较耗内存,所有数据一次性加载到内存;而生成器表达式遵循迭代器协议,逐个产生元素
    / o) v# e2 g3 K  s7 p得到的值不一样:列表推导式得到的是一个列表;生成器表达式获取的是一个生成器
    0 \& t5 y" l# S1 g& H  E. G2 s8 G列表推导式一目了然,生成器表达式只是一个内存地址
    7 T* D( v3 y- @3 j/ C6 y0 b+ r, d" a/ I————————————————( J% X# H, H5 k' X1 P" {: R
    版权声明:本文为CSDN博主「阿玮d博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    - h, `7 q' [' ?  ^; m原文链接:https://blog.csdn.net/weixin_42511320/article/details/105676143* f# v  Q+ t6 Z' q! p8 e* Y$ H8 \
    - K# [4 @5 r! {2 N# h
    : Z6 y, L/ J, j6 q, G: i; ?
    zan
    转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
    dwadasd        

    0

    主题

    1

    听众

    54

    积分

    升级  51.58%

    该用户从未签到

    网络挑战赛参赛者

    自我介绍
    dasd asdasd
    回复

    使用道具 举报

    dwadasd        

    0

    主题

    1

    听众

    54

    积分

    升级  51.58%

    该用户从未签到

    网络挑战赛参赛者

    自我介绍
    dasd asdasd
    回复

    使用道具 举报

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

    fastpost qq
    收缩
    • 电话咨询

    • 04714969085

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

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

    蒙公网安备 15010502000194号

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

    GMT+8, 2026-11-9 19:53 , Processed in 0.246433 second(s), 64 queries .

    回顶部