deez
deez

Reputation: 1704

Python string interpolation for string and dictionary in the same line

I have a dictionary and a datetime object I converted to string. How do I print the datetime string and several items from the dictionary in the same line?

For example:

dictionary = {"_source": {"host": "host", "type": "type"}}
datetime = '25-08-2017 10:26:11'

This is what I'm trying to print:

print("%s %(host)s %(type)s" % (datetime,dictionary["_source"]))

Getting an error on the datetime string:

TypeError: format requires a mapping

Thanks!

Upvotes: 2

Views: 3304

Answers (5)

ands
ands

Reputation: 2046

Like others have said it is probably the best to use str.format(). The closest option with method str.format() to your question is code which Violet Red suggested in his answer:

"{} {host} {type}".format(datetime,**dictionary["_source"])

But if you really want or need to use the old way of formatting (using %) then you can try some of these options:

  • Separating string into two or more strings

    Like Eugene Yarmash explained in his answer you can't mix ordinary and mapping format specifiers in same string, but you could separate it to two (or more) strings like this:

    '%s' % datetime + ' %(type)s %(host)s' % dictionary["_source"]
    

    This will work but if you wanted to print datetime in the middle (something like this '%(type)s %s %(host)s') or if you have more ordinary and mapping format specifiers which are intertwined (something like this '%s '%(type)s %s %(host)s' %s). You could separate '%(type)s %s %(host)s' into multiple strings like this:

    '%(type)s' % dictionary["_source"] + ' %s ' % datetime +  '%(host)s' % dictionary["_source"]
    

    But then there is no point in string format in first place.

  • First applying mapping than ordinary format specifiers

    This method solves our problem of formatting string with ordinary and mapping format specifiers which are intertwined. I will explain this method on the example from OP. We have string '%s %(type)s %(host)s' which we want to format. Like I said in first we apply mapping format specifiers:

    print('%s %(type)s %(host)s' % dictionary["_source"])
    

    If we do this it will print out:

    '{'type': 'type', 'host': 'host'} type host'
    

    This does not work, but what we can do is add parentheses () in every ordinary format specifier and update our dictionary with {'': '%s'}:

    print('%()s %(type)s %(host)s' % {'type': 'type', 'host': 'host', '': '%s'})
    

    This will print out:

    '%s type host'

    which we can easily format with % (datetime).

    The question is how to {'': '%s'} to your dictionary. You have two options, to use a function or to define your class for the dictionary object.

    1. Using function

    def ForFormat(x):
        d = x.copy()
        d.update({'': '%s'})
        return d
    

    And you use it like this:

    print('%()s %(type)s %(host)s' % ForFormat(dictionary["_source"]) % (datetime))
    

    The result is exactly what we want:

    '25-08-2017 10:26:11 type 45 host'
    

    2. Creating class

    class FormatDict(dict):
        def __missing__(self, key):
            return '%s'
    

    Here we don't actually add {'': '%s'} to dictionary, but rather change its method __missing__() which is called when key can not be found in dictionary so it will retrun '%s' for each mapping format specifier that is not in dictionary. It is used like this:

    print('%()s %(type)s %(host)s' % FormatDict(dictionary["_source"]) % (datetime))
    

    It also prints out the desired result:

    '25-08-2017 10:26:11 type 45 host'
    

Upvotes: 2

Eugene Yarmash
Eugene Yarmash

Reputation: 150031

You can't mix ordinary and mapping format specifiers in a single format string. You should use either

"%s %s %s" % (param1, param2, param3)

or

"%(key1)s %(key2)s %(key3)s" % {"key1": val1, "key2": val2, "key3": val3}

In Python 3.6+ you can use much more convenient and efficient f-strings for interpolation, e.g:

f'{val1} {val2} {val3}'

where replacement fields are expressions evaluated at run time.

Upvotes: 2

Ajax1234
Ajax1234

Reputation: 71471

You can try this:

dictionary = {"_source": {"host": "host", "type": "type"}}
datetime = '25-08-2017 10:26:11'

print("host {} type {} datetime {}".format(dictionary["_source"]["host"], dictionary["_source"]["type"], datetime))

Upvotes: 1

Violet Red
Violet Red

Reputation: 221

One way is to assign a name to your datetime arg:

"{t} {host} {type}".format(t=datetime,**dictionary["_source"])

But actually it will work even without it

"{} {host} {type}".format(datetime,**dictionary["_source"])

though it's better to use named values in formatted strings imo

Upvotes: 6

mgilson
mgilson

Reputation: 310097

You're better off using the format method:

>>> "{} {d[host]} {d[type]}".format(datetime, d=dictionary["_source"])
'25-08-2017 10:26:11 host type'

Upvotes: 3

Related Questions