模仿 `len` 和 `bool` 的 Python 行为

Mimicking Python behavior for `len` and `bool`

考虑以下代码:

>>> class X:
... pass
...
>>> x = X()
>>> len(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'X' has no len()
>>> bool(x)
True

但是当试图模仿这个写作时 __len__ 它不起作用。

>>> class Y:
...   def __len__(self):
...     raise TypeError
...
>>> y = Y()
>>> len(y)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __len__
TypeError
>>> bool(y)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __len__
TypeError

有没有办法编写一个像未实现一样工作的__len__函数?

bool()测试一个对象的真值,所以你要看rules for Truth Value Testing:

By default, an object is considered true unless its class defines either a __bool__() method that returns False or a __len__() method that returns zero, when called with the object.

您只实现了一个故意破坏的 __len__ 方法,在调用时引发 TypeError。但是bool()在有实现且没有其他选项可用于确定真值时调用它。

判断真值时,__bool__ is preferred over __len__:

When this method is not defined, __len__() is called, if it is defined, and the object is considered true if its result is nonzero.

演示:

>>> class Z:
...     def __bool__(self):
...         return True
...     def __len__(self):
...         raise TypeError
...
>>> len(Z())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __len__
TypeError
>>> bool(Z())
True

请注意,当 __len__ 挂钩没有实现时,引发 TypeError 的是 len() 函数实现。 __len__ 实现毫无例外地可以引发,让你假装它实际上没有实现,如果它被调用,它引发的任何异常都会传播,因为你通常会想知道实现是否是以某种方式损坏。