python - 在自定义 Python 类中动态重新分配 __len__

标签 python

以前可以设置内部函数,如 __len__()在运行时。下面是一个例子:

#! /usr/bin/python3

import sys

class FakeSequence:
    def __init__(self):
        self.real_sequence = list()
        self.append = self.real_sequence.append
        self.__len__ = self.real_sequence.__len__

    def workaround__len__(self):
        return len(self.real_sequence)

if __name__ == '__main__':
    fake_sequence = FakeSequence()
    fake_sequence.append(1)
    fake_sequence.append(2)
    fake_sequence.append(3)

    length = len(fake_sequence)
    sys.stdout.write("len(fake_sequence) is %d\n" % (length))

以下是您尝试运行时的结果:
$ python2 len_test
len(fake_sequence) is 3

$ python3 len_test
Traceback (most recent call last):
  File "len_test", line 18, in <module>
    length = len(fake_sequence)
TypeError: object of type 'FakeSequence' has no len()

如果我定义 __len__()方法作为类的一部分(删除上面的“解决方法”),它按您的预期工作。如果我定义 __len__()并将其重新分配如上 FakeSequence.__len__()被调用,它不会访问新分配的 __len__() ,它总是调用 FakeSequence 类方法。

您能否指出有助于解释为什么为成员函数分配实例方法不再有效的文档?请注意,分配非双下划线方法仍然可以正常工作。我可以很容易地解决这个问题,但我更担心我错过了从 Python 2 到 Python 3 过渡的一些基本内容。 上述行为与我可以轻松访问的 Python 3 解释器一致 (3.4, 3.6, 3.7) .

最佳答案

魔术方法只在类上查找,而不在实例上查找,如 documented here .在 Py2 中,新式类也是这种情况(参见 https://docs.python.org/2.7/reference/datamodel.html#special-method-lookup-for-new-style-classes)。
我认为主要动机是减少查找以获得更好的性能,但可能还有其他原因,不知道。
编辑:实际上,the motivations are clearly explained in the 2.7 doc :

The rationale behind this behaviour lies with a number of special methods such as hash() and repr() that are implemented by all objects, including type objects. If the implicit lookup of these methods used the conventional lookup process, they would fail when invoked on the type object itself:


然后:

Incorrectly attempting to invoke an unbound method of a class in this way is sometimes referred to as ‘metaclass confusion’, and is avoided by bypassing the instance when looking up special methods:


最后:

In addition to bypassing any instance attributes in the interest of correctness, implicit special method lookup generally also bypasses the getattribute() method even of the object’s metaclass

Bypassing the getattribute() machinery in this fashion provides significant scope for speed optimisations within the interpreter, at the cost of some flexibility in the handling of special methods


所以这确实主要是性能优化 - 当您了解 Python's attribute lookup mechanism 时,这并不奇怪和 how Python's "methods" are implemented .

关于python - 在自定义 Python 类中动态重新分配 __len__,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59381104/

相关文章:

python - 创建模型并进行预测时,keras 是如何工作的?

python - 将本地主机 127.0.0.1 添加到 ALLOWED_HOSTS

python - 带索引的 Django 批量模型删除

python - 返回列表的第一个数字

python - 如何使用map函数将数据框中的所有负数转换为python pandas中所有数字的平均值?

python - 使用超过 2 个参数根据其他数组的值对 numpy 数组进行切片

python - Twisted 服务器,从 Twitter 流 api 消费并同时提供静态内容

python - 如何使得在数据库中保存数据时,函数生成的数据自动插入到Django ORM字段中

python time.time() 在 python 2 和 3 中的区别

python - 将数据帧/系列拆分为每个可能的 block