{"assignment":{"_schema_version":2,"course_id":37,"date_created":"2022-06-28T19:00:00+00:00","date_modified":"2023-09-10T14:18:47.588916+00:00","extra_instructor_files":"","extra_starting_files":"","forked_id":null,"forked_version":null,"hidden":false,"id":1119,"instructions":"## The Types\n\n* **Primitive Types**: Integer, float, Boolean, string, None\n* **Composite Types**: List, dataclasses\n\nThe five primitive types we've learned about are integer, float, Boolean, string, and `None`.\nThe two composite types we've seen so far are lists and dataclasses.\nThese two new composite types are special because they are composed of other types.\nIt's worth reminding you that dataclasses are not actually a type themselves but _a way of making new types_.\nThere are many more composite types in Python.\nBut, for now, we'll stick to these basic seven types.\nIn the earlier parts of this chapter, we saw how we could mix and match those composite types to make lists of dataclasses, dataclasses inside of dataclasses, and lists of lists.\nThere's no limit to how much we can combine these different types.\n\n## Example Nested Data\n\n```python heavy-nesting-example\nfrom dataclasses import dataclass\n\n@dataclass\nclass Person:\n    name: str\n    pets: int\n\n@dataclass\nclass House:\n    address: str\n    owner: Person\n\n@dataclass\nclass Neighborhood:\n    name: str\n    houses: list[House]\n\ngreen_acres = Neighborhood(\"Green Acres\", [\n  House(\"14 Sun Drive\", Person(\"Mary\", 1)),\n  House(\"15 Sun Drive\", Person(\"Jenny\", 0)),\n  House(\"16 Sun Drive\", Person(\"Jim\", 5)),\n])\n```\n\nLet's study a concrete example of some heavily nested data.\nHere we have three dataclasses where two of the dataclasses have fields referencing other dataclasses.\nIn fact, for the first level, the `Neighborhood` dataclasses `houses` field is a list of the `House` dataclass.\nAt the deepest point, there are four levels of nested data structure here.\n\n## A Representative Diagram\n\n![A diagram shows three boxes connected with two lines. Each box describes the name and fields of the classes described on the previous slide: Neighborhood, House, and Person](bakery_nesting_heavy_class_diagram.png)\n\nTo quickly understand the structure of complex nested data, we can model the data in a _class diagram_.\nIn the diagram, we draw each dataclass in its own box.\nThen, we connect the related dataclasses together with lines.\nIf the relationship includes a list, we draw an empty diamond starting from the owning dataclass.\nThere is a lot more to class diagrams than what we have shown here, but this should be enough to get us started.\n## Accessing Nested Data\n\n- (**Lists**) Iteration with `for` loops\n- (**Lists**) Indexing and subscripting\n- (**Dataclasses**) Attribute access\n\nAs you process this complex nested data's structure, you must stay aware of where you are.\nThis is like needing to navigate a maze.\nHowever, you also must be aware of the tools at your disposal for accessing the data.\nWhen working with a list layer, you can either iterate through the data with a `for` loop, or index specific elements if you only need one.\n\nWhen working with a dataclass layer, you can only access attributes of the instance at that layer.\nIn the `green_acres` example from before, if we wanted to add up the number of pets across everyone in the neighborhood, we would need to do an attribute access, followed by iteration, followed by a pair of attribute accesses.\n\nTo summarize, the three kinds of operations we use for accessing heavily nested data are iteration with `for` loops, indexing and subscripting, and attribute access.\nDo not confuse the operations for these types; you should not try to iterate through a dataclass with a `for` loop and you should not access list elements with attribute access.\n\n## Iterating in Code\n\n```python count-pets\nfrom dataclasses import dataclass\nfrom bakery import assert_equal\n@dataclass\nclass Person:\n    name: str\n    pets: int\n@dataclass\nclass House:\n    address: str\n    owner: Person\n@dataclass\nclass Neighborhood:\n    name: str\n    houses: list[House]\n\ndef count_pets(neighborhood: Neighborhood) -> int:\n    pets = 0\n    houses = neighborhood.houses\n    for house in houses:\n        pets += house.owner.pets\n    return pets\n\nassert_equal(count_pets(Neighborhood(\"Green Acres\", [\n  House(\"4\", Person(\"M\", 1)), House(\"5\", Person(\"J\", 0)), House(\"6\", Person(\"J\", 5)),\n])), 6)\n```\n\nHere is an example function that counts the number of pets across all the neighborhoods.\nNotice that we have extracted the `neighborhood.houses` expression to a temporary variable first; we could have used the expression directly in the loop if we had wanted to (`for house in neighborhood.houses`).\nWe could also have broken up the `house.owner.pets` expression with some temporary variables (`owner = house.owner` followed by `owner.pets`).\nAnd we could have made a helper function to help count the number of pets in an individual neighborhood.\nWhether that is effective is partially a matter of opinion but also a matter of how complex the code is.\nThis function is not super complicated, so we did not bother breaking it up.\nBut what if we had a more complicated structure?\n\n## Layers of Nesting\n\n![A diagram has two large blocks of code on either side. On the left side, there are the definitions of four dataclasses. On the right side, a list of instances are created as an example of the dataclasses. In the middle, there is a class diagram describing the complicated model.](bakery_nesting_heavy_complex.png)\n\nAs previously mentioned, there are no limits to the levels of nesting you are allowed.\nHere we see a `Planner` dataclass that has a list of `Day` dataclasses inside.\nThat `Day` class has not only a `Date` dataclass in one of its fields, but it also has a list of `Event` dataclass instances.\nOn the right-hand side, we have a list of Planner instances as an example of a large data structure.\n\n## Another Example Function\n\n```python planner-example\nfrom dataclasses import dataclass\nfrom bakery import assert_equal\n@dataclass\nclass Event:\n    name: str\n    duration: int\n@dataclass\nclass Date:\n    day: int\n    month: int\n    year: int\n@dataclass\nclass Day:\n    date: Date\n    events: list[Event]\n@dataclass\nclass Planner:\n    owner: str\n    days: list[Day]\n\ndef total_average(planners: list[Planner]) -> float:\n    total = 0\n    for planner in planners:\n        total += average_duration(planner)\n    return total\ndef average_duration(planner: Planner) -> float:\n    count, total = 0, 0\n    for day in planner.days:\n        for event in day.events:\n            count += 1\n            total += event.duration\n    return total / count\n\nassert_equal(total_average([Planner(\"Ada Bart\", [Day(Date(4, 9, 23), [Event(\"Fetch\", 45), Event(\"Nap\", 124)]),\n    Day(Date(4, 10, 23), [Event(\"Fetch\", 27), Event(\"Nap\", 60), Event(\"Bork\", 64)])]),\n  Planner(\"Babbage Bart\", [Day(Date(4, 9, 23), [Event(\"Nap\", 180)]), Day(Date(4, 10, 23), [Event(\"Nap\", 180)])])\n]), 244.0)\n```\n\nIn this example, we define two functions, `total_average` and `average_duration`, with the goal of calculating the total average duration across multiple planners.\nSince, this time, we had so many nested pieces of data, we found it quite helpful to break things up with helper functions.\nA good rule of thumb is that you should avoid having `for` loops directly inside of each other unless you are working explicitly with a 2-dimensional list like we discussed in the previous chapter.\nTechnically, the `average_duration` function does not operate on a 2-dimensional list (there is a dataclass in between the two list layers), but the effect is almost the same in the end.\nFurther, we needed the extra `count` and `total` variables for the `average_duration` loops.\nKeeping those variables in a helper function avoids collisions with the main `total_average` function.\n\nThe key to writing complex accesses is keeping track of the types.\nWhen we start dealing with truly nested data like this, we start relying more heavily on functional decomposition to help us manage the complexity.\n\n## Summary\n\n- Integers, floats, Booleans, strings, and `None` types are all primitive types.\n- Lists and types made from dataclasses are composite types, so they can all be nested arbitrary amounts inside of each other.\n- Class diagrams can be used to define the relationships between heavily nested types. Each dataclass has its own box, with lines connected to other dataclasses that are referred to in the original dataclasses fields. If the reference is in a list, the line will have a white diamond.\n- To process heavily nested data, you use `for` loops and indexing/subscript to process the lists and attribute access to process the dataclasses.\n- Heavily nested data usually results in very complicated functions, so decomposing those functions into helper functions is usually very helpful in reducing the complexity.\n","ip_ranges":"","name":"8B2) Heavily Nested Data 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\": \"Heavily Nested Data\",\n  \"youtube\": {\n    \"Bart\": \"51QBGqmH-Ts\",\n    \"Amy\": \"sId3gYdTzYw\"\n  },\n  \"video\": {\n    \"Bart\": \"https://blockpy.cis.udel.edu/videos/bakery_nesting_heavy-Bart.mp4\",\n    \"Amy\": \"https://blockpy.cis.udel.edu/videos/bakery_nesting_heavy-Amy.mp4\"\n  },\n  \"summary\": \"\",\n  \"small_layout\": true\n}","starting_code":"","subordinate":true,"tags":[],"type":"reading","url":"bakery_nesting_heavy_read","version":8},"ip":"216.73.216.157","submission":{"_schema_version":3,"assignment_id":1119,"assignment_version":8,"attempts":0,"code":"","correct":false,"course_id":37,"date_created":"2026-05-20T12:42:03.274090+00:00","date_due":"","date_graded":"","date_locked":"","date_modified":"2026-05-20T12:42:03.274090+00:00","date_started":"","date_submitted":"","endpoint":"","extra_files":"","feedback":"","grading_status":"NotReady","id":2036765,"score":0.0,"submission_status":"Started","time_limit":"","url":"submission_url-9ee1f2de-a39a-449d-8ab3-75643572736f","user_id":2044660,"user_id__email":"","version":0},"success":true}
