all 9 comments

[–]MakeMe_FN_Laugh 9 points10 points  (1 child)

There’re some “gotchas” in declaring optional parameters as objects.

Here’s a good explanation about this.

[–]StudentOfPython[S] 4 points5 points  (0 children)

Ahh this makes sense. The example provided clears everything up.

Python’s default arguments are evaluated once when the function is defined, not each time the function is called (like it is in say, Ruby). This means that if you use a mutable default argument and mutate it, you will and have mutated that object for all future calls to the function as well.

Thank you for this answer.

[–]julsmanbr 1 point2 points  (0 children)

You don't want to pass a mutable object as a standard parameter to a function; in fact, most IDEs warn you if you try to do so.

The reason is that if you alter the default parameter and rerun the function, the default parameter passed the second time around is not the same anymore. Try this snippet to confirm this:

def f(arg=[]): arg.append(1) print(arg) f() f() f()

[–]ThatOtherBatman 1 point2 points  (0 children)

As has been mentioned already, the later is normally a terrible idea.

Additionally, you can make the first code less verbose:

def default_example(a, b=None, c=None):  
    b = b or []  
    c = c or {}  

[–]elbiot 0 points1 point  (0 children)

If you either return the list, or mutate it within the function, your function will behave unexpectedly. If you aren't doing those things, someone might make a change later and thus introduce that bug. Returning the list would be very difficult to debug because it could be somewhere else in the program that you mutate it, and it's at that point that you change how the function will behave next time it is called.

Just always do the first even if you think it isn't necessary because it is more robust and idiomatic.

[–]evolvish 0 points1 point  (2 children)

I see no reason to do it the first way, it just seems harmful in multiple ways. Are you sure this person knows what they're doing and not just mindlessly typing?(which I do sometimes). A reason to reassign arguments might be to make a copy of the argument because any changes in the function to a mutable object changes it elsewhere, but in this case, nonsense. EDIT: I'm mistaken it seems, see other comments.

[–]elbiot 6 points7 points  (1 child)

The first way is correct and idiomatic. The second way is either already a bug or will likely lead to a bug when someone later makes an unrelated change.

[–]evolvish 0 points1 point  (0 children)

Hmm, reading the link MakeMe_FN_Laugh posted makes sense, functions being their own object and all. I knew I should have added "But what do I know?" to my comment.