20
\$\begingroup\$

Given:

k = {'MASTER_HOST': '10.178.226.196', 'MASTER_PORT': 9999}

I want to flatten into the string:

"MASTER_HOST='10.178.226.196', MASTER_PORT=9999"

This is the ugly way that I'm achieving this right now:

result = []
for i,j in k.iteritems():
    if isinstance(j, int):
        result.append('%s=%d' % (i,j))
    else:
        result.append("%s='%s'" % (i,j))

', '.join(result)

I'm sure my developer colleagues are going to chastize me for this code. Surely there is a better way.

\$\endgroup\$
1
  • \$\begingroup\$ I don't think it's that bad, unless perhaps you also have Boolean values in your dict, because isinstance(False, int) returns True, so instead of flag='False', you'd get flag=0 (both of which are not optimal). \$\endgroup\$
    – Tim Pietzcker
    Jan 19, 2012 at 9:00

4 Answers 4

33
\$\begingroup\$

For python 3.0+ (as @Serdalis suggested)

', '.join("{!s}={!r}".format(key,val) for (key,val) in k.items())

Older versions:

', '.join("%s=%r" % (key,val) for (key,val) in k.iteritems())
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Close but no cigar. I don't want quotes around 9999 for MASTER_PORT in the final result. \$\endgroup\$
    – Bon Ami
    Jan 19, 2012 at 8:53
  • 1
    \$\begingroup\$ @BonAmi You're right. I replaced the second %s with %r to achieve that \$\endgroup\$
    – Dor Shemer
    Jan 19, 2012 at 8:57
  • \$\begingroup\$ Instead of the (key,val) you could simply write item. iteritems returns tuples, and if you have multiple replacements in a string, you replace those using a tuple. You drop a second temporary variable and imo, you gain some readability. \$\endgroup\$
    – Elmer
    Jan 19, 2012 at 9:31
  • \$\begingroup\$ @Elmer That's interesting you say that, because I think novice pythoners might get more readability by using (key,val), since it explains better what happens. But I guess that's a matter of taste. I do agree your way is more efficient. \$\endgroup\$
    – dorsh
    Jan 19, 2012 at 9:34
  • \$\begingroup\$ I know it's a dictionary and .iteritems returns (key, val), so unless you have better variable names that warrant creating temporary variables, like (food_name, price), you can save yourself the characters. It's all about increasing your signal to noise, and (k,v) or (key, value) is mostly noise. \$\endgroup\$
    – IceArdor
    Sep 18, 2015 at 6:35
9
\$\begingroup\$

Dor Shemer's method is very good, however since 3.0+ came out, pythoneque? language is moving towards:

', '.join("{!s}={!r}".format(k,v) for (k,v) in k.items())

using .format instead of % () to format a string.

both will give the same result and are correct.

I used items for python 3.0+, but for python 2.x use iteritems

\$\endgroup\$
2
  • \$\begingroup\$ You're right. I keep thinking with python 2.6 \$\endgroup\$
    – Dor Shemer
    Jan 19, 2012 at 9:00
  • 2
    \$\begingroup\$ new syntax 3.6: f"this is a string {variable}" \$\endgroup\$
    – JinSnow
    Feb 5, 2017 at 20:18
1
\$\begingroup\$

If you want exactly that output format, your way is quite OK imo. Because you want your keys unquoted and your values quoted if they're strings and unquoted if they're just numbers, there is no 'easy way' I think

In general str(k) will return a string like {'MASTER_HOST': '10.178.226.196', 'MASTER_PORT': 9999}

\$\endgroup\$
1
\$\begingroup\$

For python 3.6+ you can use f-strings:

', '.join(f'{k}_{v}' for k, v in my_dict.items())
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nice! Do you think you can improve the efficiency a little? \$\endgroup\$
    – Chocolate
    Feb 18, 2021 at 0:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.