Python中foo.__x__和x(foo)的原因(即len和__len__)

now*_*wox 3 python python-internals

直观地说,一个List类应该实现一个属性或一个方法来检索实例的长度。幸运的是,Python 的列表有一个名为__len__. 不幸的是,这种方法并不意味着直接使用。我应该使用一个外部函数来为我读取隐藏的方法。

这就像我需要请别人打开冰箱给我拿啤酒。啤酒在冰箱里,我有双手,我应该可以自己做。

从概念上讲,这种方法似乎很奇怪。为什么没有用于获取列表长度的属性(而不是方法)。

换句话说,我更喜欢使用foo.len而不是foo.len()or foo.__len__len(foo)对我来说似乎更奇怪。

这个实现有解释吗?

这个答案部分回答了我的问题,但我的挫败感仍然存在。

409*_*ict 5

你可以找到一个深理由在这里和Guido的思想在这里

总而言之,这是因为它们可能不像您想象的那样密切相关。只是谈论您的帖子的len对比__len__,但您可以在第一个链接中找到其他示例。

让我们首先关注__len__

class Test1:
    pass

class Test2:
    def __bool__(self):
        return False

class Test3:
    def __len__(self):
        return 0

t1 = Test1()
t2 = Test2()
t3 = Test3()
Run Code Online (Sandbox Code Playgroud)

现在,在布尔上下文中对t1, t2¹的评估是什么t3

  • bool(t1)True。标准的 python 行为,任何未明确的都False被考虑True
  • bool(t2)False。显式设置对象以False相应地行为。
  • bool(t3)False。由于t3工具__len__被认为是一个容器,并且由于它的长度是,0所以它是一个空的。根据定义,False在布尔上下文中考虑空容器。

__len__不一定只能由 调用len

len,另一方面,为您提供保证:

  • 它将返回一个正整数;
  • 它适用于任何容器,而不仅仅是列表;
  • 它将计算该容器中的元素数量。不管它意味着什么都取决于容器:比较

    s = "A string with "
    d = s.encode("utf-8")
    print(len(s)) # outputs 15
    print(len(d)) # outputs 18
    
    Run Code Online (Sandbox Code Playgroud)

    因为s是字符d容器,是字节容器。


¹请注意,这__bool____nonzero__在python2中。