7

I'm trying to make a templated string that will print values of a given dict. However, the key may or may not exist in the dict. If it doesn't exist, I'd like it to return an empty string instead.

To demonstrate what I mean, let's say I have a dict:

test_dict = { 1: "a", 2: "b"}

And a template string:

'{} {} {}'.format(test_dict.get(1), test_dict.get(2), test_dict.get(3))

I'd like the following output:

'a b '

But instead I get:

'a b None'
Watercayman
  • 7,970
  • 10
  • 31
  • 49
doctopus
  • 5,349
  • 8
  • 53
  • 105
  • Your template string explicitly contains a comma and a space following the second item, so your desired output is impossible. – John Gordon Jul 26 '19 at 21:48
  • Fixed the mistake – doctopus Jul 26 '19 at 21:49
  • 1
    It still contains a space following the second item, so the desired output is still impossible. – John Gordon Jul 26 '19 at 21:49
  • Ok fixed again. That's not the point of my question though. The last placeholder to print an empty string instead of `None`. – doctopus Jul 26 '19 at 21:51
  • 1
    You can pass an extra argument to `.get()` to specify a return value if the key is not found, instead of the default `None`. Use `test_dict.get(3, '')` and it will return a blank string. – John Gordon Jul 26 '19 at 21:52
  • Ahh yes this is what I'm looking for, thank you. – doctopus Jul 26 '19 at 21:53
  • Now that you mention the extra space though, is there a way to remove the placeholder completely if key doesn't exist? – doctopus Jul 26 '19 at 21:58
  • Not if you use a fixed string template. You'd have to build it dynamically, and only add the space and the third value if it exists. – John Gordon Jul 26 '19 at 22:47
  • Or this, but it's kind of ugly `'{} {}{}'.format(test_dict.get(1), test_dict.get(2), (' ' + test_dict.get(3)) if test_dict.get(3) else '')` – John Gordon Jul 26 '19 at 22:49

4 Answers4

6

Use the dictionary's get function. This allows you to specify a value to return if the key is not found

'{}, {}, {}'.format(test_dict.get(1,''), test_dict.get(2,''), test_dict.get(3, ''))
MichaelD
  • 1,274
  • 1
  • 10
  • 16
  • This would also make a good answer on [Python: most idiomatic way to convert None to empty string?](https://stackoverflow.com/questions/1034573/python-most-idiomatic-way-to-convert-none-to-empty-string), then we could close this question into that as a (near-)duplicate. – smci Jul 27 '19 at 01:39
1

UPDATES PER OP COMMENT

You can use the string library to help here. See the below script using your test_dict:

#https://stackoverflow.com/a/51359690
from string import Formatter

class NoneAsEmptyFormatter(Formatter):
    def get_value(self, key, args, kwargs):
        v = super().get_value(key, args, kwargs)
        return ' ' if v is None else v

fmt = NoneAsEmptyFormatter()

test_dict = { 1: "a", 2: "b"}

test_str = fmt.format('{} {} {}', test_dict.get(1), test_dict.get(2), test_dict.get(3))

print(test_str)

We build a quick NoneAsEmptyFormatter class and use that to format the strings in coming from the dict.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
artemis
  • 6,857
  • 11
  • 46
  • 99
  • 1
    Yes I'm aware of why it's causing None. I'm wondering how I can change my template string though, so it returns an empty string instead of `None` in the event that the key does not exist. – doctopus Jul 26 '19 at 21:48
  • Editing post now per OP's comments after my original post answered the first version of the question (for whoever carelessly downvoted) – artemis Jul 26 '19 at 21:51
1

One way would be to get the length of the dict, and put the same amount of placeholeders inside the template:

In [27]: test_dict = { 1: "a", 2: "b"}                                                                                                                                                                      

In [28]: ' '.join(['{}'] * len(test_dict))                                                                                                                                                                  
Out[28]: '{} {}'

In [29]: ' '.join(['{}'] * len(test_dict)).format(*test_dict.values())                                                                                                                                      
Out[29]: 'a b'

Note that, this is basically the same as ' '.join(test_dict.values()) but showing you the template string as an example.

heemayl
  • 39,294
  • 7
  • 70
  • 76
1

Re your comment,

Now that you mention the extra space though, is there a way to remove the placeholder completely if key doesn't exist?

Yes, this is possible. Just make a list of values, filter out any Nones, then join the result:

In [3]: values = map(test_dict.get, [1, 2, 3])

In [4]: ' '.join(v for v in values if v is not None)
Out[4]: 'a b'

Or if order is not important, or if you're using Python 3.7+ and you want to preserve insertion order, you can skip some steps:

In [5]: ' '.join(test_dict.values())
Out[5]: 'a b'
wjandrea
  • 28,235
  • 9
  • 60
  • 81