len()和.__ len __()之间的区别?

Mar*_*ark 84 python

打电话len([1,2,3])[1,2,3].__len__()?之间有什么区别吗?

如果没有明显的差异,在幕后做了哪些不同的事情?

Mik*_*ham 91

len是一个获取集合长度的函数.它通过调用对象的__len__方法来工作.__something__属性是特殊的,通常不仅仅是满足眼睛,通常不应该直接调用.

在很久以前就确定了某些东西的长度应该是一个函数,而不是一个方法代码,推断len(a)初学者的意思是明确的,但a.len()不会那么清楚.当Python启动__len__时甚至不存在,并且len是一种特殊的东西,它适用于几种类型的对象.无论这种情况离开我们是否完全合理,它都会留下来.

  • fwiw,一个看似合理的原因是python _really really_不喜欢保留方法名称 - 一个`Rectangle`类可能想要`length`和`width`,如果`.length()`被有效保留,你要么笨拙地更改名称,要么打破鸭子打字. (6认同)
  • @EvgeniSergeev事实上,像这样的对象有这样的属性 - 一个numpy数组有一个`shape`属性(根本不是一个方法,因为它是对象的属性而不是对象的一个​​动作). (5认同)
  • 这是留下来的,但另外还有一个`some_collection.length()`方法也没什么坏处.实际上,`.size()`会更好,因为基于树的数据结构有一个大小,但不容易想象有一个长度. (4认同)
  • 我认为,无论数据结构如何,在整个语言中拥有一个通用标准来获取对象的长度是非常棒的。很高兴不必记住它是 obj.length、obj.length()、obj.size、obj.size() 还是多年来梦想的其他东西 (2认同)

Ale*_*lli 63

通常情况下,内置或运算符的"典型"行为是__whatever__在所涉及的对象上调用(具有不同且更好的语法)合适的魔术方法(名称相似的方法).通常内置或运算符具有"附加值"(它可以根据所涉及的对象采用不同的路径) - 在lenvs 的情况下__len__,它只是对内置的一些完整性检查魔法:

>>> class bah(object):
...   def __len__(self): return "an inch"
... 
>>> bah().__len__()
'an inch'
>>> len(bah())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object cannot be interpreted as an integer
Run Code Online (Sandbox Code Playgroud)

当你看到对len内置函数的调用时,你确定,如果程序在此之后继续而不是引发异常,则调用返回一个整数,非负数,小于2**31 - 当你看到一个电话xxx.__len__(),你没有把握(除了代码的作者要么不熟悉Python,要么根本没有好;-).

除了简单的健全性检查和可读性之外,其他内置函数还提供了更多附加值.通过调用内置函数和使用运算符来统一设计所有Python,从不通过调用魔术方法,程序员可以免于记住哪种情况的负担.(有时会出现错误:直到2.5,你必须调用foo.next()- 在2.6中,虽然这仍然适用于向后兼容性,你应该调用next(foo),然后3.*,魔术方法被正确命名__next__而不是"oops-ey" next! - ).

因此,一般规则应该是永远不要直接调用魔术方法(但总是通过内置方式间接调用),除非你确切知道为什么需要这样做(例如,当你在子类中重写这样的方法时,如果子类需要遵循必须通过对magic方法的显式调用来完成的超类.

  • @DarekNędza这与上面的内容无关,这与内置len有关.你刚刚定义了你的len函数,当然可以返回你想要的任何东西.OP谈到内置len,它在所考虑的对象上调用`__len__`特殊_method_(不是函数). (3认同)
  • 亚历克斯明确地说_if_你在呼唤内置,_then_你确定...... 他没有说确定你打电话给内置.但是如果你想知道这一点,你可以:`len in vars(__ builtins __).values()`. (3认同)

Joh*_*ooy 24

你可以认为len()大致相当于

def len(x):
    return x.__len__()
Run Code Online (Sandbox Code Playgroud)

一个优点是它允许你写出类似的东西

somelist = [[1], [2, 3], [4, 5, 6]]
map(len, somelist) 
Run Code Online (Sandbox Code Playgroud)

代替

map(list.__len__, somelist)
Run Code Online (Sandbox Code Playgroud)

要么

map(operator.methodcaller('__len__'), somelist)
Run Code Online (Sandbox Code Playgroud)

但是行为略有不同.例如,在整数的情况下

>>> (1).__len__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute '__len__'
>>> len(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()
Run Code Online (Sandbox Code Playgroud)

  • 我假设你的意思是`operator.methodcaller`而不是`operator.attrgetter`. (2认同)

小智 5

您可以查看Pythond 文档

>>> class Meta(type):
...    def __getattribute__(*args):
...       print "Metaclass getattribute invoked"
...       return type.__getattribute__(*args)
...
>>> class C(object):
...     __metaclass__ = Meta
...     def __len__(self):
...         return 10
...     def __getattribute__(*args):
...         print "Class getattribute invoked"
...         return object.__getattribute__(*args)
...
>>> c = C()
>>> c.__len__()                 # Explicit lookup via instance
Class getattribute invoked
10
>>> type(c).__len__(c)          # Explicit lookup via type
Metaclass getattribute invoked
10
>>> len(c)                      # Implicit lookup
10
Run Code Online (Sandbox Code Playgroud)