If you are using Python 3.2+, use can use str.format_map().

For bond, bond:

from collections import defaultdict
'{bond}, {james} {bond}'.format_map(defaultdict(str, bond='bond'))

Result:

'bond,  bond'

For bond, {james} bond:

class SafeDict(dict):
    def __missing__(self, key):
        return '{' + key + '}'

'{bond}, {james} {bond}'.format_map(SafeDict(bond='bond'))

Result:

'bond, {james} bond'

In Python 2.6/2.7

For bond, bond:

from collections import defaultdict
import string
string.Formatter().vformat('{bond}, {james} {bond}', (), defaultdict(str, bond='bond'))

Result:

'bond,  bond'

For bond, {james} bond:

from collections import defaultdict
import string

class SafeDict(dict):
    def __missing__(self, key):
        return '{' + key + '}'

string.Formatter().vformat('{bond}, {james} {bond}', (), SafeDict(bond='bond'))

Result:

'bond, {james} bond'
Answer from falsetru on Stack Overflow
🌐
Real Python
realpython.com › python-formatted-output
A Guide to Modern Python String Formatting Tools – Real Python
February 1, 2025 - In this example, you have four replacement fields in the template but only three arguments in the call to .format(). So, you get an IndexError exception. Finally, it’s fine if the arguments outnumber the replacement fields. The excess arguments aren’t used: ... Here, Python ignores the "baz" argument and builds the final string using only "foo" and "bar".
Discussions

python - Why does `str.format()` ignore additional/unused arguments? - Stack Overflow
In other words, the choice is deliberate, because there are practical reasons for allowing more arguments than are converted. Note that the C# String.Formatter implementation that inspired the Python PEP does the same, for those same reasons. More on stackoverflow.com
🌐 stackoverflow.com
How to get .format() to ignore a specific {} that is in a string?
I see you have solved your problem, but FYI: in order to achieve literal {s and }s in str.format()'s output, you need to double them ({{ and }}) in the template string. More on reddit.com
🌐 r/learnpython
10
2
July 14, 2018
Why does Python string formatting silently ignore mismatched argument counts with class instances? - Stack Overflow
Normally, Python old-style string formatting complains if the number of placeholders in the string doesn't match the number of arguments passed: >>> 'no.placeholders.here' % 'test' Traceb... More on stackoverflow.com
🌐 stackoverflow.com
Do not use Python's str.format() for expanding placeholders in commands
Placeholders in command environment variables such as CIBW_BEFORE_BUILD and CIBW_BEFORE_TEST are expanded using Python's str.format(): More on github.com
🌐 github.com
46
September 22, 2021
Top answer
1 of 1
20

Ignoring un-used arguments makes it possible to create arbitrary format strings for arbitrary-sized dictionaries or objects.

Say you wanted to give your program the feature to let the end-user change the output. You document what fields are available, and tell users to put those fields in {...} slots in a string. The end-user then can create templating strings with any number of those fields being used, including none at all, without error.

In other words, the choice is deliberate, because there are practical reasons for allowing more arguments than are converted. Note that the C# String.Formatter implementation that inspired the Python PEP does the same, for those same reasons.

Not that the discussion on this part of the PEP is that clear cut; Guido van Rossum at some point tries to address this issue:

The PEP appears silent on what happens if there are too few or too many positional arguments, or if there are missing or unused keywords. Missing ones should be errors; I'm not sure about redundant (unused) ones. On the one hand complaining about those gives us more certainty that the format string is correct. On the other hand there are some use cases for passing lots of keyword parameters (e.g. simple web templating could pass a fixed set of variables using **dict). Even in i18n (translation) apps I could see the usefulness of allowing unused parameters

to which the PEP author responded that they were still undecided on this point.

For use-cases where you must raise an exception for unused arguments you are expected to subclass the string.Formatter() class and provide an implementation for Formatter.check_unused_args(); the default implementation does nothing. This of course doesn't help your friend's case where you used str.format(*args, **kwargs) rather than Formatter().format(str, *args, **kwargs). I believe that at some point the idea was that you could replace the formatter used by str.format() with a custom implementation, but that never came to pass.

If you use the flake8 linter, then you can add the flake8-string-format plugin to detect the obvious cases, where you passed in an explicit keyword argument that is not being used by the format string.

🌐
Python
docs.python.org › 3 › library › string.html
Common string operations — Python 3.14.6 documentation
While other exceptions may still occur, this method is called “safe” because it always tries to return a usable string instead of raising an exception. In another sense, safe_substitute() may be anything other than safe, since it will silently ignore malformed templates containing dangling delimiters, unmatched braces, or placeholders that are not valid Python identifiers.
🌐
Reddit
reddit.com › r/learnpython › how to get .format() to ignore a specific {} that is in a string?
r/learnpython on Reddit: How to get .format() to ignore a specific {} that is in a string?
July 14, 2018 -

