2

I'm trying to use the dataclasses default_factory field to dynamically add a property (id) while also still being able to create a subsequent property (id_with_appended_str) whose default value depends on the former property (id) already being created.

The subsequent property (id_with_appended_str) should also support being declared as a parameter (e.g.: MyDataClass(id_with_appended_str="123"). The subsequent property should also be of type str, not Optional[str]. These are some examples that get close to the desired intent:

from dataclasses import dataclass, field
from typing import Final
from uuid import uuid4


@dataclass
class MyDataClass1:
    id: Final[str] = field(init=False, default_factory=lambda: uuid4().hex)
    id_with_appended_str: str = id + "something_appended"
    # or
    # id_with_appended_str: str = field(
    #     default_factory=(lambda id=id: id + "something_appended")
    # )

# A possible alternative
@dataclass
class MyDataClass2:
    id: Final[str] = field(init=False)
    id_with_appended_str: str

    def __post_init__(self):
        # Note this causes a linting error from reassigning a Final prop
        self.id = uuid4.hex
        self.id_with_appended_str = self.id + "something_appended"


def test_1():
    result = MyDataClass1()
    assert "something_appended" in result.id_with_appended_str


def test_2():
    result = MyDataClass1("123")
    assert result.id_with_appended_str == "123"
Jamie.Sgro
  • 821
  • 1
  • 5
  • 17
  • I believe that there's no way to achieve this without some introspection or metaclass hackery. But fwiw, the whole design sounds like a non-starter to me. If you want the described behaviour, you *don't* want a dataclass. – Richard Neumann Apr 04 '22 at 20:01

0 Answers0