tldr; format
只是调用obj.__format__
并由执行str.format
更高级别操作的方法使用。对于较低级别,教一个对象如何格式化自己是有意义的。
它只是语法糖
这个函数共享名称和格式规范的事实str.format
可能会产生误导。的存在str.format
很容易解释:它做了复杂的字符串插值(替换旧的%
操作符);format
可以将单个对象格式化为字符串,str.format
规范的最小子集。那么,我们为什么需要format
?
该函数是某些OO语言中的构造format
的替代方案。这个决定与(关于为什么 Python 使用函数而不是Javascript或 Ruby之类的属性)的基本原理是一致的。obj.format('fmt')
len
len(x)
x.length
当一种语言采用obj.format('fmt')
构造(或obj.length
,obj.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)
了(来晚得多)。实际上有两个相互交织的原因,都是HCI:x.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类关于对象命名空间冲突的错误。