38

format内置函数似乎是str.format专门用于格式化单个对象的方法的子集。

例如。

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

显然是首选

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

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

编辑:我在问str.formatand format,而不是为什么我们没有(13).format

4

2 回答 2

41

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

它只是语法糖

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

该函数是某些OO语言中的构造format的替代方案。这个决定与(关于为什么 Python 使用函数而不是Javascript或 Ruby之类的属性)的基本原理是一致的。obj.format('fmt')lenlen(x)x.length

当一种语言采用obj.format('fmt')构造(或obj.lengthobj.toString等等)时,会阻止类具有称为format(或length,,,toString你明白了)的属性 - 否则它将掩盖语言的标准方法。在这种情况下,语言设计者将防止名称冲突的负担放在程序员身上。

Python 非常喜欢PoLA并且对内置函数采用__dunder__(双下划线)约定,以最大限度地减少用户定义的属性和语言内置函数之间发生冲突的可能性。所以obj.format('fmt')就变成obj.__format__('fmt')了,当然你可以调用obj.__format__('fmt')而不是format(obj, 'fmt')(同样的方式你可以调用obj.__len__()而不是len(obj))。

使用您的示例:

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

哪一个更干净,更容易打字?Python 设计非常实用,它不仅更简洁,而且与 Python 的鸭式OO方法非常一致,并且让语言设计人员可以自由地更改/扩展底层实现,而不会破坏遗留代码。

PEP 3101引入了新str.format方法并format内置,没有对函数的基本原理进行任何评论,format但实现显然只是语法糖

def format(value, format_spec):
    return value.__format__(format_spec)

我在这里休息一下。

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

引用非常BDFL关于len

首先,我出于HCI的原因选择len(x)了(来晚得多)。实际上有两个相互交织的原因,都是HCIx.len()def __len__()

(a) 对于某些运算,前缀符号比后缀读起来更好——前缀(和中缀!)运算在数学中有着悠久的传统,它喜欢视觉帮助数学家思考问题的符号。将我们重写公式的简单性与使用原始 OO 表示法做同样事情的笨拙进行比较x*(a+b)x*a + x*b

(b) 当我读到代码时,len(x)我知道它在询问某事的长度。这告诉我两件事:结果是一个整数,而参数是某种容器。相反,当我阅读时x.len(),我必须已经知道这x是某种实现接口或继承自具有标准的类的容器len()。当一个没有实现映射的类有一个get()orkeys()方法,或者不是一个文件的东西有一个方法时,我们偶尔会感到困惑write()

以另一种方式说同样的话,我将 '<code>len' 视为内置操作。我不想失去那个。/…/

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

设计和历史常见问题解答中还有关于 len 的其他推理。尽管它没有那么完整或很好的答案,但它无疑是官方的。–阿巴纳特

这是一个实际问题还是只是语法吹毛求疵?

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

此外,就 Ruby 和 JS 的命名空间污染问题而言,值得指出的是,这是动态类型语言的固有问题。在 Haskell 和 C++ 等多种静态类型语言中,类型特定的自由函数不仅是可能的,而且是惯用的。(请参阅接口原则。)但在 Ruby、JS 和 Python 等动态类型语言中,自由函数必须是通用的。动态语言的语言/库设计的很大一部分是选择正确的此类功能集。

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

于 2013-05-22T05:09:44.933 回答
8

我思考formatstr.format做不同的事情。即使您可以同时使用str.format两者,但拥有单独的版本是有意义的。

顶层format函数是所有对象都支持的新“格式化协议”的一部分。它只是调用__format__它传递的对象的方法,并返回一个字符串。这是一项低级任务,Python 的风格通常是为这些任务提供内置函数。formatPaulo Scardine 的回答解释了其中的一些基本原理,但我认为它并没有真正解决做什么和做什么之间的区别str.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依赖于格式协议的相同机制,因此它可以将自己的精力集中在更高级别的东西上。我怀疑它实际上调用了 builtin format,而不是它的参数的__format__方法,但这是一个实现细节。

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

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

于 2013-05-22T22:37:58.580 回答