V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
woshichuanqilz
V2EX  ›  Python

Python 生成器的问题

  •  
  •   woshichuanqilz · Jul 2, 2021 · 3082 views
    This topic created in 1766 days ago, the information mentioned may be changed or developed.

    学习 python 生成器的时候遇到一个问题, 生成器的目的是减少空间占用, 所以每次只是返回一个值. 再有通项公式的时候我能理解, 每一项实际上都可以算出来这样就不用记录全部的元素了. 但是如果我随便找一个没有规律的 list 做成生成器, 那么空间的节约体现在哪里呢? 比如我有这样的代码

    (x for x in [1,5,-1,10])

    假设我的这个 list 是没有规律的, 那么这个生成器是不是要存下来整个的 list, 那么空间的节约体现在哪里?

    14 replies    2021-07-04 22:29:02 +08:00
    HashV2
        1
    HashV2  
       Jul 2, 2021
    你内存里都已经有 list 了,为什么还要用生成器去遍历,直接遍历你的 list 不就好了

    想省内存,就想办法把你最开始那个 list 写成生成器
    yufpga
        2
    yufpga  
       Jul 2, 2021
    首先生成器的目的并不是为了减少空间占用。其次你要搞明白生成器的原理, 就绕不开理解 yield 的机制。(x for x in [1,5,-1,10]) 等价于:

    def gen():
    for i in [1, 5, -1, 10]:
    yield i

    g = gen()
    wuwukai007
        3
    wuwukai007  
       Jul 2, 2021
    @yufpga 你这个也占用内存得啊。
    est
        4
    est  
       Jul 2, 2021
    mylist = [1,5,-1,10]
    (x*2 for x in mylist)
    (x/2 for x in mylist)


    这这种就节约空间了。不用存 3 份。
    HashV2
        5
    HashV2  
       Jul 2, 2021
    @yufpga #2 这种惰性的迭代器不就是为了减少内存占用的么? 不为这个的话是为了什么啊
    yufpga
        6
    yufpga  
       Jul 2, 2021
    @wuwukai007
    @HashV2
    我并没有在解释节省内存的问题,我在说的是生成器的原理,解释元祖形式的列表生成器的本质。

    可以去看看 python 生成器的 PEP ( https://www.python.org/dev/peps/pep-0255/), 该有的里面都有.

    事实上,你们也看到,生成器不一定总是会减少内存占用
    yufpga
        7
    yufpga  
       Jul 2, 2021
    @HashV2 你说的惰性迭代器缺失可以减少内存占用,但生成器的应用场景不只是迭代器上
    HashV2
        8
    HashV2  
       Jul 2, 2021
    @yufpga #7 👌
    abersheeran
        9
    abersheeran  
       Jul 2, 2021
    你的场景不对。

    比如你要处理一个 31Gb 的文件,你电脑却只有 16G 内存,该怎么办呢?这时候用 yield file.read(4096) 进行流式处理。就能大幅度节约内存空间。
    BeautifulSoap
        10
    BeautifulSoap  
       Jul 2, 2021   ❤️ 2
    谈生成器不谈迭代器的话你当然搞不清楚这么搞是为什么

    生成器的一个目的是方便遍历啊,一些情况下的确可以省内存,但是重点是方便遍历啊,方便遍历啊(重要的说三遍

    迭代器通过统一了__next__()和__iter__()两个接口,可以让使用者不用在乎你内部结构多么复杂,你只要用 iter()和 next()这两个方法都可以轻松遍历。并且学过迭代器的人难道忘了么,你一直习以为常在用的 `for i in xxxx` 这写法实际上就是个语法糖 iter()和 next()写法的语法糖啊。省内存只不过是迭代器带来的优点之一,根本目的还是统一了接口可以让你轻松遍历对象


    然后就是生成器,生成器可以部分看作是迭代器的语法糖(虽然 yield 作用不止是语法糖),你手写迭代器需要实现__next__()和__iter__()两个接口,而用 yield 构建的生成器只需要简单几行代码就行了,生成器和迭代器一样可以使用 next()迭代,也能用 `for in xxx` 这个语法糖,所以,本质上还是为了方便遍历啊
    Lemeng
        11
    Lemeng  
       Jul 2, 2021
    路过,学习一下
    deplives
        12
    deplives  
       Jul 2, 2021
    因为当你如果有一个几百 G 文件需要遍历而你的内存只有 512M,你就知道他是干啥的
    ipwx
        13
    ipwx  
       Jul 4, 2021
    那如果你 [1, 5, -1, 10] 是从文件读出来的呢。。。? 你可以每次只读 100 个,但是返回一个丢出去。多好
    shendun
        14
    shendun  
       Jul 4, 2021
    @ipwx 大佬求联系方式 聊几句可以吗
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2345 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 59ms · UTC 15:39 · PVG 23:39 · LAX 08:39 · JFK 11:39
    ♥ Do have faith in what you're doing.