ericvsmith / dataclasses

Apache License 2.0
584 stars 53 forks source link

dataclass with `frozen=True` with `init=False` can't be instantiated #150

Closed DBCerigo closed 4 years ago

DBCerigo commented 4 years ago

Creating a dataclass that has frozen=True and a field with init=False makes a class that throws a dataclasses.FrozenInstanceError: cannot assign to field 'a_field' error when attempting to instantiate it.

Is this expected, and just a limitation that the user must be aware of? I couldn't find mention of it in the docs, though there are lots of mentions of other things to be aware of with init=False.

Example:

@dataclass(frozen=True)
class AClass:
    a_field: str = field(default="a_default", init=False)

Apologies for opening an issue on a historic-purposes repo, but it still seemed like the most appropriate place I could find for it.

ericvsmith commented 4 years ago

With 3.7.4, I see this:

>>> @dataclass(frozen=True)
... class AClass:
...     a_field: str = field(default="a_default", init=False)
...
>>> AClass()
AClass(a_field='a_default')
>>> AClass('')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() takes 1 positional argument but 2 were given

That looks correct to me.

Please show an example of the problem you're seeing.

DBCerigo commented 4 years ago

I thought the issue was that I hadn't made a correct example that followed my issue, but actually it turns out that even this below example works on its own. The issue actually comes from trying to instantiate the classes, as a nested member of another dataclass, from a dict using the external package dacite.from_dict(), and is not the problem of dataclasses - my apologies! stdlib support for instantiating nested dataclass would be fantastic (imo). Thanks for all the work and the response.

from dataclasses import dataclass, field
@dataclass(frozen=True)
class AClass:
    another_field: int
    a_field: str = field(default="a_default", init=False)