Python语法不一致?
我最近在阅读关于Python的特殊类方法的内容,发现有些方法的语法看起来有点奇怪或者不太一致。
比如,要从字典中获取所有的项目,你需要调用字典的类方法items()。
>>> my_dictionary.items()
[('name', 'Old Gregg'), ('Race', 'Scaly Man-Fish')]
但是,要知道字典中有多少个键,你就需要用len()
这个函数,并把字典作为参数传进去。
>>> len(my_dictionary)
2
我一直以为像len()
这样的函数其实并不是你调用它的那个类的一部分,因为它的语法看起来不太像,但在阅读了《Dive into Python》第五章后,我发现len()
实际上是调用了字典的方法。
my_dictionary.__len__()
那么,为什么它和类似的方法不是像普通的类方法那样被调用呢?
my_dictionary.len()
难道有什么我不知道的约定吗?
3 个回答
这个区分很有用,因为它把使用和来源分开了。当你在给字典类编写扩展时,你知道你是在覆盖一些语言内置的功能。如果你真的想改变一个容器的行为,你需要重写 __len__()
、__getitem__()
等方法。
不过,作为使用别人代码的人,我就不需要担心这些了。如果我用 len(my_dictionary)
,我期待它的表现是稳定的,因为程序员应该知道怎么正确实现 __len__()
。而且,任何人都可以随便写一个 my_dictionary.len() 方法,这样我就不太清楚它的表现了。
想了解更多关于下划线方法的信息,可以参考 http://www.siafoo.net/article/57,里面有很多相关的资料(第2.7.1节讲的是 __len__()
)。
我们不是在讲Java的事情。
在Python中,有很多方法可以用在对象上,只要这些对象实现了相关的API。
len() --> __len__()
str() --> __str__()
repr() --> __repr__()
除此之外:
为什么
my_dictionary.len()
要成为一个方法呢?
在JavaScript中,对象通过'length'属性来显示它们的大小,这样更自然,而不是使用一个方法……抱歉,并不是所有来自Java世界的东西都是好的,也不一定要在其他语言中存在。
Guido van Rossum这样解释:
(a) 对于某些操作,前缀表示法比后缀表示法更容易理解。前缀(还有中缀)操作在数学中有很长的历史,数学家们喜欢用能帮助他们思考问题的符号。比如,我们可以很轻松地把公式x*(a+b)改写成xa + xb,这比用面向对象的原始表示法要简单得多。
(b) 当我看到代码写着len(x)
时,我知道这是在询问某个东西的长度。这让我明白两件事:结果是一个整数,而参数是某种容器。相反,当我看到x.len()
时,我必须已经知道x是某种实现了接口或继承了具有标准len()
方法的类的容器。想想我们有时会遇到的困惑,比如一个并没有实现映射的类却有get()
或keys()
方法,或者某个不是文件的东西却有write()
方法。