为什么Python代码使用len()函数而不是length方法?

时间:2008-10-25 22:37:03

标签: python function oop methods string-length

我知道python有一个len()函数用于确定字符串的大小,但我想知道为什么它不是字符串对象的方法。

更新

好的,我意识到我很尴尬。 __len__()实际上是一个字符串对象的方法。使用字符串对象上的len函数在Python中看到面向对象的代码似乎很奇怪。此外,将__len__视为名称而不仅仅是len。也很奇怪。

9 个答案:

答案 0 :(得分:170)

字符串有长度方法:__len__()

Python中的协议是在具有长度的对象上实现此方法,并使用内置的len()函数,该函数为您调用它,类似于实现__iter__()和在可迭代的对象上使用内置的iter()函数(或者在幕后调用方法)。

有关详细信息,请参阅Emulating container types

以下是关于Python协议主题的精彩读物:Python and the Principle of Least Astonishment

答案 1 :(得分:84)

Jim对this question的回答可能有所帮助;我把它复制在这里。引用Guido van Rossum:

  

首先,由于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'视为内置操作。我不想失去那个。 / ... /

答案 2 :(得分:37)

len方法:

>>> a = 'a string of some length'
>>> a.__len__()
23
>>> a.__len__
<method-wrapper '__len__' of str object at 0x02005650>

答案 3 :(得分:30)

Python是一种实用的编程语言,len()作为函数而不是strlistdict等方法的原因是务实的。< / p>

len()内置函数直接处理内置类型:len()的CPython实现实际返回PyVarObject C structob_size字段的值表示内存中任何可变大小的内置对象。这比调用方法更快 - 不需要进行属性查找。获取集合中的项目数是一项常见操作,必须能够有效地处理strlistarray.array等基本和多样的类型。

但是,为了提高一致性,在将len(o)应用于用户定义的类型时,Python会调用o.__len__()作为后备。 __len____abs__以及Python Data Model中记录的所有其他特殊方法可以轻松创建与内置函数类似的对象,从而实现我们称之为表达性和高度一致性的API# 34; Python化&#34 ;.

通过实现特殊方法,您的对象可以支持迭代,重载中缀运算符,管理 with 块中的上下文等。您可以将数据模型视为使用Python语言的一种方式它本身就是一个框架,您创建的对象可以无缝集成。

第二个原因,由Guido van Rossum引用支持,如this one,是len(s)s.len()更容易阅读和写作。

符号len(s)与带有前缀表示法的一元运算符一致,如abs(n)len()的使用频率高于abs(),并且它应该像编写一样容易。

可能还有一个历史原因:在Python之前的ABC语言中(并且在设计中非常有影响力),有一个一元运算符写为#s,意思是len(s)

答案 4 :(得分:12)

met% python -c 'import this' | grep 'only one'
There should be one-- and preferably only one --obvious way to do it.

答案 5 :(得分:3)

这里有一些很好的答案,所以在我自己给出之前,我想强调一些宝石(没有红宝石双关语)我已经在这里阅读了。

  • Python不是纯粹的OOP语言 - 它是一种通用的,多范式的语言,允许程序员使用他们最熟悉的范例和/或最适合他们解决方案的范例。
  • Python具有一流的功能,因此len实际上是一个对象。另一方面,Ruby没有一流的功能。因此,len函数对象具有自己的方法,您可以通过运行dir(len)来检查它。

如果您不喜欢这种方式在您自己的代码中工作,那么使用您首选的方法重新实现容器是很简单的(参见下面的示例)。

>>> class List(list):
...     def len(self):
...         return len(self)
...
>>> class Dict(dict):
...     def len(self):
...         return len(self)
...
>>> class Tuple(tuple):
...     def len(self):
...         return len(self)
...
>>> class Set(set):
...     def len(self):
...         return len(self)
...
>>> my_list = List([1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'])
>>> my_dict = Dict({'key': 'value', 'site': 'stackoverflow'})
>>> my_set = Set({1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'})
>>> my_tuple = Tuple((1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'))
>>> my_containers = Tuple((my_list, my_dict, my_set, my_tuple))
>>>
>>> for container in my_containers:
...     print container.len()
...
15
2
15
15

答案 6 :(得分:1)

你也可以说

>> x = 'test'
>> len(x)
4

使用Python 2.7.3。

答案 7 :(得分:0)

此处其余答案缺少某些内容:len函数检查__len__方法是否返回非负数intlen是一个函数的事实意味着,类无法重写此行为以避免进行检查。因此,len(obj)的安全级别是obj.len()无法达到的。

示例:

>>> class A:
...     def __len__(self):
...         return 'foo'
...
>>> len(A())
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    len(A())
TypeError: 'str' object cannot be interpreted as an integer
>>> class B:
...     def __len__(self):
...         return -1
... 
>>> len(B())
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    len(B())
ValueError: __len__() should return >= 0

当然,可以通过将len函数重新分配为全局变量来“覆盖”该函数,但是这样做的代码显然比在类中覆盖某个方法的代码更可疑。

答案 8 :(得分:-1)

不是吗?

>>> "abc".__len__()
3