我知道python有一个len()
函数用于确定字符串的大小,但我想知道为什么它不是字符串对象的方法。
好的,我意识到我很尴尬。 __len__()
实际上是一个字符串对象的方法。使用字符串对象上的len函数在Python中看到面向对象的代码似乎很奇怪。此外,将__len__
视为名称而不仅仅是len。也很奇怪。
答案 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()
作为函数而不是str
,list
,dict
等方法的原因是务实的。< / p>
len()
内置函数直接处理内置类型:len()
的CPython实现实际返回PyVarObject
C struct中ob_size
字段的值表示内存中任何可变大小的内置对象。这比调用方法更快 - 不需要进行属性查找。获取集合中的项目数是一项常见操作,必须能够有效地处理str
,list
,array.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)
这里有一些很好的答案,所以在我自己给出之前,我想强调一些宝石(没有红宝石双关语)我已经在这里阅读了。
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__
方法是否返回非负数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
函数重新分配为全局变量来“覆盖”该函数,但是这样做的代码显然比在类中覆盖某个方法的代码更可疑。
答案 8 :(得分:-1)
不是吗?
>>> "abc".__len__()
3