0

I don't understand the error message and also couldn't find other SO questions and answers helping me to understand this. The MWE is tested with Python 3.9.2. I'm aware that there is a slots=True parameter in Pythons 3.10 dataclasses. But this isn't an option here.

The error output:

Traceback (most recent call last):
  File "/home/user/dc.py", line 6, in <module>
    class Foo:
ValueError: 'b' in __slots__ conflicts with class variable

Why does that happen? I even don't understand the background of that error.

#!/usr/bin/env pyhton3
from dataclasses import dataclass, field


@dataclass(init=False)
class Foo:
    __slots__ = ('a', 'b')
    a: int
    b: list[str] = field(init=False)

    def __init__(self, a, ccc):
        self.a = a

        # b = _some_fancy_modifications(ccc)

        self.b = b


if __name__ == '__main__':
    f = Foo(1, list('bar'))

The member b is not given as an argument of __init__() but computed based on the argument ccc. Because of that I think I need to write my own __init__() (@dataclass(init=False)) and the b member shouldn't be initialized by dataclass (field(init=False)). Maybe I misunderstood something here?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
buhtz
  • 10,774
  • 18
  • 76
  • 149
  • 1
    It happens because `'b' in __slots__ conflicts with class variable`, the class variable being `b: list[str] = field(init=False)`. Which one of those should `Foo.b` be? – jonrsharpe Mar 12 '23 at 10:10
  • Why isn't there a conflict with `a`? – buhtz Mar 12 '23 at 10:34
  • 1
    ...because you don't _have_ a class variable named `a`. You don't assign a value, so it's just in `__annotations__`. – jonrsharpe Mar 12 '23 at 10:35

2 Answers2

1

For __slots__ to work, Python has to insert special descriptor objects into the class dict to manage attribute access. Otherwise, since the attributes aren't stored in the instance dict, attribute lookup would be completely unable to find your attributes. Descriptors tell the attribute lookup machinery how to find special attributes.

For the b slot to work, Python has to insert a descriptor for that attribute corresponding to the 'b' key in your class dict. But you've already put something there: the field object you created. You can't have a field object and a slot descriptor as values for the same key. Python recognizes that this is a problem, and raises an error to tell you that you need to do something about this.

This isn't really something you can fix on your end. __slots__ support for dataclasses needs changes to the dataclass machinery, changes that happened in 3.10. In 3.9, you're stuck not using slots with dataclasses.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • I wonder: Does it even make sense to use `init=False` on classlevel **and** attribute level? – buhtz Mar 12 '23 at 09:43
  • 1
    @buhtz: Maybe in some weird cases with dataclass inheritance, but any cases I can think of involve horribly confusing code that shouldn't be written that way in the first place. – user2357112 Mar 12 '23 at 10:15
-1

This is not related to dataclasses. A slot is realized as a class variable of an internal type "member_descriptor".

Try:

class Foo:
    __slots__ = ('a', 'b')

print(repr(Foo.a))
print(repr(Foo.a.__class__))

Output:

<member 'a' of 'Foo' objects>
<class 'member_descriptor'>
Michael Butscher
  • 10,028
  • 4
  • 24
  • 25