3

This code works as expected:

from dataclasses import dataclass

@dataclass(slots=False, init=False)
class Test:
    field: str = "default value"


print(Test())  # outputs "Test(field='default value')"

However, if I change slots to True, it throws an AttributeError:

AttributeError: 'Test' object has no attribute 'field'

To fix the issue, I have to either use the generated __init__ method or initialize all the fields within a custom __init__ method explicitly. What is the reasoning behind this behavior?

enkryptor
  • 1,574
  • 1
  • 17
  • 27

1 Answers1

5

You're not initializing the object with its default values anyway - your __init__ isn't initializing the object at all. However, without __slots__, it kind of looks like the default value is there, because instance attribute lookup falls back to the class, and finds that field on the class is set to "default value".

With slots=True, field on the class isn't set to "default value" any more. It's set to a slot descriptor, responsible for retrieving slot values from the right part of the instance's memory layout. Instance attribute lookup finds the slot descriptor, which checks the slot in the instance's memory layout, and finds the slot is empty, so it raises an AttributeError.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • And how exactly removing the `__init__` method "fixes" the problem? – enkryptor Jul 20 '23 at 20:12
  • 1
    @enkryptor well for starters, because there *shouldn't be one to begin with*. Because *practically* the whole point of `dataclasses.dataclass` to to generate that `__init__`. When you remove it, then the one that `dataclasses.dataclass` generates one for you. And things work. – juanpa.arrivillaga Jul 20 '23 at 20:41
  • 1
    @enkryptor I would go as far as to say that *if you are going to write your own `__init__` then just don't use `dataclasses.dataclass`*. You should try to use `__post_init__`, then if that doesn't work, then your use-case is probably outside the scope of what a "dataclass" is supposed to be (which is basically a simple record-type with record-like semantics) – juanpa.arrivillaga Jul 20 '23 at 20:43
  • 1
    @juanpa.arrivillaga you're right, it's in the first paragraph of the [docs](https://docs.python.org/3/library/dataclasses.html) — "this code will add, among other things, a `__init__()`" – enkryptor Jul 20 '23 at 20:45