1 import sys
2
3 class dummy(object):
4 def __init__(self, val):
5 self.val = val
6
7 class myobj(object):
8 def __init__(self, resourc
This is a known Python gotcha.
You have to avoid using a mutable object on the call of a function/method.
The objects that provide the default values are not created at the time that the function/method is called. They are created at the time that the statement that defines the function is executed. (See the discussion at Default arguments in Python: two easy blunders: "Expressions in default arguments are calculated when the function is defined, not when it’s called.")
This behavior is not a wart in the Python language. It really is a feature, not a bug. There are times when you really do want to use mutable default arguments. One thing they can do (for example) is retain a list of results from previous invocations, something that might be very handy.
But for most programmers — especially beginning Pythonistas — this behavior is a gotcha. So for most cases we adopt the following rules.
- Never use a mutable object — that is: a list, a dictionary, or a class instance — as the default value of an argument.
- Ignore rule 1 only if you really, really, REALLY know what you're doing.
So... we plan always to follow rule #1. Now, the question is how to do it... how to code functionF in order to get the behavior that we want.
Fortunately, the solution is straightforward. The mutable objects used as defaults are replaced by
None
, and then the arguments are tested forNone
.
So how can one do it correctly? One solution is avoid using mutable default values for arguments. But this is hardly satisfactory, as from time to time a new list is a useful default. There are some complex solutions like defining a decorator for functions that deep-copies all arguments. This is an overkill, and the problem can be solved easily as follows:
class ext(myobj):
def __init__(self, resources=None):
if not resources:
resources = []
self._resources = resources