Skip to content

Function Parameters

When defining a function, we determine the names and positions of the parameters, thereby completing the function's interface definition. For the function's caller, it's sufficient to know how to pass the correct arguments and what kind of value the function will return. The complex internal logic of the function is encapsulated, and the caller does not need to understand it.

Python's function definitions are very simple, yet highly flexible. In addition to the standard required parameters, you can also use default parameters, variable parameters, and keyword parameters. This allows the function's interface to handle complex arguments while simplifying the caller's code.

Positional Parameters

Let's first write a function to calculate ( x^2 ):

python
def power(x):
    return x * x

For the power(x) function, the parameter x is a positional parameter.

When we call the power function, we must pass exactly one argument x:

python
>>> power(5)
25
>>> power(15)
225

Now, what if we need to calculate ( x^3 )? We could define another function power3, but what about ( x^4 ), ( x^5 ), and so on? It's impossible to define an infinite number of functions.

You might think of modifying power(x) to power(x, n) to calculate ( x^n ). Let's do that:

python
def power(x, n):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

With the modified power(x, n) function, we can calculate any exponent ( n ):

python
>>> power(5, 2)
25
>>> power(5, 3)
125

The modified power(x, n) function has two parameters: x and n. Both of these parameters are positional parameters. When calling the function, the two values passed are assigned to parameters x and n in order based on their positions.

Default Parameters

The new power(x, n) function definition is correct, but the old calling code fails because we added a parameter. The old code cannot call the function normally due to the missing parameter:

