Advanced usage of Python function parameters

  • 2021-12-09 09:08:53
  • OfStack

Directory 1, Keyword Parameters and Position Parameters (1) Keyword Parameters (2) Position Parameters 2, Accept Any Number of Parameters (1) Accept Any Number of Position Parameters
(2) Accept any number of keyword parameters (3) Accept any number of position parameters and keyword parameters 3, keyword-only parameters 3, optional parameters (parameters with default values)

1. Keyword parameters and position parameters

Keyword parameters ( positional argument ) and position parameters ( keyword argument )

Python The parameters of a function are divided into keyword parameters and positional parameters according to the form of parameters passed by the function when it is called (note that it is not when the function is defined).

(1) Keyword parameters

Keyword parameters are defined by identifiers such as name= ), or pass it in a dictionary booted by * * as follows:


complex(real=3, imag=5)
complex(**{'real': 3, 'imag': 5})

(2) Position parameters

A parameter that is either a keyword parameter or a position parameter. In addition to passing alone it can be passed in an iterative sequence (lists tuples and so on) booted by *. As shown below:


complex(3, 5)
complex(*(3, 5))

The positional parameter is always placed at the top of the argument list of the function, and the keyword parameter must be placed after the positional parameter. The positional relationship between them is as follows:


def func(arg1, arg2, kwarg1, kwarg2):
func(1, 2, kwarg1=3, kwarg2=4)

Here arg1 , arg2 Is a position parameter, kwarg1 , kwarg2 Is a keyword parameter. Keyword parameter key (That is, here 'kwarg1=3' In keyword argument0 , 'kwarg2=4' In ' kwarg2' ) Be sure to match the parameter name 1.

2. Accept any number of parameters

(1) Accept any number of position parameters

The "*" expression can be used in function definitions to define a function that can accept any number of positional parameters, in addition to splitting iterative objects of any length we talked about in Chapter 1, as follows:


def avg(first, *rest):
    print(rest)  
    return (first + sum(rest)) / (1 + len(rest))
print(avg(1, 2, 3, 4, 5))
# (2, 3, 4, 5)
# 1. 5


Parameters beginning with "*" must be used as the last position parameter, and the parameters beginning with "*" are tuple data structures after being passed in.

(2) Accept any number of keyword parameters

To accept any number of keyword parameters, we can similarly use "**" The parameter at the beginning of the. As shown below:


import html
def make_element(name, value, **attrs) -> str:
    key_values = [ ' %s="%s"' % item for item in attrs.items()]
    attr_str = ''.join(key_values)
    # Perform a string formatting operation. 
    element = '<{name} {attrs}>{value}</{name}>'.format(name=name, attrs=attr_str, value=html.escape(value))
    return  element

res_1 = make_element('item', 'Albatross', size='large', quantity=6)
res_2 = make_element('p', '<spam>') # escape Will put here '<spam>' In '<' And '>' Replace it with a safe sequence < >
print(res_1) # <item  size="large" quantity="6">Albatross</item> 
print(res_2) # <p ><spam></p>

"**" The parameter at the beginning must be used as the last 1 keyword parameter, and "**" The first parameter is passed in as a dictionary data structure.

(3) Accept any number of position parameters and keyword parameters at the same time

If you want a function to accept any number of positional and keyword arguments at the same time, just use the "*" And "**" That's enough.


def anyargs(*args:tuple, **kwargs:dict):
    print(args)
    print(kwargs)
anyargs(2, 3, 4, 5, time=1, data=2)
# (2, 3, 4, 5)
# {'time': 1, 'data': 2}

3. keyword-only parameters

As I said earlier, "*" The first parameter can only be used as the last position parameter, "**" The parameter at the beginning can only be used as the last keyword parameter (naturally, it is also the last parameter), and it is inferred that the parameter after the parameter at the beginning of "*" must be a keyword parameter.


#  Appear in *args The following parameter is called keyword-only Parameter 
#  In these two examples, y They can only be keyword parameters, and must be guaranteed when transferring parameters key And formal parameter 1 Pathogenic 
def a(x, *args, y):
    print(y)
