Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected result when passing datetime objects to str.format()

In Python 2.7, str.format() accepts non-string arguments and calls the __str__ method of the value before formatting output:

class Test:
     def __str__(self):
         return 'test'

t = Test()
str(t) # output: 'test'
repr(t) # output: '__main__.Test instance at 0x...'

'{0: <5}'.format(t) # output: 'test ' in python 2.7 and TypeError in python3
'{0: <5}'.format('a') # output: 'a    '
'{0: <5}'.format(None) # output: 'None ' in python 2.7 and TypeError in python3
'{0: <5}'.format([]) # output: '[]   ' in python 2.7 and TypeError in python3

But when I pass a datetime.time object, I get ' <5' as output in both Python 2.7 and Python 3:

from datetime import time
'{0: <5}'.format(time(10,10)) # output: ' <5'

Passing a datetime.time object to str.format() should either raise a TypeError or format str(datetime.time), instead it returns the formatting directive. Why is that?

like image 655
Alexander Holmbäck Avatar asked Dec 06 '25 00:12

Alexander Holmbäck


1 Answers

'{0: <5}'.format(time(10, 10)) results in call to time(10, 10).__format__, which returns <5 for the <5 format specifier:

In [26]: time(10, 10).__format__(' <5')
Out[26]: ' <5'

This happens because time_instance.__format__ attempts to format time_instance using time.strftime and time.strftime doesn't understand the formatting directive.

In [29]: time(10, 10).strftime(' <5')
Out[29]: ' <5'

The !s conversion flag will tell str.format to call str on the time instance before rendering the result - it will call str(time(10, 10)).__format__(' <5'):

In [30]: '{0!s: <5}'.format(time(10, 10))
Out[30]: '10:10:00'
like image 133
vaultah Avatar answered Dec 07 '25 15:12

vaultah