{"assignment":{"_schema_version":2,"course_id":37,"date_created":"2022-06-28T19:00:00+00:00","date_modified":"2023-09-10T13:08:39.652069+00:00","extra_instructor_files":"","extra_starting_files":"","forked_id":null,"forked_version":null,"hidden":false,"id":1036,"instructions":"## Invalid Dataclass Operations\n\n```python dataclass-invalid-operations\nfrom dataclasses import dataclass\n\n@dataclass\nclass Circle:\n    radius: int\n    color: str\n\nred_circle = Circle(5, \"red\")\nblue_circle = Circle(5, \"blue\")\n\n# All of these cause an error!\nprint(red_circle + blue_circle)\nprint(red_circle * blue_circle)\nprint(red_circle < blue_circle)\n```\n\nMost operators do not work with dataclasses.\nAddition, subtraction, and the other math operations will not work, causing `TypeError`s.\nSimilarly, the ordering operators (like the greater than `>` and less than `<` comparison operators) will not work.\n\n## Valid Dataclass Operations\n\n```python dataclass-valid-operations\nfrom dataclasses import dataclass\n\n@dataclass\nclass Circle:\n    radius: int\n    color: str\n\nred_circle = Circle(5, \"red\")\nblue_circle = Circle(5, \"blue\")\n\n# These are all valid operations\nprint(red_circle != blue_circle)\nprint(red_circle == Circle(5, \"red\"))\nprint(red_circle != \"red\")\n```\n\nThe equality (`==`) and inequality (`!=`) operators DO work, however.\nWhen you check if two dataclasses are equal, each field is checked in order to make sure they are equal.\nHowever, you will not often need to think about equality or any other operators with dataclasses directly.\nInstead, you should be thinking about accessing the *fields* of a dataclass, in order to perform operations using the data stored inside of the dataclass.\n\n## Using Attributes\n\n```python dataclass-attributes\nfrom dataclasses import dataclass\n@dataclass\nclass Rectangle:\n    length: int\n    width: int\n\nbox = Rectangle(5, 3)\n\nprint(\"The box area is\", box.length * box.width)\n```\n\nWe have previously discussed how we can access the fields of instances to use their values: We need the name of the variable holding the instance, a period (`.`), and then the name field.\nThis is like the syntax for a method, and that is no coincidence.\nTechnically speaking, a method is just an attribute that holds a function.\nWe will not bother learning to define methods in our dataclasses yet.\nInstead, the important thing to focus on is that we can access fields from instances.\nThis is especially useful when we start passing dataclasses into functions.\n\n## Functions Consuming Dataclasses\n\n```python using-dataclasses\nfrom bakery import assert_equal\nfrom dataclasses import dataclass\n\n@dataclass\nclass Rectangle:\n    length: int\n    width: int\n\ndef area(rect: Rectangle) -> int:\n    return rect.length * rect.width\n\nbox = Rectangle(5, 3)\nassert_equal(area(box), 15)\n```\n\nIn the program shown here, we have moved the multiplication inside of a function to create a reusable `area` function that consumes a `Rectangle` instance and produces an integer.\nLet's break this down, step by step.\n\nFirst, we import the `assert_equal` function and the `dataclass` decorator. By convention, imports always go at the top of a program.\n\nNext, we define a dataclass named `Rectangle`, which will be the name of the constructor function AND the new type `Rectangle` created. The dataclass has two fields, `length` and `width`.\n\nThen, we define a function named `area` that consumes a `Rectangle` and produces an integer.\nIn the header of the `area` function, we defined one parameter named `rect` that is a `Rectangle`. We used the dataclass type name `Rectangle` on the right-hand side of the colon to indicate the type of the parameter. But on the left-hand side, we were free to give whatever name we wanted to the local variable holding the instance. We chose the concise name `rect` but could have chosen clearer names like `rectangle` or `a_rectangle`.\n\nAfter the function definition, we call the constructor function (`Rectangle`) with the values `5` and `2`, which creates a new `Rectangle` instance and assigns the result to a new variable `box`. The variable name `box` is not significant; we could have named it whatever we wanted.\n\nIn the last line of code, we unit test the `area` function by calling the function inside of an `assert_equal` call. The `Rectangle` instance associated with the variable `box` is passed as an argument.\n\nWhen the `area` function is called, the `Rectangle` instance that was used as an argument is assigned to the parameter named `rect`.\nNow the body of the function is executed, and the function can use the fields of the instance stored in `rect` to calculate and calculate and return the area.\n\nFinally, the returned integer from the `area` function call is compared against the expected value `15`, which is correct, causing the unit test to pass.\n\n## Types Matter\n\n![Two machine boxes modeling functions that consume squares. One of the machines is receiving a square, which is incorrect. The other is receiving a circle, which is correct.](bakery_structures_dataclass_ops_parameter_types.png)\n\n\nNotice the `rect` parameter in the previous program has the type `Rectangle`, which matches our previously defined dataclass.\nIn the `assert_equal` call, that parameter is matched to the corresponding argument, which, in this case, is the variable `box`.\nThat `box` contains an instance of the `Rectangle` dataclass created using its constructor.\nThe function expects a Rectangle, so it would not work if you passed in a `Circle` to the `area` function.\nNot only do the types not match, but the field accesses would also be wrong.\nThe `Circle` dataclass does not have `length` or `width` fields \u2014 only the `radius` field.\n\n## Arguments are Instances, Not Types\n\n```python\n# Good\narea(Rectangle(5, 3))\n\n# Also good\nmy_box = Rectangle(5, 3)\narea(my_box)\n\n# Does not work!\narea(Rectangle)\n\n# Also does not work!\narea(my_box.length, my_box.width)\n```\n\nThere are many mistakes that beginners make when trying to define and call functions that consume dataclasses.\nThe trick is to understand when you are dealing with the value, the variable, or the type.\nFollowing are two common issues that we see:\n\nFirst, when calling a function that consumes a dataclass, make sure you _pass in an instance instead of a type_.\nYou can pass in an instance directly or assign the instance to a variable and use the variable instead.\nHowever, you should not try to pass the type directly into the function; the type is an abstract idea instead of a concrete instance.\nYou also cannot pass the fields into the dataclass directly \u2014 you need to pass a single instance, not the individual parts.\n\n## Common Mistake: Parameter Types as Variables\n\n```python\n# This is good\ndef area(rect: Rectangle) -> int:\n    return rect.length * rect.width\n\n# This does not work\ndef area(rect: Rectangle) -> int:\n    return Rectangle.length * Rectangle.width\n\n# This does not work either!\ndef area(rect: Rectangle) -> int:\n    return length * width\n```\n\nAnother common mistake is to use the parameter type inside of the function definition instead of the parameter itself.\nOr, to mistakenly use the fields without referring to the instance at all.\nYou must make sure that you use the parameter variable when you need to access the fields of an instance.\nThe recurring theme is the same between both kinds of mistakes: You can only use the instance instead of the type.\nIn the same way that you can add `5+3` but not `5+int`, you _can access the fields of an instance but not of a dataclass type_.\nThe type is a theoretical idea instead of a concrete value.\n\n## Fields As Arguments\n\n```python fields-in-expressions\nfrom dataclasses import dataclass\n\n@dataclass\nclass Rectangle:\n    length: int\n    width: int\n\ndef as_string(rect: Rectangle) -> str:\n    # Accessing fields is just another kind of expression\n    return str(rect.length) + \"x\" + str(rect.width)\n\nbox = Rectangle(4, 5)\nprint(\"The box size is \" + as_string(box))\n```\n\nThere is nothing special about the values stored in the fields of instances.\nThe attribute access expression using the period is no different from other expressions such as a variable lookup, math operation, or function call.\nThat means we can pass the result of such expressions to other function calls, math operations, or even return them.\nIn this example, we use the `str` function by passing in the values associated with the fields of the given `rect` instance to create a nice string representation of the instance.\n\nConceptually, you need to think about whether the function needs the ENTIRE instance or just a specific field from the instance.\nThen, you can decide whether to define a function that consumes the instance or a function that consumes a field from the instance.\nOften, directly passing the entire dataclass instance is more convenient than passing in multiple fields.\n\n## Summary\n\n- Dataclasses can be compared using the equality and inequality operators.\n- Dataclasses cannot be compared with the ordering operators (`<`, `>`, etc.) or used with any other operators we have learned so far (`+`, `%`, etc.).\n- Attributes of dataclasses can be accessed using the dot operator `.` and the name of the field.\n- Dataclasses are often used as parameters for functions to be able to pass in multiple pieces of data in one parameter.\n- The name and type of a dataclass parameter should be chosen carefully to highlight the difference between an instance of the dataclass and the dataclasses type itself.\n- Two mistakes are very common when writing dataclass functions:\n  - Passing a dataclass type into a function call instead of an instance of a dataclass\n  - Using the dataclass type inside the function call instead of the instance stored in the parameter\n- Ultimately, attribute access provides a value just like any other expression, and that value can be used as an argument to another function used in an operation with other expressions or returned from a function.\n\n","ip_ranges":"","name":"4A2) Using 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  \"small_layout\": true,\n  \"header\": \"Using Dataclasses\",\n  \"youtube\": {\n    \"Bart\": \"Sk_tKKSyDIg\",\n    \"Amy\": \"Fj-ViZdaOp8\"\n  },\n  \"slides\": \"bakery_structures_dataclass_ops.pdf\",\n  \"video\": {\n    \"Bart\": \"https://blockpy.cis.udel.edu/videos/bakery_structures_dataclass_ops-Bart.mp4\",\n    \"Amy\": \"https://blockpy.cis.udel.edu/videos/bakery_structures_dataclass_ops-Amy.mp4\"\n  }\n}","starting_code":"","subordinate":true,"tags":[],"type":"reading","url":"bakery_structures_dataclass_ops_read","version":11},"ip":"216.73.216.157","submission":{"_schema_version":3,"assignment_id":1036,"assignment_version":11,"attempts":0,"code":"","correct":false,"course_id":37,"date_created":"2026-05-20T14:01:42.178882+00:00","date_due":"","date_graded":"","date_locked":"","date_modified":"2026-05-20T14:01:42.178882+00:00","date_started":"","date_submitted":"","endpoint":"","extra_files":"","feedback":"","grading_status":"NotReady","id":2036903,"score":0.0,"submission_status":"Started","time_limit":"","url":"submission_url-d672cbf5-d892-4777-aec2-bc09f8cec9c7","user_id":2044668,"user_id__email":"","version":0},"success":true}
