如何在格式化时参考变量类型指定字符串格式?



如果变量a的类型在创建之前是未知的,那么在使用python字符串格式化时,特别是在格式化时,如何解释该类型?

的例子:

import numpy as np
import datetime as dt
a = dt.datetime(2020,1,1)
print(f'{a:%d/%m/%Y}')
>>>
01/01/2020

但是,如果变量被改变了,那么这将产生一个错误:

a = np.nan
print(f'{a:%d/%m/%Y}')
>>>
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-70-02594a38949f> in <module>
1 a = np.nan
----> 2 print(f'{a:%d/%m/%Y}')
ValueError: Invalid format specifier

所以我试图实现这样的东西:

print(f'{a:%d/%m/%Y if not np.isnan(a) else ,.0f}')
>>>
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-78-52c24b6abb16> in <module>
----> 1 print(f'{a:%d/%m/%Y if not np.isnan(a) else ,.0f}')
ValueError: Invalid format specifier

然而,正如我们所看到的,它试图在计算表达式之前格式化变量。也许语法需要纠正,或者完全需要另一种方法。但是,我确实特别想评估部署它的格式化程序,并在打印f字符串时部署它。

谢谢!


意识到下面的方法是可能的:

print(f'{a:%d/%m/%Y}' if isinstance(a,dt.datetime) else f'{a}')
但是,语法仍然太麻烦,特别是如果要将其部署在多个位置时。实际上,我正在寻找一种简化的方法来格式化变量,如果它是与格式兼容的类型,那么默认为没有指定的格式化器。

谢谢!

如果使用自定义函数,可以在代码的一个点上处理所需的所有类型呢?

import numbers
def get_formatter(var):
"""Get the format of a variable to be used in an f-string, based on its type"""
if isinstance(var, (dt.datetime, dt.date)):
return '%d/%m/%Y'
elif isinstance(var, numbers.Number):
if np.isfinite(var):
return '.3f'
return ''

然后你可以使用函数来格式化变量;例如:

for v in [
dt.datetime(2020,1,1),
np.nan,
5,
5.555555,
]:
print(f'{v:{get_formatter(v)}}')

会产生:

01/01/2020
nan
5.000
5.556

如果您有很多这样的事情要做,我建议您定义自己的自定义格式化器。

例如:

import string
import datetime as dt
class CustomFormatter(string.Formatter):
def format_field(self, value, format_spec):
if isinstance(value, float):
return str(value)
elif isinstance(value,dt.datetime):
return value.__format__(format_spec)
return super().format(value, format_spec)

在这个自定义格式化程序中,您可以忽略floats的所有格式说明符,并为datetimes调用__format__()方法,或者将它们更改为您想要的任何内容。使用时,只需:

print(fmt.format("{:%d/%m/%Y}",a))

当你想这样使用时,这很有用:

a = dt.datetime(2020,1,1)
b = np.nan
fmt = CustomFormatter()
for value in [a,b]:
print(fmt.format("The value is: {:%d/%m/%Y}",value))

输出将是:

The value is: 01/01/2020
The value is: nan

这意味着你不需要更改datetime或float或任何可能的类型的说明符,甚至不需要检查类型,因为你已经做了这些并把它放在了你的类中。

你可以像这样创建一个内联条件格式:

print(f'{a:{"%d/%m/%Y" if not np.isnan(a) else ",.0f"}}')

所以基本上你需要一个额外的花括号,然而,我认为@PieCot提出的解决方案要干净得多。