Just beginning to learn python When , About args,kwargs, and * I'm confused about the use of . I believe there are many people who are confused about this . I intend to dispel this doubt through this post ( I hope it can reduce doubts ).
Let's go through the following 5 Step by step to understand :
1. Use a function call to understand ’*’ The role of
2. Understand by the definition of a function ’*args’ The meaning of
3. Understand through the call of a function ’**’ The role of
4. Solve through the definition of a function ’**kwargs’ The meaning of
5. An application example is given to illustrate ’args’,’kwargs’ Application scenarios and why use it
Define a function with three positional parameters ”fun”.
>>> def fun(a,b,c):
... print a,b,c
...
Pass three position parameters to call this function
>>> fun(1,2,3)
1 2 3 # Output
You can see that this function is called with three positional parameters , Three parameters will be printed
Now we define a sequence of three integers , And use ’*’
>>> l = [1,2,3]
>>> fun(*l)
1 2 3 # Output
It breaks down the sequence ’l’ As a position parameter , And pass these position parameters to the function ’fun’ To call .
So split the sequence 、 The transmission position parameter means fun(*l) And fun(1,2,3) It's equivalent , because l = [1,2,3].
Try using other values in the sequence
>>> l = [4,8,0]
>>> fun(*l)
4 8 0 # Output
Next, we try to put four numbers in the sequence , What happens when you call a function
>>> l = [3,6,9,1]
>>> fun(*l)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fun() takes exactly 3 arguments (4 given)
We didn't get the right result in this call , Triggered TypeWrror abnormal . It's easy to see the error content ”fun() takes exactly 3 arguments (4 given)”.
The sequence ’l’ Contains four values . therefore , We tried to call ’fun(*l)’,’l’ The middle value is split and passed to the function fun As a position parameter . however ,’l’ There are four values in , call ’fun(*l)’ Equivalent to calling ’fun(3,6,9,1)’, And because of the function ’fun’ Only three positional parameters are used in the definition , So we get this error . Empathy , The same procedure , The sequence ’l’ There are two numerical cases in , Be careful error Content .
>>> l = [7,4]
>>> fun(*l)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fun() takes exactly 3 arguments (2 given)
‘*l’ Mixed with position parameters
>>> fun(23, *l)
23 7 4
ad locum , We give a position parameter 23, And subsequence ’l’ Two values removed 7 and 4, So the three parameters 23,7 and 4 It's passed to the function ’fun’
Modify the definition of the function :
>>> def fun(*args):
... print args
...
Pass a position parameter to call this function
>>> fun(13)
(13,)
Pass multiple parameters to call this function
>>> fun(11,93,43)
(11, 93, 43)
It receives tuples as positional parameters , Instead of a common parameter list . ad locum ,”args” Is a tuple . Don't worry in our explanation ” Common parameters ” Understanding of this part , This will become clear in the following examples . In the last example , Call the function to print ”args” when , He will print all the values contained in the tuple .
Let's redefine the function ,”*args” And ” General parameter list ” A mixture of
>>> def fun(a, *args):
... print "a is ", a
... print "args is ", args
...
In this function definition , Parameters ”a” representative ” General parameter list ”.
Pass four position parameters to call this function :
>>> fun(11,12,34,43)
a is 11
args is (12, 34, 43)
It's easy to see ,’a’ Print out as 11, That is, the first position parameter .’a’ After that, there is only one parameter ’*args’. therefore ,’args’ Receive location parameters other than conventional parameters as tuples . So tuple args Receive as tuple 12,34 and 43.
We can also call this function by passing a positional parameter :
>>> fun(91)
a is 91
args is ()
ad locum , The only parameter we pass is assigned to the regular parameter ’a’. therefore ,’args’ Received an empty tuple .
Now that we have ”args”, We can extract the required values to do what we want to do . Redefinition ”fun”:
>>> def fun(a, *args):
... print a
... print "args can receive a tuple of any number of arguments, let's print all that."
... for arg in args:
... print arg
...
Now we call this function by passing any parameter :
>>> fun(1,5,6,7)
1
args can receive a tuple of any number of arguments, let's print all that.
5
6
7
‘args’ Since it is a tuple , We can traverse it .
Now let's consider a scenario that uses all available parameters . We need to use two functions , The first function takes any number of arguments , And calculate the sum of other parameters except the first parameter through another function . Strange use cases , But we just need to review what we have done so far . Our goal is to get variable parameters in a function , And give these parameters to another function .
The first step is to write a function to calculate and . In this use case , This function will be applied in the first function .
>>> def calculate_sum(*args):
... return sum(args)
...
In this function , We use built-in functions ’sum’, It uses tuples or sequences as arguments , Returns the sum of all elements of a tuple . From the definition of the function, we can see ’args’ Receive tuples containing positional parameters passed to this function . therefore ,’args’ It's a tuple , As a function ’sum’ Parameters of . Next, define another function , This function has any number of arguments , And use the previous function to calculate the sum of other parameters except the first parameter .
>>> def ignore_first_calculate_sum(a,*iargs):
... required_sum = calculate_sum(*iargs)
... print "sum is ", required_sum
...
We can pass any parameter to this function . The first parameter is called the regular parameter ’a’ receive , Other parameters are ’iargs’ Receive as tuple . As we consider the case , Calculate the sum of parameters other than the first parameter . therefore , We use it ’a’ Receive the first parameter ,’iargs’ Is a tuple containing other parameters . We use the function ’calculate_sum’, but ’calculate_sum’ Multiple location parameters are required to be passed to as tuples ’args’. So in function ’ignore_first_calculate_sum’ The tuple needs to be disassembled ’iargs’, Then pass the element as a positional parameter to ’calculate_sum’. Be careful , use ’*’ Disassembly tuple .
therefore , We call it this way ’required_sum=calculate_sum(*iargs)’.
‘required_sum=calculate_sum(iargs)’ You can't call , Because it's passed on to ’calculate_sum’ Before that, we needed unpack The number . Don't use ’*’ Will not unpack The number , You can't perform the desired action . Call the function as follows :
>>> ignore_first_calculate_sum(12, 1,4,5)
sum is 10
>>> ignore_first_calculate_sum()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ignore_first_calculate_sum() takes at least 1 argument (0 given)
Get the results you want .
Define a function with three parameters , And call... In many ways :
>>> def fun(a, b, c):
... print a, b, c
...
>>> fun(1,5,7)
1 5 7
>>> fun(a=1,b=5,c=7)
1 5 7
Use ”**” Call function , In this way, we need a dictionary . Be careful : Use... In function calls ”*”, We need tuples ; Use... In function calls ”**”, We need a dictionary
>>> d={'b':5, 'c':7}
>>> fun(1, **d)
1 5 7
it unpack Dictionaries , The data items in the dictionary are passed to the function as key parameters . therefore ,”fun(1, **d)” The writing and ”fun(1, b=5, c=7)” equivalent .
For a better understanding, give a few more examples :
>>> d = {'c':3}
>>> fun(1, 4, **d)
1 4 3
>>> d = {'a':7, 'b':3, 'c':8}
>>> fun(**d)
7 3 8
Let's make some mistakes :
>>> d = {'a':7, 'b':3, 'c':8, 'd':90}
>>> fun(**d)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fun() got an unexpected keyword argument 'd'
This call is equivalent to ’fun(a=7, b=3, c=8, d=90)’, But the function only needs three arguments , So we get TypeError
>>> d = {'a':7, 'b':3,'d':90}
>>> fun(**d)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fun() got an unexpected keyword argument 'd'
fun(**d) Equate to fun(a=7, b=3, d=90). Pass to function ”fun” The number of parameters you want , But there is no... In the parameter list ’d’, in call ’d’ A key value parameter passed to a function results in TypeError.
So, “*” unpacks the dictionary i.e the key values pairs in the dictionary as keyword arguments and these are sent as keyword arguments to the function being called. “” unpacks a list/tuple i.e the values in the list as positional arguments and these are sent as positional arguments to the function being called.
Redefining functions ”fun”:
>>> def fun(a, **kwargs):
... print a, kwargs
...
This function uses only one positional parameter , Because there is only one variable in the general parameter list ’a’. But by ”**kwargs”, Multiple key value parameters can be passed .
>>> fun(1, b=4, c=5)
1 {'c': 5, 'b': 4}
>>> fun(45, b=6, c=7, d=8)
45 {'c': 7, 'b': 6, 'd': 8}
In the definition of a function ”**kwargs” What does it mean ?
use ”**kwargs” Defined function ,kwargs Receive the key value parameter Dictionary of positions other than the general parameter list . ad locum ’kwargs’ It's a dictionary .
Redefine the function :
>>> def fun(a, **kwargs):
... print "a is ", a
... print "We expect kwargs 'b' and 'c' in this function"
... print "b is ", kwargs['b']
... print "c is ", kwargs['c']
...
>>> fun(1, b=3,c=5)
a is 1
We expect kwargs 'b' and 'c' in this function
b is 3
c is 5
Error call :
>>> fun(1, b=3, d=5)
a is 1
We expect kwargs 'b' and 'c' in this function
b is 3
c is
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in fun
KeyError: 'c'
The above call , Positional arguments ’a’ And key value parameters ’b’ It's all printed out . The other key value parameters passed in are ’d’, Function requires a key value argument ’c’, And from the dictionary ’kwargs’ obtain . But no key value was passed in ’c’, trigger KeyError. If a key value is passed in ’c’ Will not cause this error
>>> fun(1, b=3, d=5, c=9)
a is 1
We expect kwargs 'b' and 'c' in this function
b is 3
c is 9
because ’**kwargs’ In the function parameter list , We can pass any key value parameter . The above call passed in ”d”, But the function doesn't use .
Another mistake :
>>> fun(1, {'b':2, 'c':34})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fun() takes exactly 1 argument (2 given)
Just like the error prompt , function ’fun’ Only one positional parameter is required , And gave two . Even though ’kwargs’ Receive key value parameters as a dictionary , But you can't pass a dictionary as a positional parameter to ’kwargs’. You can call as follows :
>>> fun(1, **{'b':2, 'c':34})
a is 1
We expect kwargs 'b' and 'c' in this function
b is 2
c is 34
Use in front of a dictionary ”**” Sure unpack Dictionaries , Pass the data items in the dictionary as key value parameters .
Inheriting classes and overriding methods at any time , We should use ’*args’ and ’**kwargs’ Give the received positional parameters and key value parameters to the parent class method . Through examples, we can better understand
>>> class Model(object):
... def __init__(self, name):
... self.name = name
... def save(self, force_update=False, force_insert=False):
... if force_update and force_insert:
... raise ValueError("Cannot perform both operations")
... if force_update:
... print "Updated an existing record"
... if force_insert:
... print "Created a new record"
...
Define a class , We can create objects of classes , Class has a method ’save()’. Suppose that the objects of the class can pass through save() Method to the database . By function save() Parameter to determine whether to create a record in the database or update an existing record .
Construct a new class , Like ’Model’ act , But we only save the object of this class after checking some conditions . This new class inherits ’Model’, rewrite ’Model’ Of ’save()’
>>> class ChildModel(Model):
... def save(self, *args, **kwargs):
... if self.name=='abcd':
... super(ChildModel, self).save(*args, **kwargs)
... else:
... return None
...
In fact, the corresponding save action occurs in ’Model’ Of ’save’ In the method . So we call the subclass's ’save()’ Method, not ’Model’ Methods . Subclass ChildModel Of ’save()’ Receive any parent class save() Required parameters , And pass it to the parent class method . therefore , Subclass ’save()’ There are... In the method parameter list ”*args” and ”**kwargs”, They can receive any positional parameter or key value parameter , Except for the general parameter list .
Create below ChildModel Entity and save :
>>> c=ChildModel('abcd')
>>> c.save(force_insert=True)
Created a new record
>>> c.save(force_update=True)
Updated an existing record
Here, you can transfer part-time parameters to the object save() Method . It's subclass save(),It received a dictionary containing the keyword argument in “kwargs”. Then it used “**” to unpack this dictionary as keyword arguments and then passed it to the superclass save(). So, superclass save() got a keyword argument ‘force_insert’ and acted accordingly.