Python technique 2: advanced usage of function parameters

Time:2021-10-19

1. Keyword argument and keyword argument

Arguments to Python functionsWhen called(note that when it is not a function definition), parameters are passed in the form of keyword parameters and location parameters.

(1) Keyword parameters:

Keyword parameters refer to the parameters guided by the identifier (such as name =) or passed in a dictionary guided by * * when transferring parameters in a function call. As follows:

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

(2) Position parameters

Parameters that are not keyword parameters are location parameters. In addition to passing it separately, it can also be passed in an iterative sequence (list, tuple, etc.) guided by *. As follows:

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

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

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

Here arg1 and arg2 are location parameters, and kwarg1 and kwarg2 are keyword parameters.The key of the keyword parameter (that is, ‘kwarg1’ in ‘kwarg1 = 3’ and ‘kwarg2’ in ‘kwarg2 = 4’) should be consistent with the formal parameter name

2. Accept any number of parameters

(1) Accept any number of position parameters

The “*” expression can also be used in theFunction definitionIt is used in to define a function that can accept any number of position parameters, as shown below:

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

The parameter starting with “*” must be used as the last positional parameter, and the parameter starting with “*” is passed in as a tuple data structure.

(2) Accept any number of keyword parameters

To accept any number of keyword parameters, we can similarly use parameters starting with “* *”. As follows:

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 = '{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 ',' ') # escape will replace' 'in' 'here with a safe sequence < >
print(res_1) # Albatross 
print(res_2) # <spam>

The parameter starting with “* *” must be used as the last keyword parameter, and the parameter starting with “* *” is passed in as a dictionary data structure.

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

If you want the function to accept any number of positional and keyword parameters at the same time, just use “*” and “* *” together.

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 parameter

As mentioned earlier, the parameter starting with “*” can only be used as the last location parameter, and the parameter starting with “* *” can only be used as the last keyword parameter (which is naturally the last parameter). Therefore, the parameter after the parameter starting with “*” must be the keyword parameter.

#The parameters that appear after * args are called keyword only parameters
#In these two examples, y can only be a keyword parameter. When passing parameters, ensure the consistency between key and formal parameters
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 parameters, that is, parameters appearing after * args can only be used as keyword parameters.
We can make full use of this property, put the keyword parameter after the parameter starting with * or after a separate * and force the caller of the function to pass the keyword parameter, 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

This technique can be used in practical projects to specify keyword parameters for functions that accept any number of location parameters, such as the following minimum function with truncation function. The clip parameter here is forced to be passed in according to the keyword parameter, and a default value of none is set to make the parameter optional. As follows:

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, the keyword only parameter can improve the readability of the code. The function is written as follows:

msg = recv(1024, False)

If the reader of the code is not familiar with the working mode of the recv function, he may not understand the function of the false parameter here. If the call of this function can be written as follows, it will be much clearer (of course, the writer of this function needs to force the user of the function to write this at the beginning):

msg = recv(1024, block=False)

Finally, ifFunction definitionWhen the keyword only parameter is used, the parameter information can be displayed naturally when the user requests help information:

print(help(recv))
# Help on function recv in module __main__:

# recv(max_size, *_, block)
#     Receives a message

3. Optional parameters (parameters with default values)

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

def spam(a, b=42):
    print(a, b)
spam(1) # 1, 42
spam(1, 2) # 1, 2

If the default value is a variable container, such as list, set, dictionary, etc., you need to use none as the default value, as shown below:

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

Warning 1:Never write directly like this:

def spam(a, b=[]):

If you write as above, some unexpected phenomena will occur: if the default value is modified outside the function body, the modification will still haunt in subsequent function calls, as shown below:

def spam(a, b=[]):
    print(b)
    return b
x = spam(1)
x.append('oh!')
x.append('no!')
print(x)
spam(1)
# []
# ['oh!', 'no!']
# ['oh!', 'no!']

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 as follows:

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

The problem here is that although none will be judged as false, many other objects (such as strings with length of 0, lists, tuples, dictionaries, etc.) also have such 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 follows:

def spam(a, b=None):
    if not b:
        b = []
spam(1) # OK
x = []
spam(1, x) # Oops! x will be overwritten by default []
spam(1, 0) # Oops! 0 will be overwritten by default []
spam(1, '') # Oops! '' will be overwritten by default []

Finally, let’s discuss a very difficult problem. We want to check whether the caller provides a specific value for optional parameters in the function (it can be any value, and none also counts). In this way, we naturally can’t use none, 0 and false as the default values, and then do the detection again, because the user may take them as parameters.
To solve this problem, 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 a unique object created based on the object () class. You can use this to detect the parameters provided by the user, because it is almost impossible for the user to_ no_ Value object as parameter input (unless the user passes in the same object, even another object of object type is different from _no_value object).
Here is a brief description of the object class. Object is the base class of almost all objects in Python. The object object has no data (there is no _dict _ dictionary at the bottom, or even no property can be set). Its only function is to detect equality.

reference

  • [1] https://www.python.org/
  • [2] Martelli A, Ravenscroft A, Ascher D. Python cookbook[M]. ” O’Reilly Media, Inc.”, 2005.