Skip to content
Advertisement

Avoiding Default Argument Value is Mutable Warning (PyCharm) [duplicate]

Code:

def evaluate_fruit(fruits):
    for fruit in fruits:
        if fruit == "Apple":
            print("Good choice!")
        else:
            print("Meh its okay")
    
    
list_o_fruits = ["Apple", "Banana", "Orange"]
    
eval_list = (lambda x=list_o_fruits: evaluate_fruit(x))
    
eval_list()

Output:

Good choice!
Meh its okay
Meh its okay

When running the code above, the output is as expected however PyCharm doesn’t like it when I pass a list/dictionary (mutable) into the lambda function. To my understanding, it is bad practice to declare a list/dictionary as a function’s default value and that makes sense. However what if I only read the content of the list/dictionary and not alter it in any way inside the function, would it be acceptable then?

Either way, what would be a better approach to declare my lambda function with a list/dictionary argument? The web has suggested a workaround for passing a mutable as a default in a ‘normal’ function by setting the default to ‘None’ then using an if-statement:

def evaluate_fruits(fruits=None):
    if fruits is None:
        fruits = []
    .
    .
    .

I could possibly utilize this concept for lambda function too but then that would make the function inconveniently long and redundant as I would have to create an if-statement condition for each generated lambda from evaluate_fruits() (it kind of defeats the purpose of using lambda).

An example would be if I had five lists (list_o_fruits1, list_o_fruits2, …, list_o_fruits5) and I wanted to created a lambda function for each of them (eval_list1, eval_list2, …, eval_list3) from evaluate_fruits().

Could I be missing something?

Advertisement

Answer

If your only requirement is to bundle several elements together into one object, and that object doesn’t need to be mutable, use a tuple instead of a list. Tuples provide all the same behavior of lists except for modification of their elements. To be exact, mutable elements can still be mutated, but elements of the tuple cannot be assigned, added, or removed, and the tuple itself is considered an immutable data structure. The syntax for constructing a tuple is the same as a list, just with parentheses instead of square brackets:

# Immutable container with immutable elements, perfectly fine to use as a default argument
tuple_o_fruits = ("Apple", "Banana", "Orange")

Python’s lack of generic enforceable const-correctness is one of the few things that really irks me about the language. The standard solution is to use builtin immutable datatypes like tuple in place of mutable ones like list. The immutable form of set is frozenset, for example. Many common builtin types such as str, int, and float are only available in immutable form. bytes is an interesting case because the immutable form is better known than its mutable alternative, bytearray. The most prominent builtin mutable type that lacks an immutable alternative is dict (but it’s not hard to make your own).

So, the real answer to “how do I avoid warnings about mutable default arguments” is, 9 times out of 10, to not use a mutable object, because immutable alternative are generally readily available. This should be sufficient for your case.

Advertisement