在自定义Python类中动态地重新分配

2024-04-24 08:07:17 发布

您现在位置: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类方法。你知道吗

你能给我指出一些文档来帮助解释为什么为成员函数分配实例方法不再有效吗?请注意,指定非双下划线方法仍然可以正常工作。我可以很容易地解决这个问题,我更担心的是,在从python2到python3的转换过程中,我遗漏了一些基本的东西。上面的行为与我可以轻松访问的python3解释器(3.4、3.6、3.7)是一致的。你知道吗


Tags: 方法函数testselflenisdefsys
3条回答

魔术方法只在类上查找,而不是在实例上,如documented here。Py2中的新样式类(cfhttps://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 mechanismhow Python's "methods" are implemented时,这并不奇怪。你知道吗

在Python 3中测试:

您可以创建自己的函数,比如mylen,并将其传递给类的构造函数。下面的示例使用始终返回5的函数mylen

import sys

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

    def __len__(self):
        return self.length_function()

if __name__ == '__main__':

    def mylen():
        return 5

    fake_sequence = FakeSequence(mylen)
    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))

文档here中描述了这种行为。这与Python2和Python3中的新样式和旧样式类有关。换句话说,如果您继承了object,那么在python2中就不应该这样做。您发布的代码使用python2中的旧样式类和python3中的新样式类。你知道吗

docs声明,为了通过绕过查找来提高优化速度,“必须在类对象本身上设置特殊方法,以便解释器一致地调用它。”

相关问题 更多 >