英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论