I have a text file that gets read in to the program, and it also contains a JSON file.

An example of what I'm talking about is this:

Hello, {}. Welcome to /r/{}. This is a JSON file.

---

{ 
    "key": "value"
}

That is stored in a text file that we will call example.txt. I read the file in as such:

def read_text_file(file_name):
    with open(file_name, "r") as file:
        return file.read()

my_string = read_text_file("example.txt")
formatted_string = my_string.format(username, subreddit)

However, because the dictionary also has a {} in it, .format() seems to expect a third argument with .format(). Is there a way to make it ignore the third one so that I don't get a KeyError exception?

🌐
GitHub
github.com › pypa › cibuildwheel › issues › 840
Do not use Python's str.format() for expanding placeholders in commands · Issue #840 · pypa/cibuildwheel
September 22, 2021 - Description Placeholders in command environment variables such as CIBW_BEFORE_BUILD and CIBW_BEFORE_TEST are expanded using Python's str.format(): https://github.com/pypa/cibuildwheel/blob/main/cibuildwheel/util.py#L41 This makes it (nea...
Author   pypa
Find elsewhere
🌐
Reddit
reddit.com › r/learnpython › how do i prevent python from taking a % as a format specifier?
r/learnpython on Reddit: How do I prevent Python from taking a % as a format specifier?
November 29, 2021 -

So I wanna do

print("Accuracy is %.2f%" % (accuracy))

but it just says incomplete format because its taking the second % as a format specifier. The one way I have around this is by doing

print("Accuracy is %.2f" % (accuracy),"%")

but it leaves a space between the number and the %.

Actually, as of writing the post I realised I can split it into two print statements and do an end="" and that should print the desired output. Just wanna know if there's any better way of doing this because using \ does not work to make python ignore the %.

🌐
W3Schools
w3schools.com › python › ref_string_format.asp
Python String format() Method
Remove List Duplicates Reverse a String Add Two Numbers · Python Examples Python Compiler Python Exercises Python Quiz Python Challenges Python Practice Problems Python Server Python Syllabus Python Study Plan Python Interview Q&A Python Bootcamp Python Training ... The format() method formats the specified value(s) and insert them inside the string's placeholder.
🌐
DigitalOcean
digitalocean.com › community › tutorials › how-to-format-text-in-python-3
How To Format Text in Python 3 | DigitalOcean
August 20, 2021 - For example, we may need to compare or evaluate strings of computer code that use the backslash on purpose, so we won’t want Python to use it as an escape character. A raw string tells Python to ignore all formatting within a string, including escape characters.
Top answer
1 of 4
23

The official solution (Python 3 Docs) for strings in format mappings is to subclass the dict class and to define the magic-method __missing__(). This method is called whenever a key is missing, and what it returns is used for the string formatting instead:

class format_dict(dict):
    def __missing__(self, key):
        return "..."

d = format_dict({"foo": "name"})

print("My %(foo)s is %(bar)s" % d) # "My name is ..."

print("My {foo} is {bar}".format(**d)) # "My name is ..."

Edit: the second print() works in Python 3.5.3, but it does not in e.g. 3.7.2: KeyError: 'bar' is raised and I couldn't find a way to catch it.

After some experiments, I found a difference in Python's behavior. In v3.5.3, the calls are __getitem__(self, "foo") which succeeds and __getitem__(self, "bar") which can not find the key "bar", therefore it calls __missing__(self, "bar") to handle the missing key without throwing a KeyError. In v3.7.2, __getattribute__(self, "keys") is called internally. The built-in keys() method is used to return an iterator over the keys, which yields "foo", __getitem__("foo") succeeds, then the iterator is exhausted. For {bar} from the format string there is no key "bar". __getitem__() and hence __missing_() are not called to handle the situation. Instead, the KeyError is thrown. I don't know how one could catch it, if at all.

In Python 3.2+ you should use format_map() instead (also see Python Bug Tracker - Issue 6081):

from collections import defaultdict
    
d = defaultdict(lambda: "...")
d.update({"foo": "name"})

print("My {foo} is {bar}".format_map(d)) # "My name is ..."

If you want to keep the placeholders, you can do:

class Default(dict):
    def __missing__(self, key): 
        return key.join("{}")
    
d = Default({"foo": "name"})

print("My {foo} is {bar}".format_map(d)) # "My name is {bar}"

As you can see, format_map() does call __missing__().

The following appears to be the most compatible solution as it also works in older Python versions including 2.x (I tested v2.7.15):

class Default(dict):
    def __missing__(self, key):
        return key.join("{}")

d = Default({"foo": "name"})

import string
print(string.Formatter().vformat("My {foo} is {bar}", (), d)) # "My name is {bar}"

To keep placeholders as-is including the format spec (e.g. {bar:<15}) the Formatter needs to be subclassed:

import string

