What is the purpose and use of **kwargs?

前端 未结 13 2219
伪装坚强ぢ
伪装坚强ぢ 2020-11-21 04:59

What are the uses for **kwargs in Python?

I know you can do an objects.filter on a table and pass in a **kwargs argument. &nbs

相关标签:
13条回答
  • 2020-11-21 05:47
    • kwargs in **kwargs is just variable name. You can very well have **anyVariableName
    • kwargs stands for "keyword arguments". But I feel they should better be called as "named arguments", as these are simply arguments passed along with names (I dont find any significance to the word "keyword" in the term "keyword arguments". I guess "keyword" usually means words reserved by programming language and hence not to be used by the programmer for variable names. No such thing is happening here in case of kwargs.). So we give names param1 and param2 to two parameter values passed to the function as follows: func(param1="val1",param2="val2"), instead of passing only values: func(val1,val2). Thus, I feel they should be appropriately called "arbitrary number of named arguments" as we can specify any number of these parameters (that is, arguments) if func has signature func(**kwargs)

    So being said that let me explain "named arguments" first and then "arbitrary number of named arguments" kwargs.

    Named arguments

    • named args should follow positional args
    • order of named args is not important
    • Example

      def function1(param1,param2="arg2",param3="arg3"):
          print("\n"+str(param1)+" "+str(param2)+" "+str(param3)+"\n")
      
      function1(1)                      #1 arg2 arg3   #1 positional arg
      function1(param1=1)               #1 arg2 arg3   #1 named arg
      function1(1,param2=2)             #1 2 arg3      #1 positional arg, 1 named arg
      function1(param1=1,param2=2)      #1 2 arg3      #2 named args       
      function1(param2=2, param1=1)     #1 2 arg3      #2 named args out of order
      function1(1, param3=3, param2=2)  #1 2 3         #
      
      #function1()                      #invalid: required argument missing
      #function1(param2=2,1)            #invalid: SyntaxError: non-keyword arg after keyword arg
      #function1(1,param1=11)           #invalid: TypeError: function1() got multiple values for argument 'param1'
      #function1(param4=4)              #invalid: TypeError: function1() got an unexpected keyword argument 'param4'
      

    Arbitrary number of named arguments kwargs

    • Sequence of function parameters:
      1. positional parameters
      2. formal parameter capturing arbitrary number of arguments (prefixed with *)
      3. named formal parameters
      4. formal parameter capturing arbitrary number of named parameters (prefixed with **)
    • Example

      def function2(param1, *tupleParams, param2, param3, **dictionaryParams):
          print("param1: "+ param1)
          print("param2: "+ param2)
          print("param3: "+ param3)
          print("custom tuple params","-"*10)
          for p in tupleParams:
              print(str(p) + ",")
          print("custom named params","-"*10)
          for k,v in dictionaryParams.items():
              print(str(k)+":"+str(v))
      
      function2("arg1",
                "custom param1",
                "custom param2",
                "custom param3",
                param3="arg3",
                param2="arg2", 
                customNamedParam1 = "val1",
                customNamedParam2 = "val2"
                )
      
      # Output
      #
      #param1: arg1
      #param2: arg2
      #param3: arg3
      #custom tuple params ----------
      #custom param1,
      #custom param2,
      #custom param3,
      #custom named params ----------
      #customNamedParam2:val2
      #customNamedParam1:val1
      

    Passing tuple and dict variables for custom args

    To finish it up, let me also note that we can pass

    • "formal parameter capturing arbitrary number of arguments" as tuple variable and
    • "formal parameter capturing arbitrary number of named parameters" as dict variable

    Thus the same above call can be made as follows:

    tupleCustomArgs = ("custom param1", "custom param2", "custom param3")
    dictCustomNamedArgs = {"customNamedParam1":"val1", "customNamedParam2":"val2"}
    
    function2("arg1",
          *tupleCustomArgs,    #note *
          param3="arg3",
          param2="arg2", 
          **dictCustomNamedArgs     #note **
          )
    

    Finally note * and ** in function calls above. If we omit them, we may get ill results.

    Omitting * in tuple args:

    function2("arg1",
          tupleCustomArgs,   #omitting *
          param3="arg3",
          param2="arg2", 
          **dictCustomNamedArgs
          )
    

    prints

    param1: arg1
    param2: arg2
    param3: arg3
    custom tuple params ----------
    ('custom param1', 'custom param2', 'custom param3'),
    custom named params ----------
    customNamedParam2:val2
    customNamedParam1:val1
    

    Above tuple ('custom param1', 'custom param2', 'custom param3') is printed as is.

    Omitting dict args:

    function2("arg1",
          *tupleCustomArgs,   
          param3="arg3",
          param2="arg2", 
          dictCustomNamedArgs   #omitting **
          )
    

    gives

    dictCustomNamedArgs
             ^
    SyntaxError: non-keyword arg after keyword arg
    
    0 讨论(0)
  • 2020-11-21 05:48

    You can use **kwargs to let your functions take an arbitrary number of keyword arguments ("kwargs" means "keyword arguments"):

    >>> def print_keyword_args(**kwargs):
    ...     # kwargs is a dict of the keyword args passed to the function
    ...     for key, value in kwargs.iteritems():
    ...         print "%s = %s" % (key, value)
    ... 
    >>> print_keyword_args(first_name="John", last_name="Doe")
    first_name = John
    last_name = Doe
    

    You can also use the **kwargs syntax when calling functions by constructing a dictionary of keyword arguments and passing it to your function:

    >>> kwargs = {'first_name': 'Bobby', 'last_name': 'Smith'}
    >>> print_keyword_args(**kwargs)
    first_name = Bobby
    last_name = Smith
    

    The Python Tutorial contains a good explanation of how it works, along with some nice examples.

    <--Update-->

    For people using Python 3, instead of iteritems(), use items()

    0 讨论(0)
  • 2020-11-21 05:49

    In Java, you use constructors to overload classes and allow for multiple input parameters. In python, you can use kwargs to provide similar behavior.

    java example: https://beginnersbook.com/2013/05/constructor-overloading/

    python example:

    class Robot():
        # name is an arg and color is a kwarg
        def __init__(self,name, color='red'):
            self.name = name
            self.color = color
    
    red_robot = Robot('Bob')
    blue_robot = Robot('Bob', color='blue')
    
    print("I am a {color} robot named {name}.".format(color=red_robot.color, name=red_robot.name))
    print("I am a {color} robot named {name}.".format(color=blue_robot.color, name=blue_robot.name))
    
    >>> I am a red robot named Bob.
    >>> I am a blue robot named Bob.
    

    just another way to think about it.

    0 讨论(0)
  • 2020-11-21 05:57

    Motif: *args and **kwargs serves as a placeholder for the arguments that need to be passed to a function call

    using *args and **kwargs to call a function

    def args_kwargs_test(arg1, arg2, arg3):
        print "arg1:", arg1
        print "arg2:", arg2
        print "arg3:", arg3
    

    Now we'll use *args to call the above defined function

    #args can either be a "list" or "tuple"
    >>> args = ("two", 3, 5)  
    >>> args_kwargs_test(*args)
    

    result:

    arg1: two
    arg2: 3
    arg3: 5


    Now, using **kwargs to call the same function

    #keyword argument "kwargs" has to be a dictionary
    >>> kwargs = {"arg3":3, "arg2":'two', "arg1":5}
    >>> args_kwargs_test(**kwargs)
    

    result:

    arg1: 5
    arg2: two
    arg3: 3

    Bottomline : *args has no intelligence, it simply interpolates the passed args to the parameters(in left-to-right order) while **kwargs behaves intelligently by placing the appropriate value @ the required place

    0 讨论(0)
  • 2020-11-21 05:57

    Here's a simple function that serves to explain the usage:

    def print_wrap(arg1, *args, **kwargs):
        print(arg1)
        print(args)
        print(kwargs)
        print(arg1, *args, **kwargs)
    

    Any arguments that are not specified in the function definition will be put in the args list, or the kwargs list, depending on whether they are keyword arguments or not:

    >>> print_wrap('one', 'two', 'three', end='blah', sep='--')
    one
    ('two', 'three')
    {'end': 'blah', 'sep': '--'}
    one--two--threeblah
    

    If you add a keyword argument that never gets passed to a function, an error will be raised:

    >>> print_wrap('blah', dead_arg='anything')
    TypeError: 'dead_arg' is an invalid keyword argument for this function
    
    0 讨论(0)
  • 2020-11-21 05:58

    Unpacking dictionaries

    ** unpacks dictionaries.

    This

    func(a=1, b=2, c=3)
    

    is the same as

    args = {'a': 1, 'b': 2, 'c':3}
    func(**args)
    

    It's useful if you have to construct parameters:

    args = {'name': person.name}
    if hasattr(person, "address"):
        args["address"] = person.address
    func(**args)  # either expanded to func(name=person.name) or
                  #                    func(name=person.name, address=person.address)
    

    Packing parameters of a function

    def setstyle(**styles):
        for key, value in styles.iteritems():      # styles is a regular dictionary
            setattr(someobject, key, value)
    

    This lets you use the function like this:

    setstyle(color="red", bold=False)
    
    0 讨论(0)
提交回复
热议问题