diff --git a/content/README.ipynb b/content/README.ipynb index c39fa79..dd15629 100644 --- a/content/README.ipynb +++ b/content/README.ipynb @@ -27,6 +27,7 @@ " * [Demystifyng Dot Notation](classes_and_oop/README.ipynb)\n", " * [Modules](classes_and_oop/module_dot_something.ipynb)\n", " * [The Hidden Life of Objects](classes_and_oop/hidden_life_of_objects.ipynb) - Classes and OOP\n", + " * [Elections OOP Coding Challenge](classes_and_oop/elections_oop_code_challenge.ipynb)\n", " * [Method chaining](classes_and_oop/method_chaining.ipynb)\n", " * [Why bother with classes and OOP at all?](classes_and_oop/why_bother.ipynb) - It's a fair question.\n", "\n", @@ -53,6 +54,14 @@ "* [Reshaping Data](pandas_reshaping.ipynb) - Melting \"wide\" data, pivoting \"long\" data\n", "\n" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38ec6f4b-5fdc-4c4a-8c2b-adcc3367fa62", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/content/classes_and_oop/elections_oop_code_challenge.ipynb b/content/classes_and_oop/elections_oop_code_challenge.ipynb new file mode 100644 index 0000000..69870b3 --- /dev/null +++ b/content/classes_and_oop/elections_oop_code_challenge.ipynb @@ -0,0 +1,251 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5488ca1b-6fe5-42e6-99f9-43828843f5e9", + "metadata": { + "tags": [] + }, + "source": [ + "# Elections OOP Coding challenge\n", + "\n", + "So you now have a basic grounding in [Python classes and OOP](hidden_life_of_objects.ipynb). Let's try to burn this new info into your synapses through a coding challenge.\n", + "\n", + "Below you'll find some toy election data. \n", + "\n", + "We're keeping it simple for now, but many hundreds -- or thousands? millions? -- of lines of code have been written in the real world to manage the complexities of elections. This code has been written by software vendors to help election officials administer local races, along with lowly newsroom coders (including yours truly) to power election night maps and analysis.\n", + "\n", + "The challenges for any given election include:\n", + "\n", + "- Organizing candidates by race (e.g. city council, gubernatorial, U.S. senator, U.S. president)\n", + "- Organizing races by a specific election (e.g. comparing presidential results by state, county, precinct over multiple elections)\n", + "- Tallying votes by candidate to determine winners, ties/runoffs, and other fun edge cases\n", + "\n", + "### The Data\n", + "\n", + "But enough preamble. Here's our extremely simplifed data.\n", + "\n", + "Each row represents the number of votes a presidential candidate received in a particular county.\n", + "\n", + "The data is structured as a list of [dictionaries](../python_dict_basics.ipynb), with each containing the following data points:\n", + "\n", + "- Election `date` and the `office` for the race\n", + "- Candidate `name` and `party`\n", + "- `State` and `County` where each candidate received a specific numvber of `votes`\n", + "\n", + "> Note: This data is *totally* fabricated. And yet you feel the nostalgia for simpler times, no?" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "b4557040-ff63-448b-a083-474de0e17748", + "metadata": {}, + "outputs": [], + "source": [ + "votes = [\n", + " {'date': '2012-11-06', 'office': 'President', 'county': 'Fairfax', 'state': 'VA', 'name': 'Romney', 'party': 'GOP', 'votes': '1000'},\n", + " {'date': '2012-11-06', 'office': 'President', 'county': 'Fairfax', 'state': 'VA', 'name': 'Obama', 'party': 'DEM', 'votes': '2000'},\n", + " {'date': '2012-11-06', 'office': 'President', 'county': 'Shenandoah', 'state': 'VA', 'name': 'Romney', 'party': 'GOP', 'votes': '800'},\n", + " {'date': '2012-11-06', 'office': 'President', 'county': 'Shenandoah', 'state': 'VA', 'name': 'Obama', 'party': 'DEM', 'votes': '800'},\n", + " {'date': '2012-11-06', 'office': 'President', 'county': 'Lee', 'state': 'VA', 'name': 'Romney', 'party': 'GOP', 'votes': '900'},\n", + " {'date': '2012-11-06', 'office': 'President', 'county': 'Lee', 'state': 'VA', 'name': 'Obama', 'party': 'DEM', 'votes': '500'}\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "675b71fc-2f34-484b-b3f6-4935d3f505aa", + "metadata": {}, + "source": [ + "### Create a Candidate class\n", + "\n", + "For this first part, we're going to provide a bit of starter code. Your task is to:\n", + "\n", + "- Update the `Candidate` class to flesh out the following methods: \n", + " - `add_votes` - add the vote record to the `Candidate.votes` list\n", + " - `total_votes` - tally up and return the total votes based on records stored in `Candidate.votes`\n", + "\n", + "> A bit of advice: Don't try to flesh out both methods at once. Work incrementally. Start with `add_votes`. Create a class instance for a candidate and test the method. Then repeat those steps for `total_votes`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1fa908a-4406-4d6d-a9e9-6a63062a0494", + "metadata": {}, + "outputs": [], + "source": [ + "class Candidate:\n", + " \n", + " def __init__(self, candidate_name):\n", + " self.name = candidate_name\n", + " self.votes = [] # An empty list where you can store vote records\n", + " \n", + " def add_votes(self, vote_record):\n", + " # Add code here to add the vote record to self.votes\n", + " pass # NOTE: \"pass\" is a placeholder that does nothing. It's useful to design code before you actually implement the functionality\n", + " \n", + " def total_votes(self):\n", + " # Add code here to tally all votes in self.votes\n", + " # Add code here to *return* the total vote count\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "id": "db1b0c98-4f9b-48e7-a60e-361557d4860c", + "metadata": {}, + "source": [ + "Here's a basic roadmap for the steps you should complete (you can use the below code cell and add additional cells as needed).\n", + "\n", + "- Grab the first vote record from `votes` list and store it in a variable.\n", + "- Create a `Candidate` instance using the first vote record that you just stashed in a variable\n", + " - Use the dictionary's `name` key to access the candidate's name\n", + " - Create an instance of the `Candidate` class by supplying the `name` value to the class\n", + " - Save the instance in a new variable called `candidate` (note, that's a lower-case `c`).\n", + "- Call `candidate.name` to verify the name\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c326cf86-648c-451a-b2da-9ab94e52d6f7", + "metadata": {}, + "outputs": [], + "source": [ + "# Here's some scratch space for you to work" + ] + }, + { + "cell_type": "markdown", + "id": "0ca6ad28-84c4-4141-8e57-e79e6a8de86b", + "metadata": { + "tags": [] + }, + "source": [ + "### Flesh out add_votes\n", + "\n", + "Next, circle back up to the original `Candidate` class and flesh out the `add_votes` method.\n", + "\n", + "Grab two records from the `votes` list for a single candidate (either Obama or Romney).\n", + "\n", + "Create a `candidate` instance and call `add_votes` twice, once for each vote record.\n", + "\n", + "Inspect `candidate.votes` to verify the records were stored on the instance." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd4b429e-e1b7-49a9-88a2-0990db1974a4", + "metadata": {}, + "outputs": [], + "source": [ + "# Here's some scratch space to work" + ] + }, + { + "cell_type": "markdown", + "id": "916410c4-59f1-45de-9d03-ac4c7c686bce", + "metadata": { + "tags": [] + }, + "source": [ + "### Flesh out total_votes\n", + "\n", + "Flesh out the `total_votes` method.\n", + "\n", + "Once again, it's not a bad idea to start small by testing the method on a small number of records for a single candidate.\n", + "\n", + "Repeat the steps from above to create a `Candidate` instance and add a few vote records.\n", + "\n", + "Now call `candidate.total_votes()`.\n", + "\n", + "Did you get the correct result?\n", + "\n", + "\n", + "### Process all the records\n", + "\n", + "With our `Candidate` class now fully fleshed out, you're ready to write the full program. \n", + "\n", + "Remember, the goal is to tally up the votes for both candidates in order to figure out who received the most votes.\n", + "\n", + "For the most part, this is straight-forward and will involve simply looping through the `votes` list and processing each record.\n", + "\n", + "**The one wrinkle is that you'll need a way to store and retrieve a single `candidate` instance for each person in the race.**\n", + "\n", + "A dictionary can be handy for this type of bookkeeping. \n", + "\n", + "For example, let's say you created an empty dictionary called `votes_by_cand = {}`, where the candidate `name` is the key and the `Candidate` instance is the value.\n", + "\n", + "As you loop throug the records, your code can simply:\n", + "- Check `votes_by_cand` to see if the candidate's name is present.\n", + " - If it's not there:\n", + " - Create a `Candidate` instance\n", + " - Call `Candidate.add_votes` with the current record\n", + " - Insert the `Candidate` instance into the dictionary, using `candidate` name as the key and the instance as the value\n", + " - If the candidate *is* in the dictionary, simply call `candidate.add_votes` with the current record\n", + " \n", + "Once you've processed all the records, create one final loop to step through the `votes_by_cand` instances and call their `total_votes()` method.\n", + "\n", + "Now you're ready to answer some news questions:\n", + "\n", + "- How many total votes did each candidate receive?\n", + "- Who won our fictional race?\n", + "- What was the vote count difference?" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "3f6ffb95-747e-49b2-b05a-e3a5dd7c2893", + "metadata": {}, + "outputs": [], + "source": [ + "# Here's some scratch space for you to work" + ] + }, + { + "cell_type": "markdown", + "id": "58244838-e1e0-4938-8e9e-e52590a3b109", + "metadata": {}, + "source": [ + "## Summary\n", + "\n", + "Ok, hopefully you're feeling more comfortable with classes and OOP after that bit of practice.\n", + "\n", + "Next up: unraveling the mysteries of [\"method chaining\"](method_chaining.ipynb)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5be35915-220f-43ce-86cd-975d972d2a6b", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/content/classes_and_oop/hidden_life_of_objects.ipynb b/content/classes_and_oop/hidden_life_of_objects.ipynb index 822d9c8..c9d77a2 100644 --- a/content/classes_and_oop/hidden_life_of_objects.ipynb +++ b/content/classes_and_oop/hidden_life_of_objects.ipynb @@ -516,197 +516,16 @@ }, { "cell_type": "markdown", - "id": "8e0212b6-6477-49f5-9427-a26e3442e0db", + "id": "339e9f21-0da7-4772-8833-9c2e3fa36e3d", "metadata": {}, "source": [ - "## Coding challenge\n", - "\n", - "So you now have a basic grounding in Python classes and OOP. Let's try to burn this new info into your synapses through a coding challenge.\n", - "\n", - "Below you'll find some toy election data. We're keeping it simple for now, but many hundreds -- or thousands? millions? -- of lines of code have been written in the real world to manage the complexities of elections. This code has been written by software vendors to help election officials administer local races, along with lowly newsroom coders (including yours truly) to power election night maps and analysis.\n", - "\n", - "The challenges for any given election include:\n", - "\n", - "- Organizing candidates by race (e.g. city council, gubernatorial, U.S. senator, U.S. president)\n", - "- Organizing races by a specific election (e.g. comparing presidential results by state, county, precinct over multiple elections)\n", - "- Tallying votes by candidate to determine winners, ties/runoffs, and other fun edge cases\n", - "\n", - "### The Data\n", - "\n", - "But enough preamble. Here's our extremely simplifed data.\n", - "\n", - "Each row represents the number of votes a presidential candidate received in a particular county.\n", - "\n", - "The data is structured as a list of [dictionaries](../python_dict_basics.ipynb), with each containing the following data points:\n", - "\n", - "- Election `date` and the `office` for the race\n", - "- `candidate` name and `party`\n", - "- `State` and `County` where each candidate received a specific numvber of `votes`\n", - "\n", - "> Note: This data is *totally* fabricated. And yet you feel the nostalgia for simpler times, no?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "29960bea-168f-4613-a20c-ef1f524b122f", - "metadata": {}, - "outputs": [], - "source": [ - "votes = [\n", - " {'date': '2012-11-06', 'office': 'President', 'county': 'Fairfax', 'state': 'VA', 'candidate': 'Romney', 'party': 'GOP', 'votes': '1000'},\n", - " {'date': '2012-11-06', 'office': 'President', 'county': 'Fairfax', 'state': 'VA', 'candidate': 'Obama', 'party': 'DEM', 'votes': '2000'},\n", - " {'date': '2012-11-06', 'office': 'President', 'county': 'Shenandoah', 'state': 'VA', 'candidate': 'Romney', 'party': 'GOP', 'votes': '800'},\n", - " {'date': '2012-11-06', 'office': 'President', 'county': 'Shenandoah', 'state': 'VA', 'candidate': 'Obama', 'party': 'DEM', 'votes': '800'},\n", - " {'date': '2012-11-06', 'office': 'President', 'county': 'Lee', 'state': 'VA', 'candidate': 'Romney', 'party': 'GOP', 'votes': '900'},\n", - " {'date': '2012-11-06', 'office': 'President', 'county': 'Lee', 'state': 'VA', 'candidate': 'Obama', 'party': 'DEM', 'votes': '500'}\n", - "]" - ] - }, - { - "cell_type": "markdown", - "id": "7a253f02-1165-4394-9620-2a6c6bf40a8b", - "metadata": {}, - "source": [ - "### Create a Candidate class\n", - "\n", - "For this first part, we're going to provide a bit of starter code. Your task is to:\n", - "\n", - "- Update the `Candidate` class to flesh out the following methods: \n", - " - `add_votes` - add the vote record to the `Candidate.votes` list\n", - " - `total_votes` - tally up and return the total votes based on records stored in `Candidate.votes`\n", - "\n", - "> A bit of advice: Don't try to flesh out both methods at once. Work incrementally. Start with `add_votes`. Create a class instance for a candidate and test the method. Then repeat those steps for `total_votes`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bdf535d9-928a-422b-9d8d-20ae3ccfb0dd", - "metadata": {}, - "outputs": [], - "source": [ - "class Candidate:\n", - " \n", - " def __init__(self, candidate_name):\n", - " self.name = candidate_name\n", - " self.votes = [] # An empty list where you can store vote records\n", - " \n", - " def add_votes(self, vote_record):\n", - " # Add code here to add the vote record to self.votes\n", - " pass # NOTE: \"pass\" is a placeholder that does nothing. It's useful to design code before you actually implement the functionality\n", - " \n", - " def total_votes(self):\n", - " # Add code here to tally all votes in self.votes\n", - " # Add code here to *return* the total vote count\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "id": "8a953799-0c6a-4c25-bff7-66c87ceb5f84", - "metadata": {}, - "source": [ - "Here's a basic roadmap for the steps you should complete (you can use the below code cell and add additional cells as needed).\n", - "\n", - "- Grab the first vote record from `votes` list and store it in a variable.\n", - "- Create a `Candidate` instance using the first vote record that you just stashed in a variable\n", - " - Use the dictionary's `candidate` key to access the candidate's name\n", - " - Create an instance of the `Candidate` class by supplying the `candidate` value to the class\n", - " - Save the instance in a new variable called `candidate` (note, that's a lower-case `c`).\n", - "- Call `candidate.name` to verify the name\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "592fb46e-28ad-4a60-9a7e-6bc0a854a3d1", - "metadata": {}, - "outputs": [], - "source": [ - "# Here's some scratch space for you to work" - ] - }, - { - "cell_type": "markdown", - "id": "c37fd86f-26ef-4411-bf72-238ca04d1b2c", - "metadata": { - "tags": [] - }, - "source": [ - "### Flesh out add_votes\n", - "\n", - "Next, circle back up to the original `Candidate` class and flesh out the `add_votes` method.\n", - "\n", - "Grab two records from the `votes` list for a single candidate (either Obama or Romney).\n", - "\n", - "Create a `candidate` instance and call `add_votes` twice, once for each vote record.\n", - "\n", - "Inspect `candidate.votes` to verify the records were stored on the instance." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c08b954b-f9bf-4a2a-87dd-5ca9849007ae", - "metadata": {}, - "outputs": [], - "source": [ - "# Here's some scratch space to work" - ] - }, - { - "cell_type": "markdown", - "id": "e300a1ec-1768-469a-8728-428785519d57", - "metadata": {}, - "source": [ - "### Flesh out total_votes\n", - "\n", - "Flesh out the `total_votes` method.\n", - "\n", - "Once again, it's not a bad idea to start small by testing the method on a small number of records for a single candidate.\n", - "\n", - "Repeat the steps from above to create a `Candidate` instance and add a few vote records.\n", - "\n", - "Now call `candidate._total_votes()`.\n", - "\n", - "Did you get the correct result?\n", - "\n", - "\n", - "### Process all the records\n", - "\n", - "With our `Candidate` class now fully fleshed out, you're ready to write the full program. \n", - "\n", - "Remember, the goal is to tally up the votes for both candidates in order to figure out who received the most votes.\n", - "\n", - "For this most part, this is straight-forward and will involve simply looping through the `votes` list and processing each record.\n", - "\n", - "The one wrinkle is that you'll need a way to store and retrieve a single `candidate` instance for each person in the race. \n", - "\n", - "A dictionary can be handy for this type of bookkeeping. \n", - "\n", - "For example, let's say you created an empty dictionary called `votes_by_cand = {}`, where the candidate name is the key and the `Candidate` instance is the value.\n", - "\n", - "As you loop throug the records, your code can simply:\n", - "- Check `votes_by_cand` to see if the candidate's name is present.\n", - " - If it's not there:\n", - " - create a Candidate instance\n", - " - Call `Candidate.add_votes` with the current record\n", - " - Insert the `Candidate` instance into the dictionary, using `candidate` name as the key and the instance as the value\n", - " - If the candidate *is* in the dictionary, simply call `candidate.add_votes` with the current record\n", - " \n", - "Once you've processed all the records, create one final loop to step through the `votes_by_cand` instances and call their `total_votes()` method.\n", - "\n", - "Now you're ready to answer a few news questions:\n", - "\n", - "- Who won our fictional race?\n", - "- What was the vote count difference?\n", - "\n", "## Summary\n", "\n", "Hopefully you're now more comfortable with the basics of classes and OOP in Python.\n", "\n", - "You're now equipped with the knowledge to start unraveling those gnarly one-liners known as [\"method chains\"](method_chaining.ipynb)." + "Head on over to [Elections OOP Coding Challenge](elections_oop_code_challenge.ipynb) for some hands-on practice.\n", + "\n", + "Then jump to [\"method chains\"](method_chaining.ipynb) to learn how to unravel those gnarly one-liners we mentioned at the start of the lesson." ] } ], diff --git a/content/classes_and_oop/method_chaining.ipynb b/content/classes_and_oop/method_chaining.ipynb index 9df61bf..26af10d 100644 --- a/content/classes_and_oop/method_chaining.ipynb +++ b/content/classes_and_oop/method_chaining.ipynb @@ -35,11 +35,11 @@ "\n", "But let's detail each step in the chain, starting with the initial string object: `\"some text, with a comma\"`\n", "\n", - "- .`upper()` makes the string all upper case\n", - "- `.replace(\"TEXT\", \"SCREAMY TEXT\")` substitutes `SCREAMY_TEXT` for `TEXT`\n", + "- `.upper()` makes the string all upper case and *returns* a copy of the string in all caps\n", + "- `.replace(\"TEXT\", \"SCREAMY TEXT\")` substitutes `SCREAMY_TEXT` for `TEXT` and *returns* the modified string\n", "- `.split(',')`...well...splits the text on the comma and *returns* a list containing the text fragments\n", "\n", - "In this simple case, each step in the chain modifies and returns the string produced by the prior step.\n" + "> Again, to emphasize: Each step in the chain modifies and returns the string produced by the prior step (up until the last step, which returns a list)\n" ] }, { @@ -113,7 +113,7 @@ "\n", "### Methods, Unchained\n", "\n", - "If we break the code up into separate steps -- and apply `type` function along the way -- we can get a handle on how things work." + "If we break the code up into separate steps -- and apply `type` along the way -- we can get a handle on how things work." ] }, { @@ -249,7 +249,9 @@ "source": [ "As you gain comfort with various Python libraries and the language in general, we suspect you'll come to appreciate method chaining as a powerful technique that enables more compact and readable code.\n", "\n", - "But at the outset, it can be downright confusing. Hopefully you're now equipped with a few key concepts that can help you decipher this style of code when you encounter it in the wild." + "But at the outset, it can be downright confusing. Hopefully you're now equipped with a few key concepts that can help you decipher this style of code when you encounter it in the wild.\n", + "\n", + "Head on over to [Why bother](why_bother.ipynb) for a few final thoughts on classes and OOP. " ] } ], diff --git a/content/classes_and_oop/why_bother.ipynb b/content/classes_and_oop/why_bother.ipynb index 0c6d052..cd41cd8 100644 --- a/content/classes_and_oop/why_bother.ipynb +++ b/content/classes_and_oop/why_bother.ipynb @@ -13,13 +13,13 @@ "\n", "After all, it's perfectly possible to write valid and useful Python code without ever creating a class, much less chaining methods. But you'll notice that many libraries use classes, and a primary reason for their existence and widespread use is complexity. Specifically, once you gain some comfort with classes and OO, **you can use them to dramatically reduce the complexity of large code bases**.\n", "\n", - "As programs grow in size from a few lines in one script or Notebook to hundreds or thousands -- or hundreds of thousands -- of lines scattered across many modules, it can become extremely difficult to maintain and debug code. \n", + "As programs grow in size from a few lines in one script or Notebook to hundreds or thousands of lines scattered across many modules, it can become extremely difficult to maintain and debug code. \n", "\n", "Classes provide a mechanism to model aspects of our code in sensible ways, so we can group together related bits of data and functionality (aka *methods*) and use them in larger programs.\n", "\n", "For example, if you're building a system to gather and publish election night results, you might want to create classes for `Race` and `Candidate`. In such a system, you could store the votes each candidate received from a given precinct on separate instances of the `Candidate` class (one per candidate). Meanwhile, the `Race` class might have a `determine_winner` method that tallies the vote counts of each candidate and figures out the winner -- or if the race was a tie.\n", "\n", - "Classes can be quite useful in such a system since they let you model real world entities and more easily associate useful data and functionality with each entity. Such an approach can dramatically improve your ability to make sense of complex systems. And of course, you can use this approach for more abstract domains such as reading and writing CSV files, interacting with an operating system, analyzing data, and so on. \n", + "Classes can be quite useful in such a system since they let you model real world entities and more easily associate useful data and functionality with each entity. Such an approach can dramatically improve your ability to make sense of complex systems. And of course, you can use this approach for more abstract domains such as reading and writing [CSV files](https://docs.python.org/3/library/csv.html), interacting with an [operating system](https://docs.python.org/3/library/os.html), [analyzing data](https://pandas.pydata.org/), and so on. \n", "\n", "There are many more features of classes and OO in general -- we've barely scratched the surface here -- that make them useful and flexible tools for writing code, and we encourage you to learn more about them on your Python coding journey.\n", "\n", @@ -27,14 +27,6 @@ "\n", "And if nothing else, a basic understanding of classes and how they work will help you understand *how* to use dot-notation to access data and functionality in classes and modules." ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "431bed77-adca-40c3-b13f-380e9b5889b0", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": {