1

I have a function (which I'll call foo) that modifies a list (which I'll call my_list). foo does not always want to modify my_list in the same way; its behavior should influenced by its other arguments (which I'll call other_inputs). Here's some pseudocode:

def foo(my_list, other_inputs):
    for input in other_inputs:
        my_list.bar(input)
    return my_list

I can see two ways to format other_inputs.

I could use *args:

def foo(my_list, *other_inputs):
    for input in other_inputs:
        my_list.bar(input)
    return my_list

Alternately, I could make other_inputs a list, empty by default:

def foo(my_list, other_inputs=[]):
    for input in other_inputs:
        my_list.bar(input)
    return my_list

I've tested it on my machine and both options seem to do the same thing. Which one is preferable?

(Assume that this foo() is called many times, each time with a new other_inputs read in from some external source. Also assume that other_inputs is never appended to or mutated in any other way between external reads, so this isn't a problem.)

4
  • 2
    It depends on how you want to call foo: foo(some_list, a, b, c) or foo(some_list, [a, b, c]). Commented Aug 20, 2015 at 16:30
  • 2
    [this answer][1] explains why mutable default args are a bad idea [1]: stackoverflow.com/q/1132941/473285 Commented Aug 20, 2015 at 16:30
  • @scytale: he linked that answer in his last sentence.. Commented Aug 20, 2015 at 16:31
  • 4
    I think the default empty list approach is a bad idea because of the well-known mutating problem which you refer to. Even if currently your code doesn't mutate it you might in the future modify the code in a way that does. Why place minefields in your backyard just because you don't currently use that part of the yard? Commented Aug 20, 2015 at 16:34

2 Answers 2

1

Since you are reading other_inputs from another source, you presumably already have a sequence. That argues for the second approach:

def foo(my_list, other_inputs=None):
    if other_inputs is not None:
        # Assume other_inputs is some type of iterable
        for input in other_inputs:
            my_list.bar(input)
    return my_list

However, you could still use the first approach and call foo with

foo(some_list, *inputs)

It's mostly a matter of preference.

Sign up to request clarification or add additional context in comments.

2 Comments

In my particular case, I think this is the correct answer. Future readers, if you are not CERTAIN that you will never modify your code to edit the list other_inputs, then follow the advice in John Coleman's comment on my question and use *args.
Note that John Coleman wasn't arguing against a list input, just against using a list as the argument default in the function definition.
0

Obviously both of the options are correct, it would be wrong to say one of them is not.

If all other arguments passing to be function are of same type(by same type means they all change input then), then both approaches are equivalent. It is just a matter of preference as suggested by @chepner

But if there is some additional argument (say , expected length of output) which is going to be used differently from other params, then using list explicitly would be a better design.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.