reynoldsnlp
reynoldsnlp

Reputation: 1210

f-string format specifier with None throws TypeError

Using plain f-strings with a NoneType object works:

>>> a = None
>>> f'{a}'
'None'

However, when using a format specifier, it breaks---as does str.format():

>>> f'{a:>6}'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported format string passed to NoneType.__format__

>>> '{:>6}'.format(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported format string passed to NoneType.__format__

Unexpectedly, (for me, at least) the old C-style string formatting works:

>>> '%10s' % a
'      None'

What is going on here? I don't understand why f'{a:>6}' doesn't evaluate to ' None'. Why should a format specifier break it?

Is this a bug in python? If it is a bug, how would I fix it?

Upvotes: 1

Views: 3935

Answers (3)

Jamie
Jamie

Reputation: 31

The accepted answer above explains why. A solution that I have used effectively is something along the lines of:

f"{mystring:.2f}" if mystring is not None else ""

Upvotes: 1

user2357112
user2357112

Reputation: 282016

None doesn't support format specifiers. It's up to each object type to determine how it wants to handle format specifiers, and the default is to reject them:

The __format__ method of object itself raises a TypeError if passed any non-empty string.

None inherits this default.

You seem to be expecting None to handle format specifiers the same way strings do, where '{:>6}'.format('None') == ' None'. It kind of sounds like you expect all types to handle format specifiers the way strings do, or you expect the string behavior to be the default. The way strings handle format specifiers is specific to strings; other types have their own handling.


You might be thinking, hey, why doesn't %10s fail too? First, the s requests that the argument be converted to a string by str before any further processing. Second, all conversion specifier handling in printf-style string formatting is performed by str.__mod__; it never delegates to the arguments to figure out what a conversion specifier means.

Upvotes: 4

Mark Tolonen
Mark Tolonen

Reputation: 178379

None is not a string, so f'{None:>6}' makes no sense. You can convert it to a string with f'{None!s:>6}'. !a, !s, and !r call ascii(), str(), and repr() respectively on an object.

Upvotes: 6

Related Questions