te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>inheritance - Python @dataclasses(slots=True) breaks super() - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

inheritance - Python @dataclasses(slots=True) breaks super() - Stack Overflow

programmeradmin1浏览0评论

Consider the following code. I have a base and derived class, both dataclasses, and I want to call a method of the base class in the derived class via super():

import abc
import dataclasses
import typing


SLOTS = False


@dataclasses.dataclass(slots=SLOTS)
class Base:
    @abc.abstractmethod
    def f(self, x: int) -> int:
        return x


@dataclasses.dataclass(slots=SLOTS)
class Derived(Base):
    @typing.override
    def f(self, x: int) -> int:
        return super().f(x)


d = Derived()
d.f(2)

When setting SLOTS = False, this runs fine. When setting SLOTS = True, I get an error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[2], line 24
     20         return super().f(x)
     23 d = Derived()
---> 24 d.f(2)

Cell In[2], line 20, in Derived.f(self, x)
     18 @typing.override
     19 def f(self, x: int) -> int:
---> 20     return super().f(x)

TypeError: super(type, obj): obj (instance of Derived) is not an instance or subtype of type (Derived).

Why is that?

Note that it works if I use a regular slotted class instead of a dataclass:

import abc
import typing


class Base:
    __slots__ = tuple()

    @abc.abstractmethod
    def f(self, x: int) -> int:
        return x


class Derived(Base):
    __slots__ = tuple()

    @typing.override
    def f(self, x: int) -> int:
        return super().f(x)


d = Derived()
d.f(2)

Consider the following code. I have a base and derived class, both dataclasses, and I want to call a method of the base class in the derived class via super():

import abc
import dataclasses
import typing


SLOTS = False


@dataclasses.dataclass(slots=SLOTS)
class Base:
    @abc.abstractmethod
    def f(self, x: int) -> int:
        return x


@dataclasses.dataclass(slots=SLOTS)
class Derived(Base):
    @typing.override
    def f(self, x: int) -> int:
        return super().f(x)


d = Derived()
d.f(2)

When setting SLOTS = False, this runs fine. When setting SLOTS = True, I get an error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[2], line 24
     20         return super().f(x)
     23 d = Derived()
---> 24 d.f(2)

Cell In[2], line 20, in Derived.f(self, x)
     18 @typing.override
     19 def f(self, x: int) -> int:
---> 20     return super().f(x)

TypeError: super(type, obj): obj (instance of Derived) is not an instance or subtype of type (Derived).

Why is that?

Note that it works if I use a regular slotted class instead of a dataclass:

import abc
import typing


class Base:
    __slots__ = tuple()

    @abc.abstractmethod
    def f(self, x: int) -> int:
        return x


class Derived(Base):
    __slots__ = tuple()

    @typing.override
    def f(self, x: int) -> int:
        return super().f(x)


d = Derived()
d.f(2)
Share Improve this question asked Feb 17 at 18:09 rdong8rdong8 334 bronze badges 2
  • 3 yes - slots=True will make dataclasses create a new class, instead of modifying the decorated class inplace, and this will break super(). – jsbueno Commented Feb 17 at 18:19
  • 2 At a guess it's because the magic that enables super() to be called without args, and how dataclasses add slots when used with a decorator. Using the old school super(Derived, self).f(x) fixes the issue. – Dunes Commented Feb 17 at 18:19
Add a comment  | 

1 Answer 1

Reset to default 2

WHen one uses the slots=True option on dataclasses, it will create a new class using the namespace of the decorated class - while not passing it makes it modify the class "in place". (This is needed because using slots really change how the class is built - its "layout" as it is called)

The simplest thing to do is not to use __slots__ altogether - the gains slots gives one in modern Python are small since some of the optimizations that went on Python 3.11 (check it here: Are Python 3.11 objects as light as slots? )

Anyway, the workaround is quite simple - instead of the parameterless version of super(), which uses a mechanism introduced in Python 3.0, just use the explicit version of it, where you pass the class and instance as arguments.

The thing is that the parameterless version uses implicitly the class body where the super() call is actually written in: at compile time, the current class is frozen into the method, in a non-local like variable named __class__. The new class created by dataclass with slots can't (or simply does not do) update this value - so parameterless super will try to call super on the original (pre dataclass decorator ) Derived class and will fail.

This version of the code will work:


@dataclasses.dataclass(slots=SLOTS)
class Derived(Base):
    @typing.override
    def f(self, x: int) -> int:
        return super(Derived, self).f(x)

发布评论

评论列表(0)

  1. 暂无评论