I have some troubles understanding the way the format()
method of string works.
Suppose that I set a string variable with keywords arguments:
s = '{hello} {person_name}'
I could either assign this value to another variable or print it. In the latter case, the result would be {hello} {person_name}
.
I could also use the format()
method while printing s
and assign some values to the keywords:
print(s.format(hello='hello', person_name='Alice'))
In this case, the result is hello Alice
. Of course, I could also assign it to a new variable.
My problem arises when I want to use format only on one keyword:
print(s.format(hello='hello'))
or
a = s.format(hello='hello')
Both of them throw an error:
KeyError: 'person_name'
I want to be able to run something like :
s = '{hello} {person_name}'
a = s.format(hello='hello')
if something:
b = a.format(person_name='Alice')
else:
b = a.format(person_name='Bob')
print(b)
Is something like this possible or should I set all keywords when I use format()
?
In your use case, you might consider escaping the {person}
in the string:
# double brace the person_name to escape it for the first format
s = '{hello} {{person_name}}'
a = s.format(hello='hello')
# a = 'hello {person_name}'
if something:
b = a.format(person_name='Alice')
# b = 'hello Alice'
else:
b = a.format(person_name='Bob')
# b = 'hello Bob'
print(b)
With this method however you will need to follow the explicit order in which you escaped your variables. i.e. you must assign hello
first and then person_name
. If you need to be flexible about the order of things, I would suggest using a dict
to construct the variables before passing it altogether:
# dict approach
s = '{hello} {person_name}'
# determine the first variable
d = {'hello':'hello'}
... do something
d.update({'person': 'Alice'})
# unpack the dictionary as kwargs into your format method
b = s.format(**d)
# b = 'hello Alice'
This gives you a bit more flexibility on the order of things. But you must only call .format()
once all the variables are provided in your dict
(at least it must have a default value), otherwise it'll still raise an error.
If you want to be more fancy and want the ability to print the field names at the absence of the variable, you can make your own wrapper function as well:
# wrapper approach
# We'll make use of regex to keep things simple and versatile
import re
def my_format(message, **kwargs):
# build a regex pattern to catch words+digits within the braces {}
pat = re.compile('{[\w\d]+}')
# build a dictionary based on the identified variables within the message provided
msg_args = {v.strip('{}'): v for v in pat.findall(message)}
# update the dictionary with provided keyword args
msg_args.update(kwargs)
# ... and of course, print it
print(message.format(**msg_args))
s = 'Why {hello} there {person}'
my_format(s, hello='hey')
# Why hey there {person}
my_format(s, person='Alice')
# Why {hello} there Alice
You can determine the default display (at the absence of a variable) you want by modifying the v
in dictionary comprehension.