Python String Formatting

No issues with moving to str.format, f-strings have some pros and cons. For formatting a values already assigned to variables, it reads nicely.
As with the example f"ssh {username}@{hostname}"

The down-sides for Blender’s Python code are…

  • This doesn’t work so well when the contents of f-strings contains function calls, operators … etc, take this example.

    return """<input type="checkbox" title="{:s}" {:s} {:s}>""".format(
        title,
        "checked" if value else "",
        ("onclick=\"{:s}\"".format(script)) if script else "",
    )
    

    Of course we can refactor code to read better, assign variables before using them in some cases, but this makes the project a bigger task.

    The case above is a little extreme (especially that it includes a format within a format), even in simpler cases, f-strings don’t necessarily read very well, we often use unpacking from vector types, which you don’t get with f-strings.


    I find this:

    file.write("{:4f}, {:4f}, {:4f}".format(*(matrix @ vertex.co)))
    

    More readable than this:

    vertex_co = matrix @ vertex.co
    file.write(f"{vertex_co[0]:4f}, {vertex_co[1]:4f}, {vertex_co[2]:4f}")
    

    This function in release/scripts/modules/rna_prop_ui.py, doesn’t convert easily.

    def rna_idprop_quote_path(prop):
        return "[\"%s\"]" % prop.replace("\"", "\\\"")
    

    … I ran into the error: SyntaxError: f-string expression part cannot include a backslash.

    Again, assigning variables could work here, it’s just an example where f-strings can’t be used as drop-in replacements for existing code.


    Less extreme cases are always disputable, having already looked into moving to f-strings, there are enough cases in Blender’s code that don’t convert cleanly, making them less useful as a general replacement for existing formatting.

  • Many editors still don’t properly syntax highlight code in f-strings (including Blender’s).

  • Tooling around Python don’t fully support f-strings. Autopep8 for e.g. wont auto-format code inside f-strings.

  • For UI labels f-strings will extract code in the translation string, so translation strings will be more verbose & likely to change more often, although I’d want to double check with @mont29 about this.

  • Moving between f-strings and str.format adds some overhead, we may start out using with formatting that works well as an f-string, later on more complex logic could be added into the existing f-string (which I’d rather avoid), or the f-string needs to be converted into a str.format, which takes time and has potential for human error.

  • If there are cases where we do/don’t use f-strings, we need to document & communicate this, explain in patch review, request edits that add/remove it, explain that UI translations are an exception, discuss when it is/isn’t readable … which takes time and is subjective.

You can use str.format with named arguments, if argument order makes the formatting less readable.

   "{foo:s} {bar:d} {baz:f}".format(
        foo=some(b, 'c'),
        bar=non(d, e),
        baz=trivial('code', ":)"),
    )

This avoids filling the local name-space with single use variables that can be used by accident or show up un-helpfully in auto-complete.


So moving to str.format seems fine.

As for f-strings, I’d rather only use f-strings in cases where they use basic variables & attributes, where it’s unlikely we introduce more complex logic. Although having two ways of doing something thats subjective makes me less inclined to want to use them.