为什么Python有格式函数和格式方法

时间:2013-05-22 04:33:40

标签: python string format python-2.6 built-in

builtins中的format函数似乎是str.format方法的一个子集,专门用于格式化单个对象的情况。

例如。

>>> format(13, 'x')
'd'

显然优于

>>> '{0:x}'.format(13)
'd'

和IMO确实看起来更好,但为什么不在每种情况下都使用str.format来简化事情呢?这两个都是在2.6中引入的,所以必须有充分的理由同时拥有它们,它是什么?

修改:我问的是str.formatformat,而不是我们没有(13).format

的原因

2 个答案:

答案 0 :(得分:37)

tldr; format只需调用obj.__format__并由str.format方法使用,该方法可以执行更高级别的操作。对于较低级别,教会对象如何格式化自己是有意义的。

这只是语法糖

此函数与str.format共享名称和格式规范的事实可能会产生误导。 str.format的存在很容易解释:它执行复杂的字符串插值(替换旧的%运算符); format可以将单个对象格式化为字符串,即str.format规范的最小子集。那么,为什么我们需要format

format函数是某些OO种语言中obj.format('fmt')构造的替代品。此决定与len的基本原理一致(为什么Python使用函数len(x)而不是像Javascript或Ruby这样的属性x.length

当语言采用obj.format('fmt')构造(或obj.lengthobj.toString等)时,将阻止类具有名为format的属性(或{{1 }},length,你有了这个想法) - 否则它会影响语言中的标准方法。在这种情况下,语言设计者将负责防止名称冲突给程序员。

Python非常喜欢PoLA并采用内置函数的toString(双下划线)约定,以最大限度地减少用户定义属性与语言内置函数之间发生冲突的可能性。因此__dunder__变为obj.format('fmt'),当然您可以拨打obj.__format__('fmt')而不是obj.__format__('fmt')(与调用format(obj, 'fmt')而不是obj.__len__()的方式相同)。

使用您的示例:

len(obj)

哪一个更干净,更容易打字? Python设计非常实用,它不仅更清晰,而且与Python duck-typed OO方法完全一致,并使语言设计人员可以自由地更改/扩展底层实现,而不会破坏传统代码。

PEP 3101引入了新的>>> '{0:x}'.format(13) 'd' >>> (13).__format__('x') 'd' >>> format(13, 'x') 'd' 方法和内置str.format,但没有对format函数的基本原理发表任何评论,但实现显然只是{{ 3}}:

format

在这里,我休息一下。

Guido说了什么(或者是官方的?)

引用syntactic sugar关于def format(value, format_spec): return value.__format__(format_spec)

BDFL
  

首先,由于HCI原因我选择了len而不是len(x)x.len()后来发生了这种情况)。实际上有两个相互交织的原因,HCI

     

(a)对于某些操作,前缀表示法只读取比后缀更好 - 前缀(和中缀!)操作在数学中有悠久的传统,它喜欢视觉效果帮助数学家思考问题的符号。比较我们将def __len__()这样的公式重写为x*(a+b)的简单性,以及使用原始OO表示法做同样事情的笨拙。

     

(b)当我阅读代码x*a + x*b时,我知道它要求的是某些东西的长度。这告诉我两件事:结果是一个整数,参数是某种容器。相反,当我阅读len(x)时,我必须知道x.len()是某种实现接口的容器,或者是从具有标准x的类继承的。当没有实现映射的类具有len()get()方法,或者不是文件的类具有keys()方法时,我们偶尔会遇到混淆。

     

以另一种方式说同样的事情,我将'write()'视为内置操作。我不想失去那个。 / ... /

来源:pyfaq@effbot.org(原帖here也有Guido回答的原始问题)。 Abarnert还建议:

  

Design and History FAQ中还有关于len的其他推理。虽然它不完整或不是一个好的答案,但它无可争议地是官方的。 - abarnert

这是一个实际问题还是只是语法上的挑剔?

这在Python,Ruby或Javascript等语言中非常实用且真实,因为在动态类型语言中,任何可变对象实际上都是命名空间,私有方法或属性的概念是一个问题。惯例。可能我在评论中不能比abarnert更好:

  

此外,就Ruby和JS的名称空间污染问题而言,值得指出的是,这是动态类型语言的固有问题。在像Haskell和C ++这样多种类型的静态类型语言中,特定于类型的自由函数不仅是可行的,而且是惯用的。 (参见Interface Principle。)但是在Ruby,JS和Python等动态类型语言中,自由函数必须是通用的。动态语言的语言/库设计的很大一部分是选择正确的这类函数。

例如,我刚刚Ember.js支持Angular.js,因为I was tired of namespace conflicts in Ember; Angular使用优雅的类似Python的策略来处理这个问题,该策略为内置方法添加前缀(在Angular中使用len,而不是像python那样使用下划线),因此它们不会与用户定义的方法和属性冲突。是的,整个$thing并不是特别漂亮,但我很高兴Python采用这种方法,因为它非常明确,避免了有关对象命名空间冲突的PoLA类错误。

答案 1 :(得分:6)

我认为formatstr.format做了不同的事情。即使你可以使用str.format,但是有了单独的版本也是有意义的。

顶级format函数是所有对象都支持的新“格式化协议”的一部分。它只是调用传递的对象的__format__方法,并返回一个字符串。这是一个低级别的任务,Python的风格通常是为那些内置函数。 Paulo Scardine的回答解释了这方面的一些基本原理,但我认为它并没有真正解决formatstr.format之间的差异。

str.format方法有点高级,也有点复杂。它不仅可以将多个对象格式化为单个结果,还可以对对象进行重新排序,重复,索引和执行各种其他转换。不要只考虑"{}".format(obj)str.format实际上是为了更复杂的任务而设计的,例如:

"{1} {0} {1!r}".format(obj0, obj1) # reorders, repeats, and and calls repr on obj1
"{0.value:.{0.precision}f}".format(obj) # uses attrs of obj for value and format spec
"{obj[name]}".format(obj=my_dict) # takes argument by keyword, and does an item lookup

对于每个项目的低级格式化,str.format依赖于格式协议的相同机制,因此它可以将自己的工作集中在更高级别的东西上。我怀疑它实际上是调用内置format,而不是它的参数'__format__方法,但这是一个实现细节。

虽然("{"+format_code+"}").format(obj)保证提供与format(obj, format_code)相同的结果,但我怀疑后者会更快一些,因为它不需要解析格式字符串来检查任何一个复杂的东西。但是,实际程序中的噪声可能会丢失开销。

当涉及到使用时(包括Stack Overflow上的示例),您可能会看到更多str.format使用,因为一些程序员不了解format,这既新又相当模糊。相比之下,很难避免str.format(除非您决定坚持使用%运算符进行所有格式设置)。因此,理解str.format调用的容易程度(对于您和您的程序员)可能超过任何性能考虑因素。