python
>>> power(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: power() missing 1 required positional argument: 'n'

Python's error message is clear: calling power() is missing a positional argument n.

This is where default parameters come into play. Since we often calculate ( x^2 ), we can set the default value of the second parameter n to 2:

python
def power(x, n=2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

Now, when we call power(5), it is equivalent to calling power(5, 2):

python
>>> power(5)
25
>>> power(5, 2)
25

For cases where ( n > 2 ), you must explicitly pass n, such as power(5, 3).

From the above example, we can see that default parameters can simplify function calls. When setting default parameters, keep the following points in mind:

  1. Required Parameters First: Required parameters must come first, followed by default parameters. Otherwise, the Python interpreter will raise an error (think about why default parameters cannot come before required parameters).
  2. How to Set Default Parameters: When a function has multiple parameters, place the parameters that change less frequently at the end. The less frequently changing parameters can be set as default parameters.

Benefits of Using Default Parameters: The main advantage is that it reduces the complexity of function calls.

For example, let's write a registration function for first-grade students, requiring name and gender as parameters:

python
def enroll(name, gender):
    print('name:', name)
    print('gender:', gender)

With this enroll() function, calling it only requires passing two arguments:

python
>>> enroll('Sarah', 'F')
name: Sarah
gender: F

What if you want to pass additional information like age and city? This would significantly increase the complexity of the function call.

We can set age and city as default parameters:

python
def enroll(name, gender, age=6, city='Beijing'):
    print('name:', name)
    print('gender:', gender)
    print('age:', age)
    print('city:', city)

Now, most students registering only need to provide the required two parameters:

python
>>> enroll('Sarah', 'F')
name: Sarah
gender: F
age: 6
city: Beijing

Only students who need to provide additional information can pass extra parameters:

python
enroll('Bob', 'M', 7)
enroll('Adam', 'M', city='Tianjin')

As seen, default parameters reduce the difficulty of function calls. When more complex calls are needed, additional parameters can be passed to achieve the desired functionality. Whether it's a simple call or a complex one, the function remains the same.

When there are multiple default parameters, you can provide default parameters in order, such as calling enroll('Bob', 'M', 7), meaning that in addition to the name and gender parameters, the last parameter is assigned to age, and since city is not provided, it uses the default value.

You can also provide some default parameters out of order by specifying parameter names. For example, calling enroll('Adam', 'M', city='Tianjin') means that the city parameter uses the provided value, while other default parameters continue to use their default values.

Caution with Default Parameters:

Default parameters are useful but can lead to pitfalls if not used properly. The biggest pitfall is demonstrated below:

First, define a function that takes a list, adds 'END', and returns it:

python
def add_end(L=[]):
    L.append('END')
    return L

When you call it normally, the results seem correct:

python
>>> add_end([1, 2, 3])
[1, 2, 3, 'END']
>>> add_end(['x', 'y', 'z'])
['x', 'y', 'z', 'END']

When you use the default parameter, the initial result is also correct:

python
>>> add_end()
['END']

However, calling add_end() again yields incorrect results:

python
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']

Many beginners are puzzled because the default parameter is [], but the function seems to "remember" the list after adding 'END'.

Explanation:

When a Python function is defined, the default parameter L is already evaluated as []. Since the default parameter L is also a variable pointing to the list object [], each time the function is called, if L is modified, the default parameter retains its changed state instead of being reset to [].

Important Note:

When defining default parameters, always remember: default parameters must point to immutable objects!

To fix the above example, you can use None, an immutable object:

python
def add_end(L=None):
    if L is None:
        L = []
    L.append('END')
    return L

Now, no matter how many times you call it, there are no issues:

python
>>> add_end()
['END']
>>> add_end()
['END']

Why Use Immutable Objects Like str and None:

Immutable objects cannot be altered once created, reducing errors caused by data modification. Additionally, since immutable objects cannot change, they do not require locking mechanisms in multi-tasking environments, allowing safe concurrent reads. When writing programs, if you can design an immutable object, do so.

Variable Parameters

In Python functions, you can also define variable parameters. As the name suggests, variable parameters allow for a variable number of arguments, which can be one, two, or any number, including zero.

Let's take a math problem as an example: Given a set of numbers ( a, b, c, \ldots ), calculate ( a^2 + b^2 + c^2 + \ldots ).

To define this function, we must determine the input parameters. Since the number of parameters is uncertain, we might think to pass ( a, b, c, \ldots ) as a list or tuple. Thus, the function can be defined as follows:

python
def calc(numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum

However, when calling the function, you need to assemble a list or tuple first:

python
>>> calc([1, 2, 3])
14
>>> calc((1, 3, 5, 7))
84

If you use variable parameters, you can simplify the function call as follows:

python
>>> calc(1, 2, 3)
14
>>> calc(1, 3, 5, 7)
84

Therefore, we can modify the function to accept variable parameters:

python
def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum

Defining variable parameters is similar to defining a list or tuple parameter, except for the asterisk * before the parameter name. Inside the function, the parameter numbers receives a tuple, so the function code remains unchanged. However, when calling the function, you can pass any number of arguments, including zero:

python
>>> calc(1, 2)
5
>>> calc()
0

How to Call a Function with a List or Tuple When Using Variable Parameters:

If you already have a list or tuple and want to pass it to a function with variable parameters, you can do the following:

python
>>> nums = [1, 2, 3]
>>> calc(nums[0], nums[1], nums[2])
14

This approach works, but it's too cumbersome. Therefore, Python allows you to add an asterisk * before the list or tuple to unpack its elements as variable parameters:

python
>>> nums = [1, 2, 3]
>>> calc(*nums)
14

*nums means that all elements of the list nums are passed as variable parameters to the function. This method is very useful and commonly used.

Keyword Parameters

Variable parameters allow you to pass zero or any number of arguments, which are automatically assembled into a tuple inside the function. Keyword parameters allow you to pass zero or any number of named arguments, which are automatically assembled into a dictionary inside the function. Here's an example:

python
def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)

The person function accepts required parameters name and age, and also accepts keyword parameters kw. When calling this function, you can pass only the required parameters:

python
>>> person('Michael', 30)
name: Michael age: 30 other: {}

Or you can pass any number of keyword parameters:

python
>>> person('Bob', 35, city='Beijing')
name: Bob age: 35 other: {'city': 'Beijing'}
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}

Benefits of Keyword Parameters: They allow you to extend the functionality of the function. For example, in the person function, we ensure that we receive name and age parameters, but if the caller wishes to provide more parameters, we can receive them as well. Imagine you are developing a user registration feature where only username and age are required, and other fields are optional. Defining the function using keyword parameters can satisfy the registration requirements.

How to Call a Function with a Dictionary When Using Keyword Parameters:

Similar to variable parameters, you can assemble a dictionary first and then pass it to the function using keyword parameters:

python
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, city=extra['city'], job=extra['job'])
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}

Of course, the above complex call can be simplified:

python
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}

**extra means that all key-value pairs in the dictionary extra are passed as keyword parameters to the function's **kw parameter. Note that the kw parameter receives a copy of the extra dictionary, and modifying kw inside the function does not affect the original extra outside the function.

Named Keyword Parameters

For keyword parameters, the caller can pass any unrestricted keyword arguments. To determine which parameters have been passed, the function must check kw internally.

Using the person() function as an example, suppose we want to check whether city and job parameters are provided:

python
def person(name, age, **kw):
    if 'city' in kw:
        # Has city parameter
        pass
    if 'job' in kw:
        # Has job parameter
        pass
    print('name:', name, 'age:', age, 'other:', kw)

However, the caller can still pass unrestricted keyword parameters:

python
>>> person('Jack', 24, city='Beijing', addr='Chaoyang', zipcode=123456)

To restrict the names of keyword parameters, you can use named keyword parameters, such as only accepting city and job as keyword parameters. Here's how to define such a function:

python
def person(name, age, *, city, job):
    print(name, age, city, job)

Unlike keyword parameters **kw, named keyword parameters require a special separator *. Parameters after * are treated as named keyword parameters.

Calling Methods:

python
>>> person('Jack', 24, city='Beijing', job='Engineer')
Jack 24 Beijing Engineer

If the function definition already includes a variable parameter, the named keyword parameters do not require the special separator *:

python
def person(name, age, *args, city, job):
    print(name, age, args, city, job)

Important: Named keyword parameters must be passed using parameter names, unlike positional parameters. If you don't pass the parameter names, the call will result in an error:

python
>>> person('Jack', 24, 'Beijing', 'Engineer')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: person() missing 2 required keyword-only arguments: 'city' and 'job'

Since the call is missing the parameter names city and job, the Python interpreter treats the first two arguments as positional parameters and assigns the last two arguments to *args, but the missing named keyword parameters result in an error.

Named Keyword Parameters with Default Values:

Named keyword parameters can have default values to simplify calls:

python
def person(name, age, *, city='Beijing', job):
    print(name, age, city, job)

Since the named keyword parameter city has a default value, you can omit it when calling the function:

python
>>> person('Jack', 24, job='Engineer')
Jack 24 Beijing Engineer

Special Note When Using Named Keyword Parameters:

When using named keyword parameters, especially without variable parameters, do not forget to include the separator *. Otherwise, Python will not recognize the positional parameters and named keyword parameters correctly:

python
def person(name, age, city, job):
    # Missing *, so city and job are treated as positional parameters
    pass

Parameter Combinations

In Python, you can define functions using required parameters, default parameters, variable parameters, keyword parameters, and named keyword parameters. These five types of parameters can be combined, but note that the order of parameter definitions must be:

  1. Required parameters
  2. Default parameters
  3. Variable parameters
  4. Named keyword parameters
  5. Keyword parameters

For example, defining a function that includes several of these parameter types:

python
def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

When calling these functions, the Python interpreter automatically assigns the passed arguments to the corresponding parameters based on their positions and names:

python
>>> f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}

The Most Amazing Part:

Using a tuple and a dictionary, you can also call the above functions:

python
>>> args = (1, 2, 3, 4)
>>> kw = {'d': 99, 'x': '#'}
>>> f1(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
>>> args = (1, 2, 3)
>>> kw = {'d': 88, 'x': '#'}
>>> f2(*args, **kw)
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}

Therefore, for any function, you can call it using the form func(*args, **kw), regardless of how its parameters are defined.

Tip:

Although you can combine up to five types of parameters, avoid using too many combinations simultaneously, as it can make the function's interface difficult to understand.

Exercise

The following function allows calculating the product of two numbers. Please modify it slightly to accept one or more numbers and calculate the product:

python
def mul(x, y):
    return x * y

# Tests
print('mul(5) =', mul(5))
print('mul(5, 6) =', mul(5, 6))
print('mul(5, 6, 7) =', mul(5, 6, 7))
print('mul(5, 6, 7, 9) =', mul(5, 6, 7, 9))
if mul(5) != 5:
    print('mul(5) test failed!')
elif mul(5, 6) != 30:
    print('mul(5, 6) test failed!')
elif mul(5, 6, 7) != 210:
    print('mul(5, 6, 7) test failed!')
elif mul(5, 6, 7, 9) != 1890:
    print('mul(5, 6, 7, 9) test failed!')
else:
    try:
        mul()
        print('mul() test failed!')
    except TypeError:
        print('Test passed!')

Summary

  • Python functions have highly flexible parameter forms, allowing for both simple calls and passing very complex arguments.
  • Default Parameters Must Point to Immutable Objects: If you use mutable objects as default parameters, the program may encounter logical errors during runtime!
  • Syntax for Defining Variable and Keyword Parameters:
    • *args is for variable parameters, and args receives a tuple.
    • **kw is for keyword parameters, and kw receives a dictionary.
  • Syntax for Calling Functions with Variable and Keyword Parameters:
    • Variable parameters can be passed directly: func(1, 2, 3), or assembled into a list or tuple and then passed using *args: func(*(1, 2, 3)).
    • Keyword parameters can be passed directly: func(a=1, b=2), or assembled into a dictionary and then passed using **kw: func(**{'a': 1, 'b': 2}).
  • Using *args and **kw is a Python convention: Although you can use other parameter names, it's best to follow conventional usage.
  • Named Keyword Parameters: They are used to restrict the names of parameters that callers can pass while providing default values.
    • When defining named keyword parameters without variable parameters, do not forget to include the separator *. Otherwise, Python will treat them as positional parameters.
Function Parameters has loaded