为什么在一个元类的call廑方法中使用super()会引发TypeError?

2024-06-25 23:48:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用的是python3,我发现我不能在元类的__call__内使用super()。在

为什么在下面的代码中super()引发TypeError: 'ListMetaclass' object is not iterable异常?为什么我从元类中删除__call__方法会很好地工作?在

class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        new_cls = type.__new__(cls, name, bases, attrs)
        return new_cls

    def __call__(cls, *args, **kw):
        ### why the 'super()' here raises TypeError: 'ListMetaclass' object is not iterable
        return super().__call__(cls, *args, **kw)
        return super(__class__, cls).__call__(cls, *args, **kw)
        return super(__class__, cls.__class__).__call__(cls, *args, **kw)

class MyList(list, metaclass=ListMetaclass):
    a=1
    def bar(self):
        print('test');

L=MyList()
L.add(1)
print('Print MyList :', L)

Tags: selfnewreturnobjectdefargscallattrs
3条回答

我知道这会让你困惑,因为你必须把cls传递给super().__new__,但是你不能把它传给super().__call__。在

这是因为__call__是一个普通的方法,而{}是特殊的。它是behaving like a ^{}

object.__new__(cls[, ...])

Called to create a new instance of class cls. __new__() is a static method (special-cased so you need not declare it as such) [...]

作为staticmethod,它需要所有参数,而不需要将第一个参数传递给普通方法(它已经绑定)。在

所以把它改成:

return super().__call__(*args, **kw)

__call__内。在

使用super().method访问超级类的方法将已经将该方法绑定到当前实例。因此方法的self参数将已经被自动设置,就像调用self.method()时一样。在

因此,当您将当前实例(在本例中是cls类型)传递给方法时,实际上是第二次传递它。在

super().__call__(cls, *args, **kw)

所以这最后会打一个电话__call__(cls, cls, *args, **kw)。在

当您的__call__方法解释这一点时,参数将与以下定义匹配:

^{pr2}$

所以第一个cls是正确匹配的,但是第二个cls被解释为变量参数列表*args。这里是异常的来源:cls在需要iterable的地方被传递,但是cls,类ListMetaclass,不是iterable。在

因此,这里的修复方法只是删除额外的cls:super().method()由于方法绑定已经自动包含了它。在

您不应该将cls传入super().__call__()super()为您处理绑定,因此{}已经被自动传入了。在

您可能被__new__中的super().__new__(cls, ...)调用弄糊涂了,这是因为__new__是这里的例外,请参见^{} documentation

Called to create a new instance of class cls. __new__() is a static method (special-cased so you need not declare it as such) that takes the class of which an instance was requested as its first argument.

super().__call__(...)表达式中删除cls起作用:

class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        new_cls = type.__new__(cls, name, bases, attrs)
        return new_cls;
    def __call__(cls, *args, **kw):
        return super().__call__(*args, **kw)

通过传入cls,实际上是在执行list(cls),告诉list()将{}转换为新列表中的值;这要求{}为iterable。在

当您移除元类上的__call__方法时,当您调用MyClass()时,将使用默认的type.__call__方法,该方法只接收常规参数(示例中没有)并返回一个新实例。在

相关问题 更多 >