为什么 Python 代码使用 len() 函数而不是 length 方法?
-
04-07-2019 - |
题
我知道 python 有一个 len()
用于确定字符串大小的函数,但我想知道为什么它不是字符串对象的方法。
更新
好吧,我意识到我犯了一个令人尴尬的错误。 __len__()
实际上是一个字符串对象的方法。在 Python 中看到在字符串对象上使用 len 函数的面向对象代码似乎很奇怪。另外,看到也很奇怪 __len__
作为名称而不仅仅是 len。
解决方案
字符串有一个长度方法: __ len __()
Python中的协议是在具有长度的对象上实现此方法并使用内置的 len()
函数,它为你调用它,类似于你实现 __ iter __()的方式
并在可迭代的对象上使用内置的 iter()
函数(或者在幕后调用方法)。
有关详细信息,请参阅模拟容器类型。
以下是关于Python协议主题的精彩读物: Python和最小惊讶原则
其他提示
Jim对这个问题的回答可能有所帮助;我把它复制在这里。引用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‘作为内置操作。我不想失去那个。 /… /
有 len
方法:
>>> a = 'a string of some length'
>>> a.__len__()
23
>>> a.__len__
<method-wrapper '__len__' of str object at 0x02005650>
Python是一种实用的编程语言, len()
是一个函数而不是 str
, list
的方法的原因, dict
等是务实的。
len()
内置函数直接处理内置类型: len()
的CPython实现实际上返回 ob_size的值
字段>表示内存中任何可变大小的内置对象。这比调用方法更快 - 不需要进行属性查找。获取集合中的项目数是一项常见操作,必须有效地处理 PyVarObject
C struct 中的 str
, list
, array.array
等。
但是,为了提高一致性,在将 len(o)
应用于用户定义的类型时,Python将 o .__ len __()
作为后备调用。 __ len __
, __ abs __
以及中记录的所有其他特殊方法Python数据模型可以轻松创建行为类似于内置插件的对象,从而实现我们称之为“Pythonic”的富有表现力且高度一致的API。
通过实现特殊方法,您的对象可以支持迭代,重载中缀运算符,使用 块等来管理 中的上下文。您可以将数据模型视为一种使用方式Python语言本身作为一个框架,您创建的对象可以无缝集成。
第二个原因,由Guido van Rossum的引言支持,如这个,它比更容易读写
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.
这里有一些很好的答案,所以在我给出自己的答案之前,我想强调一下我在这里读到的一些宝石(没有红宝石双关语的意思)。
- 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
你也可以说
>> x = 'test'
>> len(x)
4
使用Python 2.7.3。
不是吗?
>>> "abc".__len__()
3