Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can we pass bytes as the key of keyword arguments to functions?

Tags:

Let us have the following example:

def fun(**args):
    print(str(args))

dic = {'name': 'Pulkit'}
fun(**dic)

This code works fine and I have the following output:

{'name': 'Pulkit'}

Now lets pass the value as bytes:

dic_vb = {'name': b'Pulkit'}
fun(**dic_vb)

This also works fine and have the following output:

{'name': b'Pulkit'}

But things change when I try to have the key as bytes:

dic_kb = {b'name': 'Pulkit'}

This results in TypeError saying:

TypeError: fun() keywords must be strings

Is there any way we can pass bytes as keyword arguments. I also checked CPython code at repo which deals with keyword arguments and seems like we can't pass. Is there any workaround or do I need to make sure unicodes are passed.

I am dealing with a codebase where we have lot of such instances on Python 2 and need to be ported to Python 3. So is only way possible is to convert all of the keyword arguments to unicodes?

like image 954
Pulkit Goyal Avatar asked Dec 06 '16 17:12

Pulkit Goyal


1 Answers

No, keywords need to be valid identifiers, it is the same reason why you cannot provide dictionaries that have numbers as keys to a function expecting **kwargs:

>>> dic = {1: 'Pulkit'}
>>> fun(**dic)
TypeErrorTraceback (most recent call last)
<ipython-input-54-83c29ed0f08e> in <module>()
      3 
      4 dic = {1: 'Pulkit'}
----> 5 fun(**dic)

TypeError: fun() keywords must be strings

That is also what you saw in the source, with the negation (!) of PyUnicode_Check acting as the enforcer.

It is required; you need to provide keys that are able to act as names. To see what is and what is not allowed, just try assigning it to a name in the interactive interpreter and see what errs:

>>> b'my_list' = [...]  # err
>>> 23 = [21, 22]       # err

A viable (and sole, if decode is not allowed) option is passing the dictionary as just another argument and then accessing the values through with normal dictionary look-ups.

Of course, if decoding the bytes to strings before invoking the function is a viable alternative I would suggest you pursue that option:

>>> dic = {b'name': 'Pulkit'}
>>> fun(**{b.decode(): v for b, v in dic.items()})
like image 60
Dimitris Fasarakis Hilliard Avatar answered Sep 24 '22 16:09

Dimitris Fasarakis Hilliard