【问题标题】:String formatting options: pros and cons字符串格式化选项:优点和缺点
【发布时间】:2011-12-06 05:53:36
【问题描述】:

这是在 Python 中格式化字符串的两种非常流行的方法。一种是使用dict:

>>> 'I will be %(years)i on %(month)s %(day)i' % {'years': 21, 'month': 'January', 'day': 23}
'I will be 21 on January 23'

另一个使用简单的tuple:

>>> 'I will be %i on %s %i' % (21, 'January', 23)
'I will be 21 on January 23'

第一个更易读,但第二个写起来更快。我实际上是模糊地使用它们。

各有什么优缺点?关于性能、可读性、代码优化(其中一个是否已转换为另一个?)以及您认为有用的任何其他内容。

【问题讨论】:

  • 好问题。我个人觉得第二个更具可读性。代码可读性取决于大脑。在旁注中,不知何故花括号总是毁了我。
  • 使用format() 方法时,您无需在这两种传递参数的方式之间进行选择——您可以同时使用两种方式(请参阅我的回答)。

标签: python string-formatting


【解决方案1】:

为什么format() 比% 字符串操作更灵活

我认为你真的应该坚持str的format()方法,因为它是格式化字符串的首选方法,并且将来可能会取代字符串格式化操作。

此外,它还有一些非常好的功能,还可以将基于位置的格式与基于关键字的格式相结合:

>>> string = 'I will be {} years and {} months on {month} {day}'
>>> some_date = {'month': 'January', 'day': '1st'}
>>> diff = [3, 11] # years, months
>>> string.format(*diff, **some_date)
'I will be 3 years and 11 months on January 1st'

甚至以下方法也可以:

>>> string = 'On {month} {day} it will be {1} months, {0} years'
>>> string.format(*diff, **some_date)
'On January 1st it will be 11 months, 3 years'

还有另一个支持format() 的原因。因为它是一个方法,所以它可以作为回调传递,如下例所示:

>>> data = [(1, 2), ('a', 'b'), (5, 'ABC')]
>>> formatter = 'First is "{0[0]}", then comes "{0[1]}"'.format
>>> for item in map(formatter, data):
    print item


First is "1", then comes "2"
First is "a", then comes "b"
First is "5", then comes "ABC"

是不是比字符串格式化操作灵活很多?

查看documentation page 上的更多示例,以比较% 操作和.format() 方法。

比较基于元组的% 字符串格式与基于字典的格式

一般有三种调用%字符串操作的方式(是的,三个,不是两个):

base_string % values

它们的区别在于values 的类型(这是base_string 内容的结果):

  • 可以是tuple,然后按照它们在元组中出现的顺序一个一个替换,

    >>> 'Three first values are: %f, %f and %f' % (3.14, 2.71, 1)
    'Three first values are: 3.140000, 2.710000 and 1.000000'
    
  • 可以是dict(字典),然后根据关键字替换它们,

    >>> 'My name is %(name)s, I am %(age)s years old' % {'name':'John','age':98}
    'My name is John, I am 98 years old'
    
  • 它可以是单个值,如果 base_string 包含应该插入值的单个位置:

    >>> 'This is a string: %s' % 'abc'
    'This is a string: abc'
    

它们之间有明显的区别,这些方法不能组合(与format()方法相反,它可以组合一些特性,如上所述)。

但是有一些东西只针对基于字典的字符串格式化操作,并且在其余三种格式化操作类型中是不可用的。这是能够以简单的方式将说明符替换为实际变量名:

>>> name = 'John'
>>> surname = 'Smith'
>>> age = 87
# some code goes here
>>> 'My name is %(surname)s, %(name)s %(surname)s. I am %(age)i.' % locals()
'My name is Smith, John Smith. I am 87.'

仅作记录:当然可以通过像这样解包字典来使用format()轻松替换上述内容:

>>> 'My name is {surname}, {name} {surname}. I am {age}.'.format(**locals())
'My name is Smith, John Smith. I am 87.'

有没有人知道什么是特定于一种字符串格式化操作的功能,而不是另一种?听到它可能会很有趣。

【讨论】:

  • .format() 太棒了。我不知道*diff 扩展,所以感谢您的提示;)
  • 两个答案都很好,我对format() 了解不多。但是,有关% 格式的任何信息? (这是重点)
  • @julio.alegria:我已经用您可以使用基于字典的字符串操作的方式的示例更新了我的答案 - 这种方式非常有用并且不容易被基于元组的操作取代.
  • locals()!天才!也不知道。 % 拥有和 format() 没有出现在我脑海中的一个功能是“转换”(我不确定这是否是正确的名称),例如:%2.6f.. 这在某些时候真的很常用。
  • @julio.alegria:谢谢!说到“转换”,我相信您说的是(来自 M. Lutz 的“Learning Python. 4th Edition”):“浮点数支持相同的类型代码和格式化方法调用中的格式化特异性,如 % 表达式。"。换句话说,例如。 '%2.6f' % .123456789123 和 '{:2.6f}'.format(.123456789123) 都给你'0.123457'。所以,基本上,format() 具有% 操作的这个特定功能。
【解决方案2】:

我并没有完全回答你的问题,只是认为将format 加入你的组合会很好。

我个人更喜欢format 的语法:

'I will be {years} on {month} {day}'.format(years=19, month='January', day=23)

如果我想要一些紧凑的东西,我就写:

'I will be {} on {} {}'.format(19, 'January', 23)

而format 可以很好地处理对象:

class Birthday:
  def __init__(self, age, month, day):
    self.age = age
    self.month = month
    self.day = day

print 'I will be {b.age} on {b.month} {b.day}'.format(b = Birthday(19, 'January', 23))

【讨论】:

  • +1 关于对象的要点。我也更喜欢format()。我通过展示如何使用 format() 将两种格式化方式(如 OP 所述)组合到单个调用中的示例,以某种方式扩展了您的答案。
  • 两个答案都很好,我对format() 了解不多。但是,有关% 格式的任何信息? (这是重点)
【解决方案3】:

我不是在回答这个问题,只是解释我在TIScript 中提出的想法。

我已经介绍了所谓的“stringizer”函数:任何名称以 '$' 开头的函数都是 stringizer。编译器将 '$name(' 和 ')' 视为字符串文字的引号并结合函数调用。

例如,这个:

$print(I will be {b.age} on {b.month} {b.day});

实际上是编译成

$print("I will be ", b.age, " on ",b.month," ",b.day);

其中偶数参数始终是文字字符串,奇数参数是表达式。这样就可以定义使用不同格式/参数处理的自定义字符串化器。

例如Element.$html(Hello <b>{who}</b>); 将对表达式应用 HTML 转义。而这个Element.$(option[value={12}]); 将以jQuery 风格进行选择。

非常方便灵活。

我不确定是否可以在不更改编译器的情况下在 Python 中执行类似的操作。考虑只是一个想法。

【讨论】:

  • 实际上我不相信 Python 会欢迎这样的事情,不仅因为这需要更改语法。还有一条规则说显式优于隐式。但是,您可以通过自定义方法/函数轻松完成您所做的事情,这将预处理参数并将它们传递给您所指字符串的 format() 方法。甚至类似的东西:'Hello <b>{who}</b>'.format(**escape_html(some_data))。不过,在 Python 中没什么大不了的。
  • 很抱歉,但我将不得不对不回答问题或发布任何与 Python 相关的答案投反对票
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-22
  • 1970-01-01
  • 1970-01-01
  • 2016-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多