Beware (mutable) keyword arguments and remember that...! by markon
Today, I've been working on a small Python script involving keyword-arguments. Being a simple script, it has been quite easy to debug and overcome the problem.
However, if you make an error like this inside a larger application, well, you will have few chances of catching it without a good debugging tool.
Let's see the code:
>>> class MyClass(object):
... def __init__(self, element, children=[]):
... self._element = element
... self._children = children
...
>>> c1 = MyClass(1)
>>> c1._children.append('foo')
>>> c2 = MyClass(2)
>>> c2._children
['foo']
So, beware mutable keyword-arguments and remember that when you pass a list, you're not passing a copy, but an actual reference to it (ok, you cannot modify it, but you can change its state!).
EDIT: Thank you both semarj (and Daimon) for your answer on reddit.com
EDIT2: Look at effbot.com for more info.
Comments
damilare commented 3 months ago
You should always check if len(children) > 0
markon commented 3 months ago
Cool, thank you very much for this suggestion! :D
spikeekips commented 3 months ago
This is your code to test.
The weird thing of python class, after it is instantiated, it's properties is shared with others like this. I think, it's the long time bug in python.
This is another examples of this problems.
if
classdoes not inherit the baseobjecttype.if
list()is set to the keyword argument.To escape this uncomportable, we can set the default value of keyword argument to
Noneand initialize it every time, when the class is created, like this.markon commented 3 months ago
Is this a bug?
spikeekips commented 3 months ago
I think so.
jpscaletti commented 3 months ago
This is not a bug, but the expected behavior. You should never use a mutable object as a default parameter because it is not the real object but a "pointer" to it.
Use
Noneinstead and initialize to an object inside the function:markon commented 3 months ago
If you read semarj's answer on reddit, he states that at compile time you're saying that "you just want that list", so Python keeps a reference to it. However, thank you for your last suggestion :)
spikeekips commented 3 months ago
@jpscaletti Yeah, right. I saw the same explanations on this /* problem */, but this kind of ambiguity in python always brings complexity or additional code.