def b(x, *args, y, **kwargs):
    print(y)

a(4, 6, 7, 8, y=1)
b(4, 6, 7, 3, y=1, data=2, year=3)

# 1
# 1

Such parameters are called keyword-only Parameter, that is, it appears in * args Subsequent parameters can only be used as keyword parameters.

We can take full advantage of this 1 property by placing keyword arguments after arguments that start with *, or after a separate *, forcing the caller of the function to pass keyword arguments, such as the following:


def recv(max_size, *, block):
    'Receives a message'
    pass

recv(1024, True)  # recv2() takes 1 positional argument but 2 were given
# and missing 1 required keyword-only argument: 'block'
recv(1024, block=True) # OK

In real projects, this technique can be used to specify keyword parameters for functions that accept any number of positional parameters, such as the following minimization function with truncation. Here's clip Parameter is forced to be passed in as a keyword parameter, and a default value is set None Make the parameter optional. As shown below:


def mininum(*values, clip=None):
    m = min(values)
    if clip is not None:
        m = clip if clip > m else m
    return m

res1 = mininum(1, 5, 2, -5, 10)
res2 = mininum(1, 5, 2, -4, 10, clip=0) 
print(res1, res2) # -5, 0

In addition, keyword-only Parameters can improve code readability, such as the following function writing:


msg = recv(1024, False)

If the reader of the code is not familiar with it recv Function works, so you may not quite understand the False It would be much clearer if the call to this function could be written as follows (of course, the writer of this function should force the user of this function to write this from the beginning):


complex(3, 5)
complex(*(3, 5))

0

Finally, if the function is defined when it is forced to use keyword-only Parameter, then when the user requests help information, the parameter information can naturally appear:


complex(3, 5)
complex(*(3, 5))

1

3. Optional parameters (parameters with default values)

To define an optional parameter, you need to assign a value to the parameter in the function definition and ensure that the default parameter appears at the end of the parameter list. Like this:


complex(3, 5)
complex(*(3, 5))

2

If the default value is a mutable container, such as a list, collection, dictionary, etc., you need to set the None As the default value: as follows:


def spam(a, b=None):
    if b is None:
        b = []

Warning 1: Never write directly like the following:


complex(3, 5)
complex(*(3, 5))

4

If you write as above, something you don't expect to see happens: If the default value is modified outside the function body, the modification will still haunt the subsequent function call, as shown below:


complex(3, 5)
complex(*(3, 5))

5

Warning 2: In the function body, we often need to judge whether the parameter is None. Here, we need to use the is operator. Never write it directly like the following:


complex(3, 5)
complex(*(3, 5))

6

The problem here is that although None Will be judged as False However, there are many other objects (such as strings of length 0, lists, tuples, dictionaries, and so on) that also have this behavior. In this way, many other specific inputs will also be judged as False, and then the value that should have been passed in by the user will be directly overwritten by the default []. As shown below:


complex(3, 5)
complex(*(3, 5))

7

Finally, let's discuss a very difficult problem. We want to detect in the function whether the caller supplied a specific value for the optional parameter (which can be arbitrary, None In this way, we can't use it naturally None , 0 , False Use them as defaults and then test them again, because users themselves may take them as parameters.

To solve this problem, you can write as follows:


_no_value = object()
def spam(a, b=_no_value):
    if b == _no_value:
        print("No b value supplied")
        return
    print(a, b)
spam(1) # No b value supplied
spam(1, 2) # 1 2
spam(1, None) # 1 None


Here _no_value Is based on object() Class, which can be used to detect the parameters provided by the user, because it is almost impossible for the user to put _no_value Object as parameter input (unless the user passes in the same object, even if it is object The other 1 object of type is the same as the _no_value Objects are different).

Here is a brief description of 1 object Class, object Yes Python The base class for almost all objects in, object Object does not have any data (the bottom layer is missing __dict__ Dictionary, can't even set any properties), its only function of 1 is to detect equality.


Related articles: