【问题标题】: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__ 方法——所以将双下划线解释为粗体。 =)

标签: python


【解决方案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

          【讨论】:

            猜你喜欢
            • 2020-05-12
            • 1970-01-01
            • 1970-01-01
            • 2020-02-28
            • 2013-08-27
            • 1970-01-01
            • 2015-10-18
            • 1970-01-01
            • 2021-10-26
            相关资源
            最近更新 更多