例子:
a_list = [1, 2, 3]
a_list.len() # doesn't work
len(a_list) # works
Python(非常)面向对象,我不明白为什么'len'函数不被对象继承。另外,我一直在尝试错误的解决方案,因为它对我来说似乎是合乎逻辑的
例子:
a_list = [1, 2, 3]
a_list.len() # doesn't work
len(a_list) # works
Python(非常)面向对象,我不明白为什么'len'函数不被对象继承。另外,我一直在尝试错误的解决方案,因为它对我来说似乎是合乎逻辑的
Guido的解释在这里:
首先,出于 HCI 的原因,我选择了 len(x) 而不是 x.len()(def __len__() 来得晚得多)。实际上有两个相互交织的原因,都是 HCI:
(a) 对于某些运算,前缀符号比后缀读起来更好——前缀(和中缀!)运算在数学中有着悠久的传统,它喜欢视觉帮助数学家思考问题的符号。比较我们将像 x*(a+b) 这样的公式重写为 x*a + x*b 的简单性与使用原始 OO 表示法做同样事情的笨拙。
(b) 当我读到 len(x) 的代码时,我知道它是在询问某物的长度。这告诉我两件事:结果是一个整数,而参数是某种容器。相反,当我阅读 x.len() 时,我必须已经知道 x 是某种实现接口或继承自具有标准 len() 的类的容器。当一个没有实现映射的类有一个 get() 或 keys() 方法,或者不是文件的东西有一个 write() 方法时,我们偶尔会感到困惑。
以另一种方式说同样的话,我将“len”视为内置操作。我不想失去那个。/…/
简短的回答:1)向后兼容性和 2)没有足够的区别让它真正重要。有关更详细的说明,请继续阅读。
此类操作的惯用 Python 方法是不打算直接调用的特殊方法。例如,要x + y
为您自己的类工作,您编写一个__add__
方法。要确保int(spam)
正确转换您的自定义类,请编写一个__int__
方法。为了确保这样len(foo)
做是明智的,请编写一个__len__
方法。
这就是 Python 一直以来的情况,我认为这对某些事情很有意义。特别是,这似乎是实现运算符重载的明智方法。至于其余的,不同的语言不同意;在 Ruby 中,您可以通过spam.to_i
直接调用而不是说int(spam)
.
没错,Python 是一种非常面向对象的语言,并且必须在对象上调用外部函数来获取其长度似乎很奇怪。另一方面,len(silly_walks)
并不比 更繁琐silly_walks.len()
,Guido 说他实际上更喜欢它 ( http://mail.python.org/pipermail/python-3000/2006-November/004643.html )。
它只是不是。
但是,您可以这样做:
>>> [1,2,3].__len__()
3
向类添加__len__()
方法是使len()
魔术起作用的原因。
这种方式更适合语言的其余部分。python 中的约定是__foo__
向对象添加特殊方法以使它们具有某些功能(而不是例如从特定的基类派生)。例如,一个对象是
__call__
方法 ,则可调用__iter__
方法,则可迭代,__getitem__
和 ,则支持使用 [] 访问__setitem__
。这些特殊方法之一是__len__
使其具有可访问的长度len()
。
也许您正在寻找__len__
. 如果该方法存在,则 len(a) 调用它:
>>> class Spam:
... def __len__(self): return 3
...
>>> s = Spam()
>>> len(s)
3
好吧,实际上有一个长度方法,它只是被隐藏了:
>>> a_list = [1, 2, 3]
>>> a_list.__len__()
3
len() 内置函数似乎只是一个包装器,用于调用对象的隐藏len () 方法。
不知道为什么他们决定以这种方式实施事情。
下面有一些很好的信息,说明为什么某些事物是函数而其他事物是方法。它确实会导致语言中的一些不一致。
http://mail.python.org/pipermail/python-dev/2008-January/076612.html