为啥 Python 中的字典和列表不继承 'len' 函数
Posted
技术标签:
【中文标题】为啥 Python 中的字典和列表不继承 \'len\' 函数【英文标题】:Why isn't the 'len' function inherited by dictionaries and lists in Python为什么 Python 中的字典和列表不继承 'len' 函数 【发布时间】:2008-09-17 14:43:18 【问题描述】:示例:
a_list = [1, 2, 3]
a_list.len() # doesn't work
len(a_list) # works
Python(非常)面向对象,我不明白为什么“len”函数不被对象继承。 另外,我一直在尝试错误的解决方案,因为它对我来说似乎是合乎逻辑的解决方案
【问题讨论】:
函数不会被继承。方法是。您想继承谁的对象的len
方法?
这无关紧要,因为 len 只是调用 len 方法,所以同样的继承问题仍然适用。
@Eli 你的意思是__len__
方法——所以将双下划线解释为粗体。 =)
【参考方案1】:
Guido 的解释是here:
首先,出于 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”视为内置操作。我不想失去那个。 /…/
【讨论】:
对于那些不知道的人来说,HCI 代表人机界面。因此,当 Guido 说他出于“HCI 原因”做出决定时,他是说他认为这使代码更具可读性。 @Thomas:Python 使用|
进行按位或,就像 C 一样。
Guido 认为泛型函数比方法更好。头脑一片混乱。 ://【参考方案2】:
简短的回答: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)。
【讨论】:
啊……终于明白了。 len() 实际上更像是一个运算符而不是一个函数。【参考方案3】:事实并非如此。
但是,您可以这样做:
>>> [1,2,3].__len__()
3
将__len__()
方法添加到类中是使len()
发挥作用的原因。
【讨论】:
【参考方案4】:这种方式更适合其他语言。 python 中的约定是向对象添加__foo__
特殊方法以使它们具有某些功能(而不是例如从特定的基类派生)。例如,一个对象是
__call__
方法则可调用
如果它有 __iter__
方法,则可迭代,
如果有__getitem__
和__setitem__
,则支持使用[] 访问。
...
这些特殊方法之一是__len__
,这使得它具有可通过len()
访问的长度。
【讨论】:
【参考方案5】:也许您正在寻找__len__
。如果该方法存在,则 len(a) 调用它:
>>> class Spam:
... def __len__(self): return 3
...
>>> s = Spam()
>>> len(s)
3
【讨论】:
【参考方案6】:嗯,其实还有一个length方法,只是隐藏起来了:
>>> a_list = [1, 2, 3]
>>> a_list.__len__()
3
len() 内置函数似乎只是一个包装器,用于调用对象的隐藏 len() 方法。
不知道为什么他们决定以这种方式实施。
【讨论】:
【参考方案7】:下面有一些很好的信息,说明为什么某些事物是函数而其他事物是方法。它确实会导致语言中的一些不一致。
http://mail.python.org/pipermail/python-dev/2008-January/076612.html
【讨论】:
以上是关于为啥 Python 中的字典和列表不继承 'len' 函数的主要内容,如果未能解决你的问题,请参考以下文章
Python3基础 __len__,__getitem__ 记录列表中元素访问的次数 定制不可变序列,下标字典