Answers:
字符串确实有一个length方法: __len__()
Python中的协议是在具有一定长度并使用内置len()
函数的对象上实现此方法,该内置函数会为您调用该方法,类似于您实现__iter__()
和使用内置iter()
函数的方法(或在后面调用方法)的场景)在可迭代的对象上。
有关更多信息,请参见模拟容器类型。
这是有关Python协议主题的好书:Python和最小惊讶原则
__iter__
或仅创建一个可迭代的对象__getitem__
,并且iter(x)
将以任何一种方式工作。你可以创建一个可用的功能于布尔上下文对象具有__bool__
或__len__
和bool(x)
将工作无论哪种方式。等等。我认为Armin在链接后的文章中对此进行了很好的解释-但是,即使他没有这么做,但由于一个经常公开与核心开发人员发生
zip
是顶级函数,而不是zip_with
方法。等等。仅仅因为一切都是对象,并不意味着成为对象是每件事最重要的事情。
吉姆对这个问题的回答可能会有所帮助。我在这里复制。引用Guido van Rossum:
首先,出于HCI的原因,我选择len(x)而不是x.len()(def __len __()来得很晚)。实际上,两个HCI相互交织在一起:
(a)对于某些运算,前缀表示法比后缀读得更好-前缀(和infix!)运算符在数学中有很长的传统,喜欢在视觉上帮助数学家思考问题的表示法。将我们将x *(a + b)之类的公式重写为x a + x b 的简便性与使用原始OO符号做相同事情的笨拙性进行比较。
(b)当我读到说len(x)的代码时,我知道它是在问某物的长度。这告诉我两件事:结果是整数,参数是某种容器。相反,当我阅读x.len()时,我必须已经知道x是某种实现接口或从具有标准len()的类继承的容器。当未实现映射的类具有get()或keys()方法,或者非文件类具有write()方法时,我们有时会感到困惑。
用另一种方式说同样的事情,我将“ len”视为内置操作。我不想失去那个。/.../
Python是一种务实的编程语言,并为原因len()
是一个功能,而不是一个方法str
,list
,dict
等务实。
的len()
内置函数直接处理的内置类型:CPython的执行len()
实际返回的值ob_size
字段中PyVarObject
的C结构代表任意可变大小的内置存储器中的对象。这是很多比调用一个方法快-无属性的查找需要发生。获取集合中的项目数是一种常见的操作,必须对这些基本类型多样为提高工作效率str
,list
,array.array
等。
但是,为了提高一致性,当应用len(o)
到用户定义的类型时,Python会o.__len__()
作为后备调用。 __len__
,__abs__
和所有其他特殊的记录方法的Python数据模型可以很容易地创建对象,其行为像内置插件,使表现力和高度一致的API,我们称之为“Python化”。
通过实现特殊的方法,您的对象可以支持迭代,重载infix运算符,在with
块中管理上下文等。您可以将数据模型视为一种使用Python语言本身作为框架的方式,您可以在其中无缝集成所创建的对象。
第二个原因,通过报价从吉多·范罗苏姆等支撑这一个,是它更容易阅读和写len(s)
比s.len()
。
该表示法len(s)
与带有前缀表示法的一元运算符一致,例如abs(n)
。len()
的使用频率比更高abs()
,并且应该易于编写。
可能还有一个历史原因:在Python之前的ABC语言中(在其设计中很有影响力),有一个一元运算符,#s
其含义为len(s)
。
met% python -c 'import this' | grep 'only one'
There should be one-- and preferably only one --obvious way to do it.
这里有一些很好的答案,因此在我给出自己的名字之前,我想重点介绍一下我在这里读过的一些宝石(无红宝石双关语)。
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
你也可以说
>> x = 'test'
>> len(x)
4
使用Python 2.7.3。
len
功能已经在前面的答案中提到过。那么,这个“答案”有什么意义呢?
这里的其余答案缺少一些内容: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
通过将其重新分配为全局变量来“覆盖” 函数,但是比起覆盖类中方法的代码,这样做的代码明显更可疑。
len
。他们认为,强迫人们执行.__len__
比强迫人们执行要容易.len()
。它是同一件事,看起来更干净。如果该语言要进行面向对象编程__len__
,那么世界的意思是len(..)