3

I am new to Python and I am struggling with the task of passing a dictionary, whose keys are tuples, as an argument to a function.

mydict = {('hostabc', 'pola'): 333444567, ('hostdef', 'polb'): 111222333, ('hostghi', 'polc'): 222999888}

def tupletest(**kwargs):
    print(kwargs)

tupletest(**mydict)

The following keyword error is generated:

TypeError                                 Traceback (most recent call last)
<ipython-input-29-fec409a1eb53> in <module>
      2 def tupletest(**kwargs):
      3     print(kwargs)
----> 4 tupletest(**mydict)

TypeError: tupletest() keywords must be strings

I am unsure if this is even possible given the error msg. I am testing this in 3.7.4

All help appreciated.

sushanth
  • 8,275
  • 3
  • 17
  • 28
  • You *can* pass `mydict` to a function. But you can't pass it to a function that says it expects `**kwargs` because that requires a `dict` where the keys are strings that might match a parameter name. Drop the `**` from the call and the function signature and the code will work. – BoarGules Dec 21 '20 at 12:15
  • Many thanks BoarGules for this answer, unfortunately however it seems I cannot mark a comment as the answer. – Dr Stranglove Dec 22 '20 at 08:56
  • Although this problem had its roots in a misunderstanding of what `**` is for, it *could* be called a syntax error, and fixes for syntax errors don't count as proper answers. This https://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/ comes recommended as a good explanation of how `**` works. – BoarGules Dec 22 '20 at 09:03

3 Answers3

0

I performed a little example. It ist possible:

mydict = {('hostabc', 'pola'): 333444567, ('hostdef', 'polb'): 111222333, ('hostghi', 'polc'): 222999888}

def tupletest(kwargs):
    for key in kwargs:
        #print("key: %s , value: %s" % (key, kwargs[key]))
        print(key[0])
        print(key[1])

tupletest(mydict)

I hope this helps you. I also implemented a little example for entering the key of the dictionary.

Output

0

Short answer is, no it's not possible.

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

**kwargs represents keyword arguments. These arguments are unpacked (so to say) and passed to the function. That way you can use them in the function without having to explicitly pass them to the function as the positional-or-keyword arguments.

def func(*args, **kwargs): ...

var-keyword: specifies that arbitrarily many keyword arguments can be provided (in addition to any keyword arguments already accepted by other parameters). Such a parameter can be defined by prepending the parameter name with **, for example kwargs in the example above.

https://docs.python.org/3/glossary.html#term-argument

BcK
  • 2,548
  • 1
  • 13
  • 27
0

@BoarGules has nicely pointed you to the path. I have nothing new to add and I am saying below the same thing but in a little verbose manner.

See this nice discussion here. So dictionary keys become the named parameters to the function. In this particular case however the keys are tuples. The keyword must have an associated string property and that is what the error is saying above. Notice the "strings" in the error message below.

TypeError: tupletest() keywords must be strings

Had your dictionary been simpler like below, it would have worked.

mydict = {"a": 333444567, "b": 111222333, "c": 222999888}


def tupletest(**kwargs):
    for k in kwargs:
        print(k)

tupletest(**mydict)

The above gives this.

a
b
c

If you would rather want to have the tuples, I will take the dangerous route of eval after quoting the tuples.

mydict = {"('hostabc', 'pola')": 333444567, "('hostdef', 'polb')": 111222333, "('hostghi', 'polc')": 222999888}

def tupletest(**kwargs):
    for k in kwargs:
        print(eval(k))

tupletest(**mydict)

This gives the following output.

('hostabc', 'pola')
('hostdef', 'polb')
('hostghi', 'polc')
Amit
  • 2,018
  • 1
  • 8
  • 12