17

例子:

a_list = [1, 2, 3]
a_list.len() # doesn't work
len(a_list) # works

Python(非常)面向对象,我不明白为什么'len'函数不被对象继承。另外,我一直在尝试错误的解决方案,因为它对我来说似乎是合乎逻辑的

4

7 回答 7

44

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”视为内置操作。我不想失去那个。/…/

于 2008-09-17T14:59:53.907 回答
12

简短的回答: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 )。

于 2008-09-17T14:59:54.263 回答
11

它只是不是。

但是,您可以这样做:

>>> [1,2,3].__len__()

3

向类添加__len__()方法是使len()魔术起作用的原因。

于 2008-09-17T14:46:56.777 回答
6

这种方式更适合语言的其余部分。python 中的约定是__foo__向对象添加特殊方法以使它们具有某些功能(而不是例如从特定的基类派生)。例如,一个对象是

  • 如果它有__call__方法 ,则可调用
  • 如果它有__iter__方法,则可迭代,
  • 如果有__getitem__和 ,则支持使用 [] 访问__setitem__
  • ...

这些特殊方法之一是__len__使其具有可访问的长度len()

于 2008-09-17T15:04:16.907 回答
2

也许您正在寻找__len__. 如果该方法存在,则 len(a) 调用它:

>>> class Spam:
...   def __len__(self): return 3
... 
>>> s = Spam()
>>> len(s)
3
于 2008-09-17T14:46:43.173 回答
2

好吧,实际上有一个长度方法,它只是被隐藏了:

>>> a_list = [1, 2, 3]
>>> a_list.__len__()
3

len() 内置函数似乎只是一个包装器,用于调用对象的隐藏len () 方法。

不知道为什么他们决定以这种方式实施事情。

于 2008-09-17T14:48:37.413 回答
2

下面有一些很好的信息,说明为什么某些事物是函数而其他事物是方法。它确实会导致语言中的一些不一致。

http://mail.python.org/pipermail/python-dev/2008-January/076612.html

于 2008-09-17T15:16:26.457 回答