Function Arguments in Python
Arguments are the values you pass to a function when you call it. Python matches them to parameters by position or by name, and defaults fill in missing ones. *args collects extra positional arguments, and **kwargs collects extra keyword arguments.
Key facts
- Positional arguments fill parameters in order. Keyword arguments, such as
age=36, fill them by name. def power(base, exponent=2):givesexponenta default, used when the call leaves it out.- A default is evaluated once, when
defruns, so a list default is shared by every call that uses it. UseNoneand create the list inside. *argscollects extra positional arguments into a tuple, and**kwargscollects extra keyword arguments into a dictionary.f(*items)passes a list as separate arguments, andf(**options)passes a dictionary as keyword arguments.
What are function arguments in Python?
Arguments are the values you pass to a function when you call it. Before the body runs, Python assigns each argument to a parameter, matching them by position or by name.
def describe(name, age):
print(f"{name} is {age} years old.")
describe("Ada", 36)
describe(age=36, name="Ada")Ada is 36 years old. Ada is 36 years old.
The first call passes positional arguments, so the first value goes to the first parameter. The second call passes keyword arguments such as age=36, which name the parameter they fill, so their order doesn't matter. Both calls give the function the same two values.
What is the difference between positional and keyword arguments?
A positional argument is matched by its place in the call, and a keyword argument by its name. One call can use both, as long as every positional argument comes first.
def describe(name, age):
print(f"{name} is {age} years old.")
describe(36, "Ada")
describe("Grace", age=85)36 is Ada years old. Grace is 85 years old.
Swapping the positional arguments raises no error here. Python fills the parameters in order, so the function prints nonsense. Keyword arguments prevent this when a call passes several values that could be mixed up. The second call mixes both kinds correctly, with the positional argument first.
You have used keyword arguments before. The sep and end arguments of print(), from the input and output lesson, are keyword arguments, and so is key in sort().
How do I give a parameter a default value?
Write the default after the parameter's name with an equals sign, as in exponent=2. A call can then leave that argument out, and the parameter takes the default.
def power(base, exponent=2):
return base ** exponent
print(power(5))
print(power(2, 10))
print(power(3, exponent=3))25 1024 27
Parameters with a default are optional, and parameters without one are required. A required parameter can't follow one with a default, so def power(exponent=2, base): is a SyntaxError. The one exception is a keyword-only parameter, which the *args section explains and the parameter order example shows.
PEP 8 recommends no spaces around the = in a default like this one and in a keyword argument.
Why does a default list keep its items between calls?
Python evaluates a default value once, when the def statement runs, not each time the function is called. Every call that uses the default gets that same object, so a default list collects the items from every earlier call that used it.
def add_item(item, items=[]):
items.append(item)
return items
print(add_item("a"))
print(add_item("b"))['a'] ['a', 'b']
You might expect the second call to return ['b'], but the list created when def ran still holds 'a'. The fix is a default of None and a new list created inside the function, where the code runs on every call.
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
print(add_item("a"))
print(add_item("b"))['a'] ['b']
The same trap applies to a dictionary or a set used as a default. Numbers, strings, None and tuples of them are safe defaults, because they can't be changed in place.
What does *args do in Python?
*args collects any number of extra positional arguments into a tuple. The star does the work, and args is only the usual name, so *numbers behaves the same way.
def total(*numbers):
print(numbers)
return sum(numbers)
print(total(1, 2, 3))
print(total())(1, 2, 3) 6 () 0
The three arguments arrive as the tuple (1, 2, 3), and a call with no arguments gets an empty tuple. print() is built the same way, so it accepts any number of values.
Any parameter after *args can only be passed by name, because the star collects every remaining positional argument. Such parameters are called keyword-only. The sep parameter of print() is one, so it must always be written as sep=.
def join_words(*words, sep=" "):
return sep.join(words)
print(join_words("red", "green", "blue"))
print(join_words("red", "green", "blue", sep=", "))red green blue red, green, blue
What does **kwargs do in Python?
**kwargs collects any extra keyword arguments into a dictionary. Each argument's name becomes a key, and its value becomes that key's value. The name kwargs, short for keyword arguments, is only a convention.
def show(title, **details):
print(title)
print(details)
show("Ada Lovelace", born=1815, field="mathematics")Ada Lovelace
{'born': 1815, 'field': 'mathematics'}The first argument fills title. The two keyword arguments match no parameter, so they end up in details. It's an ordinary dictionary, so you can loop over it with items() or read a value with get().
How do I pass a list or a dictionary as separate arguments?
Put * before a list or tuple in the call, or ** before a dictionary. Python unpacks the list's items into positional arguments and the dictionary's pairs into keyword arguments.
def describe(name, age):
print(f"{name} is {age} years old.")
person = ["Ada", 36]
describe(*person)
info = {"name": "Grace", "age": 85}
describe(**info)Ada is 36 years old. Grace is 85 years old.
describe(*person) makes the same call as describe("Ada", 36), and print(*range(1, 11)) uses the same star to print 1 to 10 on one line.
With describe(**info), a key that matches no parameter raises a TypeError about an unexpected keyword argument, and a missing key raises one about a missing argument.
What is the difference between *args and **kwargs?
*args collects extra positional arguments into a tuple, and **kwargs collects extra keyword arguments into a dictionary. A function can take both, with *args first.
def report(*args, **kwargs):
print(args)
print(kwargs)
report(1, 2, unit="cm")(1, 2)
{'unit': 'cm'}| Question | *args | **kwargs |
|---|---|---|
| What does it collect? | Extra positional arguments | Extra keyword arguments |
| What type is it? | A tuple, such as (1, 2) | A dictionary, such as {'unit': 'cm'} |
| Example call | report(1, 2) | report(unit="cm") |
| The star in a call | *items unpacks a list or tuple | **options unpacks a dictionary |
In what order do parameters go in a Python function?
Parameters without defaults come first, then ones with defaults, then *args, then keyword-only parameters, then **kwargs. Python checks the order when it reads the def line and reports a wrong order as a SyntaxError before anything runs.
def order(a, b=2, *args, c, d=4, **kwargs):
print(a, b, args, c, d, kwargs)
order(1, 3, 5, 6, c=7, e=8)1 3 (5, 6) 7 4 {'e': 8}The 1 and 3 fill a and b, and the 5 and 6 go to args. c is keyword-only, so it must be passed by name, and it's allowed to have no default even though b has one. d keeps its default of 4, and e matches no parameter, so it lands in kwargs. Few real functions use every kind at once.
Common mistakes with function arguments in Python
Besides the missing-argument TypeError from the functions lesson, these four messages come up often, shown here for greet(name, greeting="Hello"). The SyntaxError appears before any line of the program runs.
- TypeError: greet() takes from 1 to 2 positional arguments but 3 were given. The call passed more positional values than the function has parameters for. Remove the extra value, or add a parameter or
*argsto collect it. - TypeError: greet() got an unexpected keyword argument 'greting'. A keyword argument's name matches no parameter, here because of a typo. When a parameter's name is close, Python adds a suggestion such as
Did you mean 'greeting'? - TypeError: greet() got multiple values for argument 'name'. The same parameter was filled twice, once by position and once by name, as in
greet("Ada", name="Ada"). - SyntaxError: positional argument follows keyword argument. A positional argument came after a keyword argument in the call. Put every positional argument first.
Run the two broken programs to see the messages, then fix them in the editor.
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Ada", greting="Hi")Traceback (most recent call last):
File "main.py", line 4, in <module>
greet("Ada", greting="Hi")
~~~~~^^^^^^^^^^^^^^^^^^^^^
TypeError: greet() got an unexpected keyword argument 'greting'. Did you mean 'greeting'?def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet(greeting="Hi", "Ada") File "main.py", line 4
greet(greeting="Hi", "Ada")
^
SyntaxError: positional argument follows keyword argumentExercise
Give greeting a default value of "Hello" without changing the calls, so the program prints Hello, Ada! and then Hi, Grace! on two lines. The starter stops with a TypeError, because the first call leaves out a required argument.
def greet(name, greeting):
print(f"{greeting}, {name}!")
greet("Ada")
greet("Grace", "Hi")
Hello, Ada! Hi, Grace!
Show the solution
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Ada")
greet("Grace", "Hi")
Quiz
This quiz has 5 questions. Pick an answer to see why it is right or wrong.
-
1What does this program print?
def f(a, b=2): return a + b print(f(1))The call leaves out b, so b takes its default of 2, and 1 + 2 is 3. Only a is required, because b has a default.
-
2What does this program print?
def count(*args): return len(args) print(count("a", "b", "c"))*args collects all three arguments into the tuple ('a', 'b', 'c'), and len() counts its three items.
-
3What does this program print?
def f(**kwargs): print(type(kwargs)) f(x=1)**kwargs collects keyword arguments into a dictionary, here {'x': 1}. It is *args that collects positional arguments into a tuple.
-
4What does this program print?
def add(x, items=[]): items.append(x) return items add(1) print(add(2))The default list is created once, when def runs, and both calls append to that same list. Use None as the default and create the list inside the function to get [2].
-
5A function is defined as def f(a, b). Which of these calls is a syntax error?
A positional argument cannot follow a keyword argument, so f(a=1, 2) is a SyntaxError before anything runs. The other three calls fill a and b once each.