class Unformatted:
    def __init__(self, key):
        self.key = key
    def __format__(self, format_spec):
        return "{{{}{}}}".format(self.key, ":" + format_spec if format_spec else "")

class Formatter(string.Formatter):
    def get_value(self, key, args, kwargs):
        if isinstance(key, int):
            try:
                return args[key]
            except IndexError:
                return Unformatted(key)
        else:
            try:
                return kwargs[key]
            except KeyError:
                return Unformatted(key)


f = Formatter()
s1 = f.vformat("My {0} {1} {foo:<10} is {bar:<15}!", ["real"], {"foo": "name"})
s2 = f.vformat(s1, [None, "actual"], {"bar":"Geraldine"})
print(s1) # "My real {1} name       is {bar:<15}!"
print(s2) # "My real actual name       is Geraldine      !"

Note that the placeholder indices are not changed ({1} remains in the string without a {0}), and in order to substitute {1} you need to pass an array with any odd first element and what you want to substitute the remaining placeholder with as second element (e.g. [None, "actual"]).

You can also call the format() method with positional and named arguments:

s1 = f.format("My {0} {1} {foo:<10} is {bar:<15}!", "real", foo="name")
s2 = f.format(s1, None, "actual", bar="Geraldine")
2 of 4
20

str.format() doesn't expect a mapping object. Try this:

from collections import defaultdict

d = defaultdict(str)
d['error2'] = "success"
s = "i am an {0[error]} example string {0[error2]}"
print s.format(d)

You make a defaultdict with a str() factory that returns "". Then you make one key for the defaultdict. In the format string, you access keys of the first object passed. This has the advantage of allowing you to pass other keys and values, as long as your defaultdict is the first argument to format().

Also, see http://bugs.python.org/issue6081

🌐
Python
peps.python.org › pep-3101
PEP 3101 – Advanced String Formatting | peps.python.org
The precision is ignored for integer conversions. Finally, the ‘type’ determines how the data should be presented. ... 'b' - Binary. Outputs the number in base 2. 'c' - Character. Converts the integer to the corresponding Unicode character before printing. 'd' - Decimal Integer. Outputs the number in base 10. 'o' - Octal format.
🌐
Reddit
reddit.com › r/learnpython › format function: fill missing keys with empty string
r/learnpython on Reddit: Format function: Fill missing keys with empty string
February 5, 2020 -

Hey guys,

I'm working in a very specific enviroment and I have a scheme file where I replace keys with the format function. The file might look like this:

1: {code1}
2: {code2}
3: {code3}

I want that other persons can change the format file and add {code} tags. My program uses this file and replaces the values, but the amount of {code} blocks varies.

So at the moment I generate a dict with the code tags, and replace them in that string (which got loaded from the file)

code_tags = {"code1": "ABC", "code2": "DEF"}
file_content.format(**code_tags)

A problem occurs when there are more keys in the scheme file than keys generated from my program (KeyError). How can I put in an empty string for tags which got not specified in code_tags?

I thought about crawling the file and find every tag, compare, and add missing to the dict with and emptry string. But that's kinda hask-ish and maybe not the cleanest style.

How would you solve the problem?

Top answer
1 of 1
2

There are a few minor issues with most of your lines ignoring specific patterns.

  1. %-G%Oh no!\ %m : You have an extra % there, turning the first character into a %O (a command to overread the matched part) rather than a literal O. You also have a trailing space there, so it would only match a line with a space at the end! You can fix that to %-GOh no!\ %m. Note that you don't actually need the \ to escape the space in this format, you only need it when using the :set command, since it breaks on whitespace. You can also just use %.%# at the end of the line, since you're ignoring this pattern anyways.

  2. %-G%*\\d\ files%.%#: Here you need a single backslash in %*\d to match a number. Note that this is using a scanf()-style pattern, you can also use a Vim regular expression here to match a sequence of digits, with %\d\+. You have one more issue on your playground for this one, you have no space before files, you have just \files over there, so that needs to be corrected too. Same as above, you don't need to backslash-escape the spaces here, only for a :set command.

  3. %-Q: This is a command to pop the last file from stack, but this only makes sense when using a corresponding %P to match a file name relevant for a block of messages. It doesn't look like that's the case here.

Here's the playground with minimal fixes to make it work, and here's a playground with more cleanup (removing the spurious %Q, the backslash escapes spaces, using regex for the digit match and a %.%# to match the end of the "Oh no!" line.)

🌐
Python
docs.python.org › 3.3 › library › string.html
6.1. string — Common string operations — Python 3.3.7 documentation
March 9, 2022 - While other exceptions may still occur, this method is called “safe” because substitutions always tries to return a usable string instead of raising an exception. In another sense, safe_substitute() may be anything other than safe, since it will silently ignore malformed templates containing dangling delimiters, unmatched braces, or placeholders that are not valid Python identifiers.