TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Python's Mutable Default Problem

68 点作者 tswicegood超过 14 年前

17 条评论

sophacles超过 14 年前
I'm not sure this constitutes any problem other than a lack of understanding of the python runtime. What the author describes as:<p><i>"the mutable default parameter quirk is an ugly corner worth avoiding"</i><p>could also be described as:<p><i>"a natural outcropping of python's late binding, "names are references" variable model, and closure mechanisms, which provide a consistency to the language that is often crufted up in others"</i><p>I do somewhat agree with the author that this particular functionality should be a "use only when needed" feature. I don't think it should be avoided at all costs tho, because there are times where the mutable default allows for a lot of saved code. In fact in a few cases the code to work around using mutable defaults can get into some serious voodoo because frequently the writer is actually trying to work around the bigger mutable/immutable objects and names are references "issues" in python.<p>This also reminds me of something I was reading on the front page today about the old 'use the whole language' vs 'simplicity is king' holy war.
评论 #2242291 未加载
评论 #2242259 未加载
评论 #2242255 未加载
aston超过 14 年前
As noted in the comments, DON'T use<p><pre><code> stuff = stuff or [] </code></pre> because if you pass an empty list, you'll get a new one rather than mutating the one you passed.<p><pre><code> stuff = stuff if stuff is not None else [] </code></pre> is wordy, but at least it's correct.
评论 #2242379 未加载
评论 #2243258 未加载
评论 #2242471 未加载
评论 #2242799 未加载
评论 #2244155 未加载
perlgeek超过 14 年前
FWIW, Perl 6 implicitly treats default values as closures, and calls them when no argument is passed that could bind to the optional argument.<p>That way you get a fresh array each time, and you can even use defaults that depend on previous arguments:<p><pre><code> sub integrate(&#38;integrand, $from, $to, $step = ($to - $from) / 100) { ... }</code></pre>
emehrkay超过 14 年前
Pylint (or maybe it was pep8) has told me not to make dicts default arguments when running it against my code, but didn't explain why. Thanks for the post.
riobard超过 14 年前
You just need to fully understand when Python does evaluation.<p><pre><code> import types def function(item, stuff = lambda: []): if type(stuff) == types.FunctionType: stuff = stuff() stuff.append(item) print stuff function(1) # prints '[1]' function(2) # prints '[2]' </code></pre> In Scala it has a better syntax because of typed function object:<p><pre><code> trait Map[A, B] { … def getOrElse (key: A, default: ⇒ B): B … } </code></pre> the `default` parameter is a function, so when you do<p><pre><code> getOrElse(someKey, defaultValue) </code></pre> The `defaultValue` becomes a function that generates the value you put there when called.
spenrose超过 14 年前
Yes, it's a wart. You learn the patterns he mentions pretty quickly.
评论 #2242911 未加载
neutronicus超过 14 年前
"stuff = stuff or []"<p>This idiom is baked into the perl community. It's kind of funny to see a Pythonista deciding it's a good idea. (You can tell it hurts him too).
评论 #2242306 未加载
评论 #2242710 未加载
评论 #2242909 未加载
mark-r超过 14 年前
I keep seeing this "problem" come up, but I don't understand how it's realistic. If you have a function that modifies a parameter as a side effect, why would you have a default value for the parameter?<p>And since the site's comments seem to be taken over by link spam, is this mention on Hacker News just a clever way to juice the Google rank of said spam?
评论 #2243989 未加载
dustingram超过 14 年前
This 'problem' can actually come in handy when used with a regex callback function.<p>See if you can determine what this does:<p><pre><code> def cbk(match, nb = [0] ): if len(match.group())==len(nb): nb[-1] += 1 elif len(match.group())&#62;len(nb): nb.append(1) else: nb[:] = nb[0:len(match.group())] nb[-1] += 1 return match.group()+' '+('.'.join(map(str,nb))) str = re.compile('^(#+)',re.MULTILINE).sub(cbk,str)</code></pre>
评论 #2243912 未加载
billmcneale超过 14 年前
The problem is not so much about mutable, it's that default parameters escape the scope of their method.<p>Which is very, very messed up (but not the first thing Python messed up).
wyuenho超过 14 年前
It's on SO's Python FAQ too. This is the only thing in Python that's really bitten me. I remember it took me like a week to figure this out when I was tearing down my algorithm bit by bit to find out whether my prove was wrong or the code.<p><a href="http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument" rel="nofollow">http://stackoverflow.com/questions/1132941/least-astonishmen...</a>
pedro3005超过 14 年前
You can use this trick for memoization. Example: <a href="http://paste.pocoo.org/show/341849/" rel="nofollow">http://paste.pocoo.org/show/341849/</a>
评论 #2242914 未加载
评论 #2243969 未加载
clay超过 14 年前
"stuff = stuff or []"<p>This would fail to have expected behaviour here:<p>fill_list = []<p>stuff = function(info, full_list)<p>print fill_list<p>use the if list is None: paradigm
viraptor超过 14 年前
Not sure if that's a "problem" if the only other way to implement function-static variables would be to add a variable visible for the whole module, or tricks with decorators...<p><pre><code> @statics(blah=[]) def foo(normal_args, **kwargs): # or def foo(normal_args, blah): </code></pre> It messes up the idea of looking at the definition to find the function signature.
baq超过 14 年前
it's a gotcha but it makes perfect sense once you understand why it works that way - i.e. the difference between evaluating a function definition and calling it.
jfm3超过 14 年前
The Pythonist doth protest too much, methinks.
drstrangevibes超过 14 年前
i think its clearer and more pythonic in this case to do<p>def function(item, stuff): .... blah blah def function(item): function(item, [])