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

2024-06-02 17:11:50 发布

您现在位置:Python中文网/ 问答频道 /正文

内置函数中的^{}函数似乎是专门用于格式化单个对象的^{}方法的子集。

例如

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

显然比

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

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

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


Tags: 对象方法函数format编辑情况事情内置
2条回答

我认为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_spec+"}").format(obj)可以保证给出与format(obj, format_spec)相同的结果,但我怀疑后者会更快一些,因为它不需要解析格式字符串来检查任何复杂的内容。然而,在实际程序中,开销可能会在噪声中丢失。

当谈到使用(包括堆栈溢出的例子)时,您可能会看到更多的str.format使用,这仅仅是因为一些程序员不知道format,这是新的,而且相当模糊。相反,很难避免str.format(除非您决定对所有格式使用%运算符)。因此,理解一个str.format调用的容易程度(对您和您的程序员同事来说)可能超过任何性能考虑。

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(或者lengthtoString的属性,这是你的主意)否则它会使标准方法与该语言相形见绌。在这种情况下,语言设计者将防止名称冲突的责任推给程序员。

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的duck-typed方法很好地结合在一起,使语言设计者可以自由地更改/扩展底层实现,而不破坏遗留代码。

PEP 3101引入了新的str.format方法和format内置,没有对format函数的基本原理做任何评论,但是实现显然只是syntactic sugar

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

我把箱子放在这里。

圭多怎么说的(还是官方的?)

引用关于lenBDFL

First of all, I chose len(x) over x.len() for HCI reasons (def __len__() came much later). There are two intertwined reasons actually, both HCI:

(a) For some operations, prefix notation just reads better than postfix — prefix (and infix!) operations have a long tradition in mathematics which likes notations where the visuals help the mathematician thinking about a problem. Compare the easy with which we rewrite a formula like x*(a+b) into x*a + x*b to the clumsiness of doing the same thing using a raw OO notation.

(b) When I read code that says len(x) I know that it is asking for the length of something. This tells me two things: the result is an integer, and the argument is some kind of container. To the contrary, when I read x.len(), I have to already know that x is some kind of container implementing an interface or inheriting from a class that has a standard len(). Witness the confusion we occasionally have when a class that is not implementing a mapping has a get() or keys() method, or something that isn’t a file has a write() method.

Saying the same thing in another way, I see ‘len‘ as a built-in operation. I’d hate to lose that. /…/

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

There's additional reasoning about len in the Design and History FAQ. Although it's not as complete or as good of an answer, it is indisputably official. – abarnert

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

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

Also, as far as the namespace-pollution issue with Ruby and JS, it's worth pointing out that this is an inherent problem with dynamically-typed languages. In statically-typed languages as diverse as Haskell and C++, type-specific free functions are not only possible, but idiomatic. (See The Interface Principle.) But in dynamically-typed languages like Ruby, JS, and Python, free functions must be universal. A big part of language/library design for dynamic languages is picking the right set of such functions.

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

相关问题 更多 >