226

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

更新

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

4

9 回答 9

193

字符串确实有一个长度方法:__len__()

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

有关更多信息,请参阅模拟容器类型

这是关于 Python 协议主题的好读物:Python and the Principle of Least Astonishment

于 2008-10-25T22:51:19.217 回答
103

吉姆对这个问题的回答可能会有所帮助;我在这里复制它。引用 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”视为内置操作。我不想失去那个。/…/

于 2008-10-26T01:11:08.340 回答
37

有一个len方法:

>>> a = 'a string of some length'
>>> a.__len__()
23
>>> a.__len__
<method-wrapper '__len__' of str object at 0x02005650>
于 2008-10-25T22:49:54.163 回答
36

Python 是一种实用的编程语言,len()作为函数而不是 , 等的方法的str原因listdict实用的。

len()内置函数直接处理内置类型:CPython 实现len()实际上返回C 结构中的字段值,该ob_size字段表示内存中任何可变大小的内置对象。这比调用方法快得多——不需要进行属性查找。获取集合中项目的数量是一种常见的操作,并且对于诸如 , 等基本和多样化的类型必须有效地工作。PyVarObjectstrlistarray.array

但是,为了提高一致性,当应用于len(o)用户定义的类型时,Python 调用o.__len__()作为后备。 __len__,以及Python 数据模型__abs__中记录的所有其他特殊方法,可以轻松创建行为类似于内置函数的对象,从而实现我们称之为“Pythonic”的富有表现力和高度一致的 API。

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

第二个原因,得到 Guido van Rossum 这样的引用的支持是它len(s)s.len().

该表示法len(s)与带有前缀表示法的一元运算符一致,例如abs(n). len()比 更经常使用abs(),而且它应该很容易编写。

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

于 2014-04-21T07:19:39.380 回答
12
met% python -c 'import this' | grep 'only one'
There should be one-- and preferably only one --obvious way to do it.
于 2008-10-25T22:38:58.227 回答
4

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

  • 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
于 2017-02-28T03:06:58.460 回答
2

这里的其他答案缺少一些东西:该len函数检查该__len__方法是否返回一个非负数int。这是一个函数的事实len意味着类不能覆盖此行为以避免检查。因此,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通过将函数重新分配为全局变量来“覆盖”该函数,但是这样做的代码比覆盖类中方法的代码更明显可疑。

于 2019-12-02T19:40:07.543 回答
-1

你也可以说

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

使用 Python 2.7.3。

于 2013-01-04T23:44:59.463 回答
-2

它没有?

>>> "abc".__len__()
3
于 2008-10-26T01:50:18.153 回答