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

fue*_*sjr 196 python oop methods function string-length

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

更新

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

Jon*_*nan 171

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

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

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

以下是关于Python协议主题的很好的阅读:Python和最小惊讶原则

  • 令人惊讶的是,使用"len"的原因是多么愚蠢.他们认为强迫人们实施`.__ len__`比强迫人们实现`.len()`更容易.它是一样的,一个看起来更清洁.如果语言将有一个OOP`__len__`,那么世界上什么是制造`len(..)` (116认同)
  • len,str等可以与高阶函数一起使用,例如map,reduce和filter,而不需要定义函数或lambda来调用方法.并非一切都围绕着OOP,即使在Python中也是如此. (34认同)
  • 此外,通过使用协议,他们可以提供实现事物的替代方法.例如,您可以使用`__iter__`创建一个iterable,或者只使用`__getitem__`创建一个iterable,并且`iter(x)`将以任何方式工作.您可以使用`__bool__`或`__len__`创建一个可用的bool上下文对象,并且`bool(x)`将以任一方式工作.等等.我认为Armin在链接后的帖子中解释得相当好 - 但即使他没有,因为一个经常公开与核心开发人员不一致的人的外部解释而称为Python moronic并不完全公平...... (10认同)
  • @Evicatos:+1代表"并非一切都围绕着OOP",但我的结尾是"_es special_ in Python",而不是_even_.Python(与Java,Ruby或Smalltalk不同)并不试图成为"纯OOP"语言; 它明确地被设计成一种"多范式"语言.列表推导不是迭代的方法.`zip`是顶级函数,而不是`zip_with`方法.等等.仅仅因为一切都是一个对象并不意味着成为一个对象是每件事最重要的事情. (7认同)
  • 那篇文章写得太糟糕了,在读完之后我感到困惑和愤怒."在Python 2.x中,例如Tuple类型没有暴露任何非特殊方法,但你可以用它来创建一个字符串:"整个事情是几乎无法解读的句子的融合. (5认同)
  • 说出您的意愿,但是`len(“ __ len__”)不是“ len” .__ len __()`...:/ (2认同)
  • @IonutBotizan不,但是`len("__ len __")=="__ len __".__ len __()`和`len("len")=="len".__ len __()`. (2认同)

Fed*_*oni 87

吉姆对这个问题的回答可能有所帮助; 我把它复制在这里.引用Guido van Rossum:

首先,为了HCI的原因,我选择了len(x)而不是x.len()(def __len __()来得晚了).实际上有两个相互交织的原因,都是人机交互:

(a)对于某些操作,前缀表示法只比读后缀更好 - 前缀(和中缀!)操作在数学中有悠久的传统,它喜欢视觉效果帮助数学家思考问题的符号.比较我们将x*(a + b)等公式重写为x a + x b的简单性,以及使用原始OO表示法做同样事情的笨拙.

(b)当我阅读len(x)代码时,我知道它是在询问某些东西的长度.这告诉我两件事:结果是一个整数,参数是某种容器.相反,当我读取x.len()时,我必须知道x是某种实现接口的容器,或者是从具有标准len()的类继承的.当没有实现映射的类具有get()或keys()方法,或者不是文件的类具有write()方法时,见证我们偶尔会遇到的混淆.

用另一种方式说同样的事情,我认为'len'是一种内置操作.我不想失去那个./ ...... /

  • HCI代表什么? (20认同)
  • 超过 200 票表示缺少 str.len() 浪费了很多人的时间来这里阅读为什么字符串没有长度函数“应该”是直观的:facepalm:无论如何都要保留内置的len() 函数,但为什么不_也_支持对字符串等基本事物的合理方法...... (13认同)
  • 这就是为什么,如果你需要良好的多态性,你使用一种具有良好推理的语言.请参阅:Go,Haskell,CLOS.如果鸭子咬你的屁股,鸭子打字有什么意义呢? (12认同)

unm*_*ted 37

有一种len方法:

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

  • 是的,但它并不意味着可以直接使用。`len` 验证 `__len__` 的输出。请参阅 [是否存在 `len(someObj)` 不调用 `someObj` 的 `__len__` 函数的情况?](/sf/ask/34720661/) Dunder 方法通常并不意味着被直接调用。 (3认同)

Luc*_*lho 31

Python是一种务实的编程语言,并为原因len()是一个功能,而不是一个方法str,list,dict等务实.

len()内置函数直接与优惠内建类型:CPython的执行len()实际返回的值ob_size字段中PyVarObject的C结构代表任意可变大小的内置存储器中的对象.这是很多比调用一个方法快-无属性的查找需要发生.获取集合中的项目数是一种常见的操作,必须对这些基本类型多样为提高工作效率str,list,array.array等.

但是,为了提高一致性,在应用于len(o)用户定义的类型时,Python会将其o.__len__()称为回退. __len__,__abs__以及Python数据模型中记录的所有其他特殊方法可以轻松创建与内置函数类似的对象,从而实现我们称之为"Pythonic"的富有表现力且高度一致的API.

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

第二个原因,由Guido van Rossum引用的支持就像这样,它len(s)比阅读和写作更容易s.len().

符号len(s)与带有前缀表示法的一元运算符一致,如abs(n).len()使用的方式比经常使用abs(),并且它应该像编写一样容易.

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

  • 我不相信最优性论点。虽然方法调用确实可能会更慢,但足够先进的解释器或编译器(Python 解释器可以做比这更高级的事情)可以识别出正在调用内置类型的“len”方法,并恢复为返回“ob_size” ` 或任何它需要的东西,至少在绝大多数时候。 (5认同)

Ale*_*try 12

met% python -c 'import this' | grep 'only one'
There should be one-- and preferably only one --obvious way to do it.
Run Code Online (Sandbox Code Playgroud)

  • 使用对象时显而易见的事情当然是一种方法. (32认同)
  • @Peter:我会向有照片证据的人支付20美元,他们会把你对Guido的评论录下来.50美元,如果在他的额头上. (4认同)
  • 是的,Python 设计者坚持教条,但他们自己并不尊重自己的教条。 (2认同)
  • $ python -c'import this'| grep很明显 (2认同)

kay*_*ya3 5

这里的其余答案中缺少一些内容:该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
Run Code Online (Sandbox Code Playgroud)

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

  • 它还检查 int 是否不大于 `sys.maxsize`,并且首先检查 `obj.__len__` 是否存在。我写了[另一个问题的答案](/sf/answers/4172289761/),列出了所有不同的检查。 (3认同)