281

I put a dict as the default value for an optional argument to a Python function, and pylint (using Sublime package) told me it was dangerous. Can someone explain why this is the case? And is a better alternative to use None instead?

2
  • 5
    The problem with pasing empty list as a default argument is that it will be shared between all invocations of the function -- see the "important warning" in docs.python.org/3/tutorial/… Commented Jan 18, 2017 at 12:13
  • In case that your function signature consists of only one dict argument or can otherwise admit a **kwargs form in its signature, then using a **kwargs argument seems to fully bypass this issue, as whenever it isn't filled by a caller its value defaults to an empty dictionary. But obviously this is a language feature detrimental to most people's notion of elegance in translating thoughts to code outside of extreme forms of functional programming thinking. Commented May 11, 2024 at 12:51

2 Answers 2

345

Let's look at an example:

def f(key, value, my_dict={}):
    my_dict[key] = value
    return my_dict

print(f('a', 1))
print(f('b', 2))

Which you probably expect to output:

{'a': 1}
{'b': 2}

But actually outputs:

{'a': 1}
{'a': 1, 'b': 2}
Sign up to request clarification or add additional context in comments.

13 Comments

so how we can still achieve a default value that matches afterwards code, vs saying "if h is None: h = {}" and then continue the code ?
I am kinda late, but I wanted to say thanks for this example. This was not something I was aware of with Python, so I was wondering why having empty list/dict was considered "dangerous". This helped a lot.
@alper it's not global variable, you can access it only in the scope of the function, but the default value, if not supplied is referenced to the dict you defined as literal. one way to avoid it is to def func(hash=None): if hash == None: hash = {} ...
I just want to say this is a real Python WTF. Who thought this could possibly be sane behaviour?
Note that hash=dict() has the same behaviour as hash={}.
|
306

It's dangerous only if your function will modify the argument. If you modify a default argument, it will persist until the next call, so your "empty" dict will start to contain values on calls other than the first one.

Yes, using None is both safe and conventional in such cases.

7 Comments

if function is not modifying the argument, should we still use None as default in the name of best practice?
@NightFurry: I hesitate to prescribe anything here--None is often the best choice, but perhaps not 100% of the time. Use your judgement, but if you can't decide, None is a safe bet.
In case anyone else stumbles across this question, please look at this answer on optional dictionaries in function arguments. I feel it's a much better discussion on how this issue should be addressed. Basically, today one should type-hint an optional mapping of {key: value}. ie arg: Optional[Mapping[str, str]] = None
If the function does not modify the argument but leaks a reference to it (by returning it, yielding it, calling some other function with it as an argument, or so on), then the same problem can occur. I would recommend always using None, even if the function is written carefully to avoid such bugs, purely so that seemingly-innocuous changes to the function cannot break it.
That sounds like a bug in python, as far I know other dynamic programming languages will not behave that way
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.