Search code examples
pythonstring-formatting

Quote string value in F-string in Python


I'm trying to quote one of the values I send to an f-string in Python:

f'This is the value I want quoted: \'{value}\''

This works, but I wonder if there's a formatting option that does this for me, similar to how %q works in Go. Basically, I'm looking for something like this:

f'This is the value I want quoted: {value:q}'
>>> This is the value I want quoted: 'value'

I would also be okay with double-quotes. Is this possible?


Solution

  • Use the explicit conversion flag !r:

    >>> value = 'foo'
    >>> f'This is the value I want quoted: {value!r}'
    "This is the value I want quoted: 'foo'"
    

    The r stands for repr; the result of f'{value!r}' should be equivalent to using f'{repr(value)}'. Conversion flags are a feature carried over from str.format, which predates f-strings.

    For some reason undocumented in PEP 3101, but mentioned in the docs, there's also an !a flag which converts with ascii:

    >>> f'quote {"πŸ”₯"!a}'
    "quote '\\U0001f525'"
    

    And there's an !s for str, which seems useless... unless you know that objects can override their formatter to do something different than object.__format__ does. It provides a way to opt-out of those shenanigans and use __str__ anyway.

    >>> class What:
    ...     def __format__(self, spec):
    ...         if spec == "fancy":
    ...             return "π“…π‘œπ“‰π’Άπ“‰π‘œ"
    ...         return "potato"
    ...     def __str__(self):
    ...         return "spam"
    ...     def __repr__(self):
    ...         return "<wacky object at 0xcafef00d>"
    ... 
    >>> obj = What()
    >>> f'{obj}'
    'potato'
    >>> f'{obj:fancy}'
    'π“…π‘œπ“‰π’Άπ“‰π‘œ'
    >>> f'{obj!s}'
    'spam'
    >>> f'{obj!r}'
    '<wacky object at 0xcafef00d>'
    

    One example of where that !s might be useful in practice is with alignment/padding of types that don't otherwise support it:

    >>> f"{[1,2]:.>10}"
    TypeError: unsupported format string passed to list.__format__
    >>> f"{[1,2]!s:.>10}"
    '....[1, 2]'
    

    Or types which "support" it, but not how you may have intended:

    >>> from datetime import date
    >>> f"{date.today():_^14}"
    '_^14'
    >>> f"{date.today()!s:_^14}"
    '__2024-03-25__'