6

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'
9
  • Your template string explicitly contains a comma and a space following the second item, so your desired output is impossible. Commented Jul 26, 2019 at 21:48
  • Fixed the mistake Commented Jul 26, 2019 at 21:49
  • 1
    It still contains a space following the second item, so the desired output is still impossible. Commented Jul 26, 2019 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. Commented Jul 26, 2019 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. Commented Jul 26, 2019 at 21:52

4 Answers 4

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, ''))
Sign up to request clarification or add additional context in comments.

1 Comment

This would also make a good answer on Python: most idiomatic way to convert None to empty string?, then we could close this question into that as a (near-)duplicate.
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.

2 Comments

Why not just do ' '.join(test_dict.values())?
@wjandrea Yes, that's the plan. Showing the template string for better understanding.
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.

2 Comments

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.
Editing post now per OP's comments after my original post answered the first version of the question (for whoever carelessly downvoted)
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'

2 Comments

Appreciate the help, but unfortunately in my case, the order is important.
@doctopus Oh, option 1 preserves order. Option 2 might not.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.