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

时间:2015-11-04 09:16:27

标签: python python-internals

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

就像我需要让别人打开冰箱为我喝啤酒。啤酒放在冰箱里,我有双手,我应该能够自己做。

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

换句话说,我更希望使用foo.len代替foo.len()foo.__len__len(foo)对我来说更奇怪。

这个实现有解释吗?

answer部分回答了我的问题,但我的沮丧仍然存在。

1 个答案:

答案 0 :(得分:4)

您可以找到深刻的理由here和Guido的想法here

总结一下,这是因为它们可能与您想象的不那么密切相关。只是谈论您帖子的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()

现在对布尔上下文中t1t2¹和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
    

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

¹请注意,__bool__在python2中为__nonzero__