{"assignment":{"_schema_version":2,"course_id":37,"date_created":"2022-06-28T19:00:00+00:00","date_modified":"2023-09-10T14:17:33.215250+00:00","extra_instructor_files":"","extra_starting_files":"","forked_id":null,"forked_version":null,"hidden":false,"id":1114,"instructions":"## Nesting Dataclasses\n\n```python nesting-example\nfrom dataclasses import dataclass\n\n@dataclass\nclass Address:\n    city: str\n    state: str\n\n@dataclass\nclass Person:\n    name: str\n    work: Address\n    home: Address\n\nada = Person(\"Ada\", Address(\"Newark\", \"DE\"),\n             Address(\"Elkton\", \"MD\"))\nprint(ada)\n```\n\nJust like how dataclasses can be nested inside lists, dataclasses can be nested inside other dataclasses.\nThis introduces extra complexity but can help organize large complex objects and increase reusability.\nIn the following example, the `Person` class depends on an `Address` class for two of its fields.\nThis allows us to cleanly separate the parts of an address from the parts of a erson, both in our minds and in our code.\nWhen you print out the entire object, you can see that `ada` has two different addresses inside.\n\n## Order of Definitions\n\n```python order-matters\nfrom dataclasses import dataclass\n\n@dataclass\nclass Person:\n    name: str\n    work: Address\n    home: Address\n\n@dataclass\nclass Address:\n    city: str\n    state: str\n\nada = Person(\"Ada\", Address(\"Newark\", \"DE\"),\n             Address(\"Elkton\", \"MD\"))\nprint(ada)\n```\n\nThe order in which you define dataclasses matters.\nIf you try running the following code , you will get an error on the second line of the definition of the `Person` class.\nThat definition is expecting the `Address` class to already exist, so a `NameError` occurs instead.\nThe dataclasses must be defined before they can be referenced, at least in Python.\n\n## Nested Access\n\n```python nested-access\nfrom dataclasses import dataclass\n\n@dataclass\nclass Address:\n    city: str\n    state: str\n\n@dataclass\nclass Person:\n    name: str\n    work: Address\n\nada = Person(\"Ada\", Address(\"Newark\", \"DE\"))\nprint(ada.work.state)\n```\n\nWhen you have multiple levels of nested data classes, you still use attribute access to get data inside of the classes.\nHowever, you will have to chain the accesses together to get to the desired level.\nThe leftmost part is the name of the variable, and then the name of each attribute is written after a period.\nBe sure not to use the attribute's type!\n\n## Visualization\n\n![A visualization of the `ada.work.state` expression, where a box labeled `Person` has an arrow labeled `work` pointing to a box labeled `Address`, with an arrow pointing in turn to a string value `\"DE\"`, suggesting that the data is stored inside of other data.](bakery_nesting_2d_dataclasses_unpacking_visualization.png)\n\nImagine opening a box and finding another box inside, and then opening that box to find the value you are looking for.\nEach level of nested dataclass means another box.\n\n## Temporary Variables to Unpack Nested Data\n\n```python temporary-variables\nfrom dataclasses import dataclass\n\n@dataclass\nclass Address:\n    city: str\n    state: str\n\n@dataclass\nclass Person:\n    name: str\n    work: Address\n\nada = Person(\"Ada\", Address(\"Newark\", \"DE\"))\njob = ada.work  # Introduced a temporary!\nada_state = job.state\nprint(ada_state)\n```\n\nA temporary variable can help alleviate some of the ugliness of heavily nested classes.\nAssigning one part of the chained attribute access to a new variable allows you to name that expression and reuse it later.\nThis is especially helpful if you are going to need to use the value stored inside multiple times.\n\n## Stack/Heap Diagram of Instances\n\n![A Stack/Heap diagram that shows three variables on the stack pointing to two instances on the heap.](bakery_nesting_2d_dataclasses_stack_heap.png)\n\nA stack/heap diagram can help explain the relationship between the variables and the instances.\nThe `ada` variable points to the `Person` instance, which in turn has a `work` field that points to the `Address` instance.\nThe `job` temporary variable also points to the same `Address` instance.\nThe `ada_state` temporary variable got its value from the `job.state` attribute access, but the rules for primitive types like strings and integers are a little different in terms of references.\n\n## Mutating Nested Data\n\n```python mutate-nested-data\nfrom dataclasses import dataclass\n@dataclass\nclass Address:\n    city: str\n    state: str\n@dataclass\nclass Person:\n    name: str\n    work: Address\n\n# Original values\nada = Person(\"Ada\", Address(\"Newark\", \"DE\"))\njob = ada.work\nada_city = job.city\nprint(\"Nested access: \", ada.work.city)\nprint(\"Direct access: \", job.city)\nprint(\"Local variable: \", ada_city)\n# Attribute access updates attributes\nada.work.city = \"Wilmington\"\nprint(\"Nested access: \", ada.work.city)\nprint(\"Direct access: \", job.city)\nprint(\"Local variable: \", ada_city)\n# Variable access does not\njob = Address(\"Baltimore\", \"MD\")\nprint(\"Nested access: \", ada.work.city)\nprint(\"Direct access: \", job.city)\nprint(\"Local variable: \", ada_city)\n```\n\nAny changes made to the fields of `job` (such as changing the value of `job.city`) would also update `ada`'s `work` instance, since they point to the same object on the heap.\nThe same is true for `ada.work.city` if the `job.city` attribute is updated.\nHowever, the `ada_city` temporary variable does not share a connection with the `job.city` or `ada.work.city` references.\n\nAttribute access can modify the value of fields on the heap, but variable updates do not modify those fields.\nWhen we update the `job` variable to point to a new value that had no impact on the `ada.work` field at all.\nInstead, the `job` variable points to a new value on the heap.\nThe `ada_city` variable is also unaffected because that variable holds a primitive value on the stack.\n\n## Visualizing Mutation\n\n![A stack heap diagram showing the results of mutating data in the stack heap.](bakery_nesting_2d_dataclasses_mutating_stack_heap.png)\n\nThe following Stack/Heap diagram clarifies the new relationships.\nThe `ada` variable points to the `Ada` instance, still.\nBut the `job` variable poitns to a completely different `Address` instance.\nEven if that new instance had the same values as the original `Address`,\nthe two instances would still be separated.\nNotice how the `ada_city` variable has a different value from either instance's `city` field.\n\n## Lists in Dataclasses\n\n```python lists-in-dataclasses\nfrom dataclasses import dataclass\n\n@dataclass\nclass Emails:\n    user: str\n    messages: list[str]\n\ninbox = Emails(\"adabart\", [\"HELP!\", \"Department News\",\n                           \"Hello World\"])\n\n\nprint(inbox.messages[1])\n```\n\nAs you might have guessed by now, lists can also be nested inside of dataclasses.\nLists are just another type, after all, so using them inside of a dataclass is not a big deal.\nThe only part that might feel strange is _how_ you access individual elements of the list.\nNotice how we must combine the attribute access syntax with the list indexing syntax.\nAll the same rules and operations apply that we have learned so far, they might just look a little funny at first.\n\n## How Much Nesting?\n\n```python unnecessary-nesting\nfrom dataclasses import dataclass\n\n# Not good nesting - adds nothing of value!\n@dataclass\nclass Person:\n    name: Name\n\n@dataclass\nclass Name:\n    full_name: str\n\nada_bart = Person(Name(\"Ada\"))\nprint(ada_bart)\n```\n\nWhen you are designing your dataclasses, you should reflect on how much nesting you want.\nBreaking up complex dataclasses into smaller pieces can help make your code reusable and reduce your cognitive load.\nHowever, you also must do more levels of attribute access, and it can be difficult to remember where things are.\nYou need to learn to work with the brain that you have and find an appropriate level of depth for the classes.\n\nIn this example, we see a `Person` class that has a `name` field with a corresponding `Name` class, rather than being directly a `str`.\nThis makes no sense since the `Name` class only ends up with one field.\nBut, it might make sense if we were going to add some other fields like `first_name`,`last_name`, and `nickname` to the `Name` field.\nThen we could reuse that structure across other classes that need complex names.\n\n## Summary\n\n- Instances of dataclasses can be nested inside of other dataclasses.\n- To access values in nested dataclasses, attribute access can be chained together.\n- If one dataclass has fields of another type of dataclass, then the dataclasses must be defined in order.\n- To reduce the amount of attribute chaining, you can use temporary variables to store references to the nested data.\n- Updating variables will not affect the original values of the attributes; only attribute access will update the value stored in fields of a dataclass. Instead, the variables will simply point to new references.\n- Lists can also be stored in the fields of dataclasses.\n- Dataclasses should only be nested inside of other dataclasses when the extra organization makes the code easier to read and think about, since there is a small extra layer of complexity when accessing nested data.\n- However, breaking up complex data into multiple dataclasses can make it much easier to reason about an individual piece of data, so is often worth doing.\n\n","ip_ranges":"","name":"8A2) Nested Dataclasses Reading","on_change":"","on_eval":"","on_run":"","owner_id":1,"owner_id__email":"acbart@udel.edu","points":0,"public":true,"reviewed":false,"sample_submissions":[],"settings":"{\n  \"header\": \"Nesting Dataclasses\",\n  \"youtube\": {\n    \"Bart\": \"OhuCWSfoBJY\",\n    \"Amy\": \"_fB8KSLY0PQ\"\n  },\n  \"video\": {\n    \"Bart\": \"https://blockpy.cis.udel.edu/videos/bakery_nesting_2d_dataclasses-Bart.mp4\",\n    \"Amy\": \"https://blockpy.cis.udel.edu/videos/bakery_nesting_2d_dataclasses-Amy.mp4\"\n  },\n  \"summary\": \"\",\n  \"small_layout\": true\n}","starting_code":"","subordinate":true,"tags":[],"type":"reading","url":"bakery_nesting_2d_dataclasses_read","version":11},"ip":"216.73.216.157","submission":{"_schema_version":3,"assignment_id":1114,"assignment_version":11,"attempts":0,"code":"","correct":false,"course_id":37,"date_created":"2026-05-20T23:50:39.045910+00:00","date_due":"","date_graded":"","date_locked":"","date_modified":"2026-05-20T23:50:39.045910+00:00","date_started":"","date_submitted":"","endpoint":"","extra_files":"","feedback":"","grading_status":"NotReady","id":2037101,"score":0.0,"submission_status":"Started","time_limit":"","url":"submission_url-ab9c43a3-ecb9-4f7c-a25d-b142f611a743","user_id":2044772,"user_id__email":"","version":0},"success":true}
