Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using !s vs. :s to format a string in Python

I'm really curious about :s format string in Python 3. The documentation says !s is conversion and that :s is format_spec.

It also says !s will apply str(), but it doesn't say anything similar about :s. I think there's no significant difference between them, but I want to be sure. Can anyone clarify these?

Some code example:

print("{!s}".format("this"))
print("{:s}".format("that"))
# I want to be sure that these two are processed identically internally

It's still confusing, but let me wrap up with my own (layperson's) words.

  1. type("whatever".format) is always str.
  2. Use !s if you want convert the object into str before formatting.
  3. :s means that the object(or the converted object) will be treated as str during some internal formatting process. It's the default format_spec.

Is anything wrong here?

like image 432
Sangbok Lee Avatar asked Jan 13 '17 08:01

Sangbok Lee


People also ask

How do I format a string in Python %s?

What is % string formatting in Python? One of the older ways to format strings in Python was to use the % operator. You can create strings and use %s inside that string which acts like a placeholder. Then you can write % followed be the actual string value you want to use.

What is S %% in Python?

The % symbol is used in Python with a large variety of data types and configurations. %s specifically is used to perform concatenation of strings together. It allows us to format a value inside a string. It is used to incorporate another string within a string.

What is %s and %R in Python?

PythonServer Side ProgrammingProgramming. The %s specifier converts the object using str(), and %r converts it using repr().

How do you use %S and %D in Python?

In, Python %s and %d are used for formatting strings. %s acts a placeholder for a string while %d acts as a placeholder for a number. Their associated values are passed in via a tuple using the % operator. This code will print abc 2.


2 Answers

!s, and its brethren !a and !r apply str(), ascii() and repr() respectively before interpolation and formatting. These are called conversion flags, and are part of the Format String Syntax spec, not the per-field formatting spec applied to values when interpolating:

The conversion field causes a type coercion before formatting. Normally, the job of formatting a value is done by the __format__() method of the value itself. However, in some cases it is desirable to force a type to be formatted as a string, overriding its own definition of formatting. By converting the value to a string before calling __format__(), the normal formatting logic is bypassed.

Bold emphasis mine.

:s only applies afterwards to the conversion result (or the original object if no conversion had been applied), and only if the __format__ method for the type of object supports that formatting option. Usually, only objects of type str support this formatter; it's there as the default, mostly because the Format Specification Mini-Language allows for the existence of a type character and because the older % printf-style formatting had a %s format. If you tried to apply the s type to an object that doesn't support it, you'd get an exception.

Use !s (or !a or !r) when you have an object that is not itself a string and either doesn't support formatting otherwise (not all types do) or would format differently from their str(), ascii() or repr() conversions:

>>> class Foo:
...     def __str__(self):
...         return "Foo as a string"
...     def __repr__(self):
...         return "<Foo as repr, with åéæ some non-ASCII>"
...     def __format__(self, spec):
...         return "Foo formatted to {!r} spec".format(spec)
...
>>> print("""\
... Different conversions applied:
... !s: {0!s:>60s}
... !r: {0!r:>60s}
... !a: {0!a:>60s}
... No conversions: {0:>50s}
... """.format(Foo()))
Different conversions applied:
!s:                                    Foo as a string
!r:             <Foo as repr, with åéæ some non-ASCII>
!a:    <Foo as repr, with \xe5\xe9\xe6 some non-ASCII>
No conversions: Foo formatted to '>50s' spec

Note: all formatting specified by the format spec are the responsibility of the __format__ method; the last line does not apply the alignment operation in the >50s formatting spec, the Foo.__format__ method only used it as literal text in a formatting operation (using a !r conversion here).

For the converted values, on the other hand, the str.__format__ method is used and the output is aligned to the right in a 50 character wide field, padded with spaces on the left.

like image 69
Martijn Pieters Avatar answered Sep 30 '22 22:09

Martijn Pieters


You're unlucky you used strings as the value to be formatted. Using pretty much any other object you'd get how these aren't the same.

In (as much as I can) layman's terms:

  • The absence or existence of the conversion flag specifies the type of the value we going to format and, by extent, who's __format__ we'll be calling. As Martjin points out, by using this we can bypass certain behavior and treat the value more generically (like a string). It comes in three different flavors that correspond to the three different ways an object can choose to represent itself as a string.
  • The type specifier, coupled with other specifiers, specifies how the type we have should finally be presented. For strings there isn't a rich set of options (a string is presented as is) but, for types like ints, you can have different presentations.

I do think, though, that type is probably a confusing name to give this specifier.

like image 3
Dimitris Fasarakis Hilliard Avatar answered Sep 30 '22 23:09

Dimitris Fasarakis Hilliard