0

in my experience the unpacking ** are useless

so please read my question and tell me why we use them or give me an example where the two asterisks are useful

why we use ** for unpacking in python functions while we can get the same result without them.

so,

dict1 = {"brand": "Ford", "model": "Mustang", "year": 1964}
def func(args):
    for i in args.items():
        print(i)

func(dict1)

the previous function will get the same result as the following

dict1 = {"brand": "Ford", "model": "Mustang", "year": 1964}
def func(**args):
    for i in args.items():
        print(i)

func(**dict1)
  • this is just a preference that a function accepts a dict or multiple arguments, a rule of thumb is that a function shouldn't have more than 3,4 arguments so if the function has more than that use dict instead. – mirhossein Feb 14 '21 at 02:10
  • What if a funtion takes multiple arguments? E.g., `func(a, b, **kwargs)`. – ghchoi Feb 14 '21 at 02:11
  • Answer [here](https://stackoverflow.com/questions/36901/what-does-double-star-asterisk-and-star-asterisk-do-for-parameters) – AnkurSaxena Feb 14 '21 at 02:14
  • [What is the rationale for closing "why" questions on language design?](https://meta.stackexchange.com/questions/170394/what-is-the-rationale-for-closing-why-questions-on-a-language-design) – Charles Duffy Feb 14 '21 at 02:16
  • Does this answer your question? [What does \*\* (double star/asterisk) and \* (star/asterisk) do for parameters?](https://stackoverflow.com/questions/36901/what-does-double-star-asterisk-and-star-asterisk-do-for-parameters) – Akshay Sehgal Feb 14 '21 at 02:28

2 Answers2

1

It's not an issue in your function because you are iterating over the passed dictionary explicitly but, for general cases, * is used for unpacking args and ** is used for unpacking kwargs / keyword arguments.


This can be seen by the results below -

  1. Unpacking keyword arguments with ** maps each key to the respective keyword argument. This returns the values for corresponding params as defined in the function.
def func(brand, model, year):
    return brand, model, year
    
dict1 = {"brand": "Ford", "model": "Mustang", "year": 1964}
print(func(**dict1))

#OUTPUT: ('Ford', 'Mustang', 1964)
  1. A single * unpacks the dictionary to its keys only. Therefore, when these are passed, the function returns the keys as strings. In this case, a proper data structure for passing params would be a list or tuple.
dict1 = {"brand": "Ford", "model": "Mustang", "year": 1964}
print(func(*dict1))

#OUTPUT: ('brand', 'model', 'year')
  1. Without unpacking, this scenario fails because model is expecting 3 parameters, but got only 1 (dictionary).
dict1 = {"brand": "Ford", "model": "Mustang", "year": 1964}
print(func(dict1))

#OUTPUT:
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-731-f73ee817438f> in <module>
      1 dict1 = {"brand": "Ford", "model": "Mustang", "year": 1964}
----> 2 print(func(dict1))

TypeError: func() missing 2 required positional arguments: 'model' and 'year'
Akshay Sehgal
  • 18,741
  • 3
  • 21
  • 51
0

You usually wouldn't include **args in the API of a function which didn't need to integrate with anything else. You would usually use it to wrap/interact with another function in some way which doesn't care about exact argument behavior. E.g., consider the following contrived example:

@memoize
def f(a=0, b=0):
    if a==0: return b
    return a * f(a-1, b-a)

def memoize(f):
    cache = {}
    def _f(**kwargs):
        t = tuple(kwargs.items())
        if t not in cache:
            cache[t] = f(**kwargs)
        return cache[t]
    return _f

The main advantage of using **kwargs rather than passing in a dictionary is that the memoized function has exactly the same API as the function it's wrapping, so a caller can't reasonably distinguish between them.

As you pointed out, there isn't much functional difference in the two conventions from an implementation perspective -- the distinction lies in the API you're exposing to the outside world (performance can vary too, but as far as I'm concerned I don't think it'd worth paying attention to such small gains when contrasted with other approaches to improving performance). In some places it might not matter at all, and in others you might have good reason to choose one strategy over the other.

Hans Musgrave
  • 6,613
  • 1
  • 18
  • 37