Home > database >  Function to calculate the sum of numbers defined in a list and in a dictionary in python / using * a
Function to calculate the sum of numbers defined in a list and in a dictionary in python / using * a

Time:07-12

Given a list and a dictionary, I want to calculate the sum of its elements. Here's how I tried to do it

def sum(*arg , **argv):
    S=0
    for i , j in arg, list(argv.values()):
      S = i   j
    return S

li=[1,2]
dic={'a':1 , 'b':2}
print(sum(li,dic))

But I get this error : TypeError: can only concatenate list (not "dict") to list what's the problem ?

Remarque: I'm writing this code just because I'm trying to understand the * and ** in python

CodePudding user response:

If you print out the values of arg and argv in the function, you will see that the value of arg is ([1, 2], {'a': 1, 'b': 2}) while the value of argv is an empty dict {}, which is most likely not what you intended. Now there are multiple problems with that you are trying to do.

First, sum is already a builtin function in Python, so it is bad practice to redefine it. Though this is not the issue that is causing your code to error.

Second, let's take a look at the for loop more closely:

for i , j in arg, list(argv.values()):
  S = i   j

Note that arg is ([1, 2], {'a': 1, 'b': 2}) and argv is {}, which means list(argv.values()) is an empty list [] (at least for your example function call). Instead of calling S = i j, we will print out i and j to see what their values are:

for i , j in arg, list(argv.values()):
  print(i)
  print(j)

If you run this, it will print out [1, 2] (which is i) and {'a': 1, 'b': 2} (which is j), and then end in an error:

ValueError: not enough values to unpack (expected 2, got 0)

Now we see what the problem is. In the first pass through the loop, arg is unpacked, which causes i and j to be assigned the values of the first and second elements of arg respectively. So when S = i j is ran, it will run into an error when trying to compute i j, because i is a list while j is a dict.

And the reason why we got the ValueError when we took out S = i j was because on the second iteration of the loop, it attempts to unpack list(argv.values()), but it is an empty list, so it can't be unpacked into two values.

Third, one last reason why your code won't work is because you initialized S to have a value of 0, which is an integer. Even if, miraculously, i and j were both lists, the code will still fail due to not being able to add an integer with a list:

TypeError: unsupported operand type(s) for  =: 'int' and 'list'

With all that in mind, here are a few fixes I recommend:

First, change your function name to something else, other than sum, so that it doesn't conflict with the builtin sum function. I will change it to arg_sum for now.

Second, to make sure arg and argv have the intended values, you will also need to include the unpack operators in the function call itself. Instead of arg_sum(li, dic), trying doing arg_sum(*li, **dic). You will see that arg has the value [1, 2] and that argv has the value {'a': 1, 'b': 2}, which is most likely what you intended.

Third, for i, j in arg, list(argv.values()) will unpack in unintended ways. With the fixes I've already mentioned above, i and j will have the values 1 and 2 respectively on the first iteration (arg gets unpacked into two values), and they will also be 1 and 2 respectively on the second iteration (list(argv.values()) gets unpacked into two values). Coincidentally, this will actually give you the correct result, but this is only because li and dic have only two values; it will throw a ValueError for any other length.

Instead, what you want is the zip function, which will pair the two lists element-wise. So i and j will take on the values of the first element of the two lists in the first iteration, the second element in the second iteration, and so on.

Taking all these fixes into account, here is the final, revised code:

def arg_sum(*arg, **argv):
 S = 0
 for i, j in zip(arg, list(argv.values())):
  S  = i j
 return S

li = [1, 2]
dic = {'a': 1, 'b': 2}
print(arg_sum(*li, **dic))
  • Related