Reputation: 23283
I'm wondering if there's a way to add an argument to the default arguments a function takes.
For instance:
SOME_CITIES = ["Gotham","Chicago"]
def do_something(name, cities=SOME_CITIES):
for city in cities:
print(name, city)
do_something("Clark")
>> Clark Gotham
>> Clark Chicago
# Can I do something like this (pseudocode, obviously):
do_something("Clark", *["New York", "LA"])
>> Clark Gotham
>> Clark Chicago
>> Clark New York
>> Clark LA
The idea is do_something("Clark", *"New York")
would run through the function, doing Gotham
, Chicago
, and then the city I added, New York
.
This is similar from my understanding of **kwargs
, but that would look like:
def do_something(name, **kwargs):
# Code here...
do_something("Clark", SOME_CITIES, "New York")
But that requires me to recall to send SOME_CITIES
through, when I'd like to include that by default. Does that make sense?
Edit: The SOME_CITIES
may not always be a list. It could be two functions, i.e. SOME_FUNCTIONS = func1, func2
. Also - as some answers seem to get at below, if this is a bad idea and kwargs
/args
is better, that's fine too just let me know and explain a little :)
Upvotes: 0
Views: 89
Reputation: 1121346
Python has no syntax or behaviour to extend lists used as a default argument, no. You can simply use the *args
catch-all parameter here and concatenate in the function:
SOME_CITIES = ("Gotham", "Chicago")
def do_something(name, cities=SOME_CITIES, *further_cities):
for city in cities + further_cities:
print(name, city)
If the sequences are expected to be large, you could use itertools.chain()
instead of concatenation. Note the change to using tuples here, which avoids a common pitfall of using a mutable data type where you never intent to make changes to the value at runtime anyway.
You need to be extremely careful when using a list as a default argument value, see "Least Astonishment" and the Mutable Default Argument. In this specific case there is little point in avoiding it as SOME_CITIES
is also defined outside of the function and you have more options to alter that object, but you may want to consider using a None
sentinel instead:
SOME_CITIES = ["Gotham", "Chicago"]
def do_something(name, cities=None, *further_cities):
if cities is None:
# start with a base list
cities = SOME_CITIES
cities = cities + list(further_cities)
for city in cities:
print(name, city)
Upvotes: 2
Reputation: 71451
You can change your default parameter in your function to *args
, and then use functools.partial
:
import functools
SOME_CITIES = ["Gotham","Chicago"]
OTHER_CITIES = ["New York", "LA"]
def do_something(name, *cities):
for city in cities:
print(name, city)
new_funct = functools.partial(do_something, 'clark', *SOME_CITIES)
new_funct(*OTHER_CITIES)
Output:
clark Gotham
clark Chicago
clark New York
clark LA
Upvotes: 1