我在 2013 年问核心开发者 Raymond Hettinger 这个问题时,他用“Python 之禅”里的原话回答了我:“实用胜于纯粹。”在 1.2 节里我提到过,如果 x是一个内置类型的实例,那么 len(x)的速度会非常快。背后的原因是 CPython 会直接从一个 C 结构体里读取对象的长度,完全不会调用任何方法。获取一个集合中元素的数量是一个很常见的操作,在 str、list、memoryview等类型上,这个操作必须高效。
换句话说,len之所以不是一个普通方法,是为了让 Python 自带的数据结构可以走后门,abs也是同理。但是多亏了它是特殊方法,我们也可以把 len用于自定义数据类型。这种处理方式在保持内置类型的效率和保证语言的一致性之间找到了一个平衡点,也印证了“Python 之禅”中的另外一句话:“不能让特例特殊到开始破坏既定规则。”
如果把abs和 len都看作一元运算符的话,你也许更能接受它们——虽然看起来像面向对象语言中的函数,但实际上又不是函数。有一门叫作 ABC 的语言是 Python 的直系祖先,它内置了一个 #运算符,当你写出 #s的时候,它的作用跟 len一样。如果写成 x#s这样的中缀运算符的话,那么它的作用是计算 s中 x出现的次数。在 Python 里对应的写法是 s.count(x)。注意这里的 s是一个序列类型。
——出自该书《1.4 为什么len不是普通方法》
saying = "Hello world!"
print(len(saying))
# 结果:12
String saying = "Hello world!";
System.out.println(saying.length());
// 结果:12
int(s)
函数,而 Java 可以用 Integer.parseInt(s)
;整型数字转化为字符串,Python 可以用 str(i)
,而 Java 也有 String.valueOf(i)
。mylist = [2, 1, 3, 5, 4]
mylist.sort()
print(mylist) # [1, 2, 3, 4, 5]
mylist.reverse()
print(mylist) # [5, 4, 3, 2, 1]
mylist = [2, 1, 3, 5, 4]
sort_list = sorted(mylist)
print(sort_list) # [1, 2, 3, 4, 5]
reverse_list = reversed(mylist)
print(list(reverse_list)) # [4, 5, 3, 1, 2]
x*(a + b)
重写成 x*a + x*b
,但同样的事,以原生的面向对象的方式实现,就比较笨拙。出自《The History of Python: Why Python uses 0-based indexing》
让我们来先看看切片的用法。可能最常见的用法,就是“取前 n 位元素”或“从第i 位索引起,取后 n 位元素”(前一种用法,实际上是 i == 起始位的特殊用法)。如果这两种用法实现时可以不在表达式中出现难看的 +1 或 -1,那将会非常的优雅。
使用 0-based 的索引方式、半开区间切片和缺省匹配区间的话(Python最终采用这样的方式),上面两种情形的切片语法就变得非常漂亮:a[:n] 和 a[i:i+n],前者是 a[0:n] 的缩略写法。