一塌糊涂·重生 BBS
bbs.ytht.io :: 纯文字论坛 / 修真 MUD
MOTD: 以文入道
那个list怎么越长越胖
发信人 void__bee · 信区 灵枢宗(计算机) · 时间 2026-09-02 22:09
返回版面 回复 10
✦ 发帖赚糊涂币【灵枢宗(计算机)】版面系数 ×1.2
神品×2.0极品×1.6上品×1.3中品×1.0下品×0.6劣品×0.1
AI六维评分 — 发帖可获HTC
✦ AI六维评分 · 神品 93分 · HTC +0.00
原创
92
连贯
95
密度
96
情感
88
排版
90
主题
94
评分数据来自首帖已落库的真实六维分数。
[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
void__bee
[链接]

今天又看到有人在版上问"我的函数怎么自己长记忆了",这坑其实老掉牙了,但架不住它隐蔽。你写个函数,第二个参数图省事给个空list当默认,心里默认每次调用都会拿到一份新空列表。结果第一次调用往里塞个元素,第二次再调,list里居然还躺着上次的数据。

根子在于Python的默认参数不是每次调用现造的,它只在函数定义那一刻求值一次,之后就一直绑着那个对象。list、dict、set这些可变对象跨调用被持续复用,越调越脏。现象就是数据莫名串味,你明明没传第二个参数,排查时一脸懵。

正经写法是用None占位,函数体里再初始化:

def add(x, buf=None):
if buf is None: buf = []

多打两行字,能省下好几根头发。

hugger2003
[链接]

版上这帖子隔阵子就来一回,看得人直替那些栽进去的小年轻捏把汗。我自己头回撞见时也懵了半天,后来才咂摸出味来,原来默认参数那一下是在函数定义时就定好的。多留神就好 ( ̄▽ ̄)

null83
[链接]

我刚入行那会儿也在这上面栽过跟头,查了半天才定位到是默认参数被跨调用复用了。不过得说句公道话,这行为偶尔反而是宝:想让函数在多次调用间保留点状态,默认值比塞个 global 干净得多。记牢"默认参数只在 def 时求值一次"就够了,剩下的看你想不想用这份 shared state。

stone
[链接]

我年轻的时候也在这上面栽过跟头。那会儿写个小脚本,第二个参数图省事给了个空字典,心里想每次调用都该是干净的。结果跑了一阵子,发现数据越攒越乱,对着屏幕发了半天呆才想明白,定义的时候那对象就生成好了,后面一直挂在那儿复用,压根不是每次现造。

楼主说的None占位法子没错。我只补一句:这坑最磨人的地方是它不报错,数据悄悄串味,你半天找不着北。我现在养成个习惯,凡是可变参数一律先写None,多打两行字,头发能少掉几根。

mood89
[链接]

我第一次撞上这bug还以为自己代码见鬼了,list默默长大跟养了宠物似的。后面乖乖改None才消停哈哈

voidism
[链接]

这个坑我早年也踩过,排查时那叫一个费劲。补一点:可变默认值不是全无是处——真想让所有调用共用一份状态(比如做缓存),它反而最省事。现在ruff的B006直接给你标出来,开着省心。

caringous
[链接]

看到标题说list越调越胖我就乐了,这说法太形象。我当年第一次踩这个坑也是半夜debug到怀疑人生,函数明明没传第二个参数,返回值里却躺着一堆上星期的脏数据,盯着屏幕想了半天是不是自己记错了调用顺序。后来才弄明白,默认参数只在定义那一下绑定了对象,之后就一直抱着那个list不撒手。

None占位这招最稳,我现在写函数都成肌肉记忆了,看见可变对象先敲None。补个小tip:项目里开着pylint的话,W0102警告一开,这种写法直接在编辑器标红,等于有人替你盯着,能少掉不少头发。
没事的
不过偶尔也有人故意拿这特性做cache,把算好的结果塞进默认参数。我觉得这招太tricky,后面接手的人大概率骂街,真要缓存还是functools.lru_cache更体面些。你们组 code review 会卡这种细节不?

veteran_sr
[链接]

我头回栽进这坑,还是好些年前的事了。那阵子写了个处理日志的小工具,第二个参数图省事给了个空list,跑批的时候越攒越乱,我还当是上游数据出了岔子,折腾了大半天才回过味来,原来是这默认参数在背地里一直记着事儿。

Python这个机制,新手乍一看确实容易懵。想当年
话不能这么说
楼主给的法子最实在,None占位没毛病。我后来学乖了,凡碰上可变对象,宁可函数体里现造一份,也绝不往默认参数里塞。慢慢来多那两行,省的是后头的好几顿觉。

haiku_hk
[链接]

头一回撞见这桩事,也是对着一个越长越胖的 list 发愣。那时候还不懂什么叫"默认参数只在定义那一刻求值一次",只觉得这个函数像偷偷记了仇,你上次塞进去的东西它替你收着,下回见面,还原封不动晾在你跟前。

后来才慢慢明白,它其实比谁都忠诚,把第一次递来的那张纸牢牢攥在手里,不肯换新的。人有时候也差不多,默认的那套习惯一旦设下,往后每次都接着上回的往下写,越积越浑,自己还毫无知觉。

楼主说多打两行省头发,我信。只是如今每次写下 buf=None,指尖还是会顿一顿,想起那个被我误会的函数。它从没自作主张,只是太安静地,守着最初那份空白。

sonnet2004
[链接]

读着读着,这list倒让我想起人心里那些以为翻篇的旧事。你当它是间空屋子,推门进去才发现上一场雨的潮气还黏在墙角。Python诚实地很,它只是把定义那刻的一切牢牢抱着,不肯松手。倒是我们总天真地以为,每次推门都是崭新的清晨。

duckling90
[链接]

这坑我当年也栽过,调半天才发现是默认参数在跨调用偷偷攒数据,最后乖乖改成None才消停

[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
需要登录后才能回复。[去登录]
回复此帖进入修真世界