442

I have the following code

test = "have it break."
selectiveEscape = "Print percent % in sentence and not %s" % test

print(selectiveEscape)

I would like to get the output:

Print percent % in sentence and not have it break.

What actually happens:

    selectiveEscape = "Use percent % in sentence and not %s" % test
TypeError: %d format: a number is required, not str
Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
jondykeman
  • 6,172
  • 3
  • 23
  • 22
  • @KarlKnechtel: But I have personally met the problem when the formatting template was read from a file. If you have no control over what is inside the file, then the question is legitimate. – pepr May 22 '12 at 07:22
  • If the formatting template is in a file, then getting the template correct - including proper escaping of `%` symbols - is the responsibility of the file creator. – Karl Knechtel May 22 '12 at 16:04
  • 99
    Why isn't it `\%`? That was my guess, I'm surprised to find it's `%%` instead - seems pretty counterintuitive. – Demis Apr 28 '15 at 16:14
  • 4
    `% i` means "a decimal representation of an integer, padded left with spaces. – Antti Haapala -- Слава Україні Apr 02 '16 at 21:19
  • 8
    The escape is to the function, not the language syntax. Hence if the escape was `\%` it would actually be `\\%` when written in ordinary code. `` is the typical pattern I've seen, and ``\`` happens to be the most common escape character, for better or worse. – shemnon Oct 14 '16 at 21:00
  • 1
    @Demis and how do you escape `\ ` if you had to print `\\%`? You are bound to require escaping through repetition of special characters, if the special characters are also not special depending on circumstances. – Sassa NF Jan 17 '17 at 21:48
  • 2
    I think it is annoying in Python that the the literal % is encoded by "%%" and not by "\%". – MasterControlProgram Nov 01 '17 at 18:39
  • @Ralf I find it more confusing that when I need to escape `%` in LaTeX mode, `r'\%'` doesn't work but `r'\%%'` works – nish-ant Dec 19 '19 at 16:12

6 Answers6

735
>>> test = "have it break."
>>> selectiveEscape = "Print percent %% in sentence and not %s" % test
>>> print selectiveEscape
Print percent % in sentence and not have it break.
Nolen Royalty
  • 18,415
  • 4
  • 40
  • 50
  • 60
    In Python 3.3.5, `print('%s%%' % 100)` prints `100%`. But `print('%%')` prints `%%`. So it looks like you don't have to escape the % signs if you don't make substitutions. – Zenadix Sep 08 '15 at 19:39
  • 6
    @Zenadix This is true in Python 2.7 as well – Tom Dec 15 '15 at 18:17
  • 2
    Note that the `%` method is actually deprecated (in Python 3) in favor of `str.format()`: https://docs.python.org/2/library/stdtypes.html#str.format – dantiston Feb 20 '17 at 18:45
  • 12
    Note that the `%` method is not depreciated in Python 3.6. It will continue to be supported in lieu of its similarity to c, c++, etc. `str.format()` and f-strings are preferred but not enforced. – Aaron Apr 07 '17 at 21:02
  • Just noticed that If the string is a json string, being read from a file you don't even need to escape the `%` sign. Just `%` will do – wander95 Dec 19 '17 at 16:24
  • You can also be sneaky and do `print "Print percent %" + "variable %s" % 'text'` as a dirty workaround. – dragon788 Dec 31 '18 at 23:35
  • @Zenadix that is because it is **not string escaping**, but a *completely different* escape mechanism that is processed *by the `%` operator* (at the same time that it's scanning for `%s` symbols). So it's the same reason that `print('%s')` prints `%s` and doesn't give any kind of error. A similar thing happens with regexes, but it's much more confusing there because regex syntax also uses the ``\`` character for escaping and because people use "raw strings" with an `r` prefix to cut down on the backslashes, then mistakenly think the `r` means "regex". – Karl Knechtel Oct 13 '22 at 17:59
62

Alternatively, as of Python 2.6, you can use new string formatting (described in PEP 3101):

'Print percent % in sentence and not {0}'.format(test)

which is especially handy as your strings get more complicated.

Karmel
  • 3,452
  • 2
  • 18
  • 11
48

try using %% to print % sign .

Botz3000
  • 39,020
  • 8
  • 103
  • 127
openmeet123
  • 519
  • 3
  • 2
10

You can't selectively escape %, as % always has a special meaning depending on the following character.

In the documentation of Python, at the bottem of the second table in that section, it states:

'%'        No argument is converted, results in a '%' character in the result.

Therefore you should use:

selectiveEscape = "Print percent %% in sentence and not %s" % (test, )

(please note the expicit change to tuple as argument to %)

Without knowing about the above, I would have done:

selectiveEscape = "Print percent %s in sentence and not %s" % ('%', test)

with the knowledge you obviously already had.

Anthon
  • 69,918
  • 32
  • 186
  • 246
6

If you are using Python 3.6 or newer, you can use f-string:

>>> test = "have it break."
>>> selectiveEscape = f"Print percent % in sentence and not {test}"
>>> print(selectiveEscape)
... Print percent % in sentence and not have it break.
Jaroslav Bezděk
  • 6,967
  • 6
  • 29
  • 46
3

If the formatting template was read from a file, and you cannot ensure the content doubles the percent sign, then you probably have to detect the percent character and decide programmatically whether it is the start of a placeholder or not. Then the parser should also recognize sequences like %d (and other letters that can be used), but also %(xxx)s etc.

Similar problem can be observed with the new formats -- the text can contain curly braces.

pepr
  • 20,112
  • 15
  • 76
  • 139