openpyxl 写 Excel 的三个隐蔽坑:等号开头的文本、列宽自适应、公式缓存

举报
yd_257742204 发表于 2026/11/07 06:25:15 2026/11/07
【摘要】 批量生成 Excel 时 openpyxl 有几个静默失败的坑:以等号开头的文本被当成公式、列宽不会自适应、公式没有缓存值导致回读为 None。本文给出可复现的最小代码和三种处置方式。

Python 生成器实战:用惰性求值把内存从 O(n) 降到 O(1)

处理大文件、大接口分页、无限流数据时,很多人第一反应是把数据全部读进 list 再处理。数据量一大,内存立刻爆炸。生成器(generator)是 Python 里解决这类问题的标准答案,但实际用起来有几个隐蔽的坑,这篇按实战顺序讲清楚。

一、惰性求值的核心:一次只产出一项

生成器函数用 yield 返回数据,调用它得到的是生成器对象,函数体并不执行,直到每次 next() 推进到下一个 yield:

def read_large(path):
    with open(path, encoding='utf-8') as f:
        for line in f:
            line = line.strip()
            if line:
                yield line

logs = read_large('access.log')   # 此刻什么都没读
first = next(logs)                # 只读第一行

同样的文件如果写 lines = f.readlines(),1GB 的日志就要吃掉数倍内存;生成器版本任何时刻只持有一行。

二、坑一:生成器是一次性的

生成器耗尽后再迭代,得到的是空结果,而且不报错——这是最容易踩的静默 bug:

errors = (l for l in read_large('access.log') if 'ERROR' in l)
print(sum(1 for _ in errors))   # 1203
print(sum(1 for _ in errors))   # 0 !

对策只有两个:要么需要多次使用就改成列表(接受内存代价),要么把生成器封装成工厂函数,每次调用产生新的生成器。

三、坑二:生成器表达式引用外层变量是惰性绑定

keys = ['a', 'b', 'c']
gens = [k for k in keys]          # 没问题
funcs = [lambda: k for k in keys] # 三个 lambda 全返回 'c'

lambda 捕获的是变量 k 本身而不是当时的值,循环结束后 k 停在 'c'。生成器表达式同理——如果生成器内部引用了循环变量,真正 next() 时才求值。修法是给函数参数做默认值绑定:lambda k=k: k。

四、坑三:yield 与 return 的合作

生成器里 return 不是返回值,而是触发 StopIteration;只有 yield from 委托链才能把返回值带出来(PEP 380),日常代码里几乎用不到,但调试看到 StopIteration('xxx') 携带值时要知道这是 return 的产物,不是异常数据。

五、实战模式:分页拉取转惰性流

把"循环翻页拉接口"封装成生成器,调用方就能用统一的 for 循环处理,翻页细节全部隐藏:

def iter_pages(fetch, page_size=100):
    page = 1
    while True:
        items = fetch(page, page_size)
        if not items:
            return
        yield from items
        page += 1

total = sum(1 for _ in iter_pages(fetch_orders))  # 内存恒定

配合 itertools.islice 还能随时截断:islice(iter_pages(fetch), 500) 只拉前 500 条就停止翻页,请求数也随之减少——这是 list 方案做不到的。

小结

场景 用法
逐行处理大文件 yield line,内存 O(1)
多次消费 工厂函数每次新建,勿复用耗尽的生成器
循环里建 lambda/生成器 默认参数绑定 k=k
接口分页 yield from items + islice 截断

生成器不是语法糖,是把"存储整份数据"换成"按需生产数据"的结构性手段。写数据管道时先想清楚数据会被消费几次,再决定生成器还是列表。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。