Ouch, that is one extremely non-user friendly feature going on there. The only reason it works at all is because most people use default for strings/numbers only.<p>That functionality really should be changed for the next major python release, and have default evaluate each time the function is called - which is how 99.9% of people using it expect it to work.
The most frustrating thing that bit me when I was first learning python was the error when you pass the wrong number of arguments to a method:<p><pre><code> >>> class A(object):
... def method(self, a): pass
...
>>> A().method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method() takes exactly 2 arguments (1 given)
</code></pre>
Once you understand more about how method dispatch works it makes sense, but it's really confusing to be told you were doing something you don't think you are.
Wow I have been using Python for years and didn't realize default values were only created when defined. I don't think I have ever been bitten by it, but it would have been one helluva bug to track down.
I've been coding in Python for 8 years now and only this year came up against this behavior. I had a good long laugh after realizing what had just eaten up my previous couple hours.<p>I actually figured it out by printing out the id of the object being modified in my code, and when seeing it was the same had to really scratch my head. Default args are initialized when the function (or similarly, class) is defined, not when executed.
As a newbie to Python, my biggest issue when coming up to speed on a new project is chasing down the types of arguments to and return values from functions. Previously I was a Java programmer and while I don't miss its verbosity, I do miss how I always knew what types I was working with. Does anybody have any tips that make this easier?
A simple fix to the time/now example is also useful for demonstrating first-class functions:<p><pre><code> def print_now(now=time.time):
print now()</code></pre>
When I saw the title for this post, my first thought was "hmm, mutable default arguments are pretty tricky, hopefully that's somewhere on the list". I wasn't disappointed.
Cool, it looks like the Rachums are Israeli Pythonista brothers:<p><a href="https://news.ycombinator.com/item?id=5998675" rel="nofollow">https://news.ycombinator.com/item?id=5998675</a>
I went into this thinking "This'll be an obvious example - one I'm sure I wouldn't make."<p>I was wrong, and now I know better. Thank you.
Ha, that's funny. Just ran into this issue a few days ago. Spent an hour or two trying to figure what was going on, thought I was going crazy. Finally caved and asked an experienced python programmer, and they immediately pointed out that lists are mutable. Goes to show the value of working with experienced programmers.
A safe pattern for this without the None check is keyword expansion which will define defaults when a function is called.<p><pre><code> def foo(**kwargs):
numbers = kwargs.pop('numbers', [])
numbers.append(9)
print numbers</code></pre>
I would put the unfortunate scoping design above mutable defaults on the list of things that confused me.<p>Also, I really don't like the decision to make Python 2 disobey the system locale and use ascii as the default encoding. Lots of Python programs out there have broken i18n for no good reason because of that (nobody starts teaching python by telling you to use .decode('utf-8')/.encode('utf-8') when you pipe data, and by the time you realize what's wrong, you often already have code out there.)
Also worth mentioning is the closure gotcha: when you create functions in a loop, the functions' context points to the context of the latest iteration of the loop. Other languages might have this issue as well and provide alternatives based on map-style constructs. In Python, you can take advantage of the behaviour described by the OP to make your inner functions have their own context, which is initialized when the function gets created.
Note that tuples are immutable in python. I usually use tuples as default values for collections:<p>def f(x=()):
x = list(x)
...<p>def g(y=(()))
y = dict(y)
...<p>f() is the pattern for lists, g() is for dicts. Note that you can pass in regular lists to f() and regular dicts to g().