Function parameters in Python

When defining a function in Python, we define the name and location of the parameter, and the function’s interface definition is completed.

For function callers, all you need to know is how to pass the correct parameters and what the function will return. The complex logic inside the function is encapsulated and the caller does not need to know it.

Python’s function definition is very simple, but the flexibility is very large.

In addition to the normally defined mandatory parameters, default parameters, mutable parameters, and keyword parameters can be used to define functions that define interfaces that can handle complex parameters and simplify the caller’s code.

Location parameters

Let’s first write a function that calculates x2:

def power(x):
    return x * x

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

When we call the power function, we have to pass in one and only one parameter, x:

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

Now, what if we want to calculate x3? Can redefine a power3 function, but if you want to calculate x4, x5 … … how to do? We can not define an infinite number of functions.

You may think of it, you can change the power (x) power (x, n), used to calculate xn, said dry:

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

For this modified power (x, n) function, any n-th power can be calculated:

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

The modified power (x, n) function has two parameters: x and n, both of which are position parameters. When the function is called, the two incoming values are assigned to the parameters x and n in the order of their positions.

Default parameters

The new power (x, n) function definition is fine, but the old calling code failed because we added a parameter that caused the old code to fail to call properly because of a missing parameter:

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

The Python error message is clear: the calling function power () is missing a positional parameter n.

This time, the default parameters came in handy. Since we often calculate x2, so it is entirely possible to set the default value of the second argument n to 2:

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

In this way, when we call power (5), it is equivalent to calling power (5, 2):

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

For other cases where n> 2, n must be explicitly passed in, such as power (5, 3).

As can be seen from the above example, the default parameters can simplify the function call. When setting the default parameters, there are several points to note:

First, the required parameters in the former, the default parameters in the post, otherwise the Python interpreter will error (think about why the default parameters can not be placed on the front of the required parameters);

Second, how to set the default parameters.

When the function has multiple parameters, put the parameters of the big changes in front of the small changes in parameters on the back. Small changes in the parameters can be used as the default parameters.

What are the benefits of using default parameters? The biggest advantage is to reduce the difficulty of calling functions.

For example, we write a grade pupil registration function, you need to pass in name and gender two parameters:

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

In this way, calling the enroll () function only requires passing in two parameters:

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

If you want to continue to pass age, city and other information how to do? This will make calling the complexity of the function greatly increased.

We can set age and city as the default parameters:

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

In this way, most students do not need to provide age and city when registering, but only provide the two required parameters::

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

Only students who do not match the default parameters need to provide additional information:

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

So, the default parameters reduce the difficulty of function calls, but once you need more complex calls, they can pass more parameters to achieve. Whether it is a simple call or a complex call, the function only needs to define one.

When there are multiple default parameters, the default parameters can be provided in order at the time of invocation, such as inviting enroll (‘Bob’, ‘M’, 7), meaning that except for the two parameters name and gender, the last one The parameter is applied to the age parameter, and the city parameter is still used because it is not provided.

Some of the default parameters may also be provided out of order. When not in order to provide some of the default parameters, the need to write the parameter name. For example, call enroll (‘Adam’, ‘M’, city = ‘Tianjin’), meaning that the city parameter is passed in, and other default parameters continue to use the default value.

The default parameters are useful, but not used properly, will fall pit. The default parameter has a maximum pit, demonstrated as follows:

First define a function, pass in a list, add an END and then return:

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

When you normally call the result looks good:

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

When you call with the default parameters, the first result is also correct:

>>> add_end()
['END']

However, when you call add_end () again, the result is incorrect:

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

Many beginners are wondering, the default argument is [], but the function seems to remember “the list that was last added ‘END’ each time.

The reason is explained as follows:

When the Python function is defined, the value of the default parameter L is calculated as [] because the default parameter L is also a variable that points to the object [], each time the function is called, and if the content of L is changed, The next time the call is made, the contents of the default parameters will change, no longer the [] function definition.

So, to define the default parameters to keep in mind: the default parameters must point to the same object!

To modify the above example, we can use None of this invariant object to achieve:

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’s no problem:

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

Why design str, None such a constant object? Because immutable objects once created, the data inside the object can not be modified, thus reducing the errors caused by modifying the data. In addition, the object does not change, multi-tasking environment at the same time read the object does not require locking, while reading a little problem. We write a program, if you can design a constant object, then try to design a constant object.

Variable parameters

In Python functions, you can also define variable parameters. As the name suggests, variable parameters is the number of arguments passed is variable, can be 1, 2 to any one, can also be 0.

Let’s take math problems as an example, given a set of numbers a, b, c …, calculate a2 + b2 + c2 + ……

To define this function, we must determine the parameters entered. Since the number of parameters is uncertain, we first think that it is possible to pass a, b, c … as a list or tuple, so that the function can be defined as follows:

 

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

But when calling, you need to assemble a list or tuple:

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

If you use variable parameters, the way to call the function can be simplified as follows:

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

So, let’s change the function’s parameters to mutable:

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

Defining mutable parameters Compared to defining a list or tuple parameter, just precede the argument with an asterisk. Inside the function, the numbers parameter receives a tuple, so the function code does not change at all. However, when calling this function, you can pass in any number of parameters, including 0 parameters:

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

If you already have a list or tuple, to call a variable parameter how to do? You can do this:

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

This wording is, of course, workable and the problem is too cumbersome, so Python allows you to add a * before the list or tuple and change the elements of the list or tuple into mutable arguments:

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

* nums means that all elements of the nums list are passed as mutable parameters. This writing is very useful, and very common.

Keyword parameters

Variables allow you to pass in 0 or any number of arguments, which are automatically assembled as a tuple when the function is invoked. The keyword parameter allows you to pass in 0 or any parameters with the parameter name, the keyword parameters automatically assembled within the function as a dict. Look at the example:

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

The function person accepts the keyword parameter kw in addition to the mandatory parameters name and age. When calling this function, you can only pass the required parameters:

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

You can also pass in any number of keyword parameters:

>>> 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'}

What is the use of keyword parameters? It can extend the function’s function. For example, in the person function, we guarantee that we get the two parameters, name and age, but we can also receive it if the caller is willing to provide more parameters. Imagine you are doing a user registration function, in addition to the user name and age are required, the other is optional, the use of keyword parameters to define this function can meet the registration requirements.

And similar to the variable parameters, you can also assemble a dict, and then convert the dict keyword parameters into it:

>>> 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 complex call above can be simplified to write:

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

** Extra means that all the key-values of the extra dict are passed to the ** kw parameter of the function using the keyword argument, kw will get a dict, noting that the kict dw is a copy of extra, the change to kw is not Will affect extra outside the function

Name the keyword argument

For keyword arguments, the caller of the function can pass in any unrestricted keyword argument. As for what exactly came in, you need to check kw inside the function.

Still taking the person () function as an example, we want to check if there are city and job parameters:

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

But callers can still pass in unrestricted keyword arguments:

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

If you want to limit the name of a keyword argument, you can use named keyword arguments, for example, to receive only city and job as keyword arguments. The function defined in this way is as follows:

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

Unlike the keyword argument ** kw, the named keyword argument requires a special delimiter *, and the arguments following * are treated as named keyword arguments.

The calling method is as follows:

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

If there is already a mutable parameter in the function definition, followed by the named keyword arguments no longer need a special delimiter *:

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

Named keyword parameters must pass in the name of the parameter, which is different from the location parameter. If there is no incoming parameter name, the call will complain:

>>> person('Jack', 24, 'Beijing', 'Engineer')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: person() takes 2 positional arguments but 4 were given

Due to the lack of parameters called city and job at the time of invocation, the Python interpreter treats all these four parameters as positional parameters, but the person () function accepts only two positional parameters.

Named keyword arguments can have default values to simplify calling:

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

Because the named keyword parameter city has a default value, when invoked, you can not pass in the city parameter:

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

When using named keyword arguments, pay particular attention to the fact that you must add * as a special delimiter if you do not have variable arguments. If * is missing, the Python interpreter will not recognize positional parameters and named keyword arguments:

def person(name, age, city, job):
    
    pass

Parameter combination

Define the function in Python, you can use the required parameters, default parameters, variable parameters, keyword parameters and named keyword parameters, these five parameters can be used in combination. However, note that the order in which the parameters are defined must be: mandatory, default, variable, named keyword, and keyword.

For example, define a function, including the above several parameters:

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)

At the time of the function call, the Python interpreter automatically passes in the corresponding parameters according to the parameter position and the parameter name.

>>> 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 is through a tuple and dict, you can also call the above function:

>>> 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': '#'}

So, for any function, it can be called with something like func (* args, ** kw), no matter how its parameters are defined.

summary

Python’s function has a very flexible parameter form, can achieve a simple call, but also can pass very complicated parameters.

The default parameters must use immutable objects, if it is a variable object, the program will run a logical error!

Pay attention to the syntax for defining variable parameters and keyword parameters:

* args is a variable argument, args receives a tuple;

** kw is the keyword argument, kw is receiving a dict.

And how to pass in the function of variable parameters and keyword parameters syntax:

Variables can either be passed in directly to func (1, 2, 3) or you can assemble a list or tuple first, followed by * args: func (* (1, 2, 3));

The keyword argument can either be passed directly to func (a = 1, b = 2), or assembled dict first, followed by ** kw: func (** {‘a’: 1, ‘b’: 2 }).

Using * args and ** kw is a Python convention, of course, you can use other parameter names, but it is best to use idioms.

The named keyword parameter is to limit the name of the parameter that the caller can pass in, and can provide the default value at the same time.

Defining Named Key Parameters Do not forget to write the delimiter * without variable arguments, otherwise the positional parameters will be defined.