TypeError在使用具有slots=True的数据类中使用super()时发生。

huangapple go评论63阅读模式
英文:

TypeError when using super() in a dataclass with slots=True

问题

这段代码中,当你在使用 dataclass 的时候,添加了 slots=True,就会导致 super() 的调用出现错误。为了修复这个问题,你可以在 super() 中使用类名而不是 self,像这样:

data = super(B, self).get_data()

这会正确地调用父类的方法,而不会引发 TypeError。这是因为 slots=True 会创建一个新的类来代替原始的类,所以需要显式指定类名。

英文:

I have a dataclass with (kind of) a getter method.

This code works as expected:

from dataclasses import dataclass

@dataclass()
class A:
    def get_data(self):
        # get some values from object's fields
        # do some calculations
        return "a calculated value"

@dataclass()
class B(A):
    def get_data(self):
        data = super().get_data()
        return data + " (modified)"


b = B()

print(b.get_data())  # a calculated value (modified)

However, if I add slots=True, I get a TypeError:

from dataclasses import dataclass

@dataclass(slots=True)
class A:
    def get_data(self):
        return "a calculated value"

@dataclass(slots=True)
class B(A):
    def get_data(self):
        data = super().get_data()
        return data + " (modified)"


b = B()

print(b.get_data())  # TypeError: super(type, obj): obj must be an instance or subtype of type

The error vanishes if I use the old-style super(), contrary to pep-3135:

from dataclasses import dataclass

@dataclass(slots=True)
class A:
    def get_data(self):
        return "a calculated value"

@dataclass(slots=True)
class B(A):
    def get_data(self):
        data = super(B, self).get_data()
        return data + " (modified)"


b = B()

print(b.get_data())  # a calculated value (modified)

Why does this happen and how to fix it the right way?

答案1

得分: 2

Sure, here's the translated content:

slots:如果设置为True(默认为False),将生成__slots__属性,并返回一个新的类,而不是原始类。如果类中已经定义了__slots__,则会引发TypeError

以此为例:

@dataclass(slots=True)
class Foo:
    pass

这意味着它的工作方式类似于:

class Foo:
    pass

Foo = dataclass(slots=True)(Foo)

你定义了一个名为Foo的类,然后它被替换为一个不同的,被修改过的类。

现在,你的方法:

def get_data(self):
    data = super().get_data()
    ...

这个super()是在原始的Foo类中编写的,它会假设它应该查找这个原始Foo类的父类;但它当前具有的实例实际上不是该类的实例,而是另一个经过修改的类的实例。

当你改用这种方式:

data = super(Foo, self).get_data()

这会查找当前引用名称Foo的内容,这与此时self引用的内容相匹配。

英文:

> slots: If true (the default is False), __slots__ attribute will be generated and new class will be returned instead of the original one. If __slots__ is already defined in the class, then TypeError is raised.
>
> https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass

Taking this as an example:

@dataclass(slots=True)
class Foo:
    pass

This means this works something like this:

class Foo:
    pass

Foo = dataclass(slots=True)(Foo)

You define a class Foo, and then it gets replaced with a different, altered class.

Now, your method:

def get_data(self):
    data = super().get_data()
    ...

This super() was written in the original Foo class and will assume it's supposed to look up the parent of this original Foo class; but the instance it currently has is not actually an instance of that class, it's an instance of the other, altered class.

When you do this instead:

data = super(Foo, self).get_data()

This looks up what currently refers to the name Foo, which again matches what self also refers to at this moment.

huangapple
  • 本文由 发表于 2023年8月4日 21:29:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76836403.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定