{"assignment":{"_schema_version":2,"course_id":37,"date_created":"2022-06-28T19:00:00+00:00","date_modified":"2025-08-17T17:51:18.286632+00:00","extra_instructor_files":"","extra_starting_files":"","forked_id":null,"forked_version":null,"hidden":false,"id":1009,"instructions":"## Scope and Values\n\n1. Variables inside a function cannot be used outside.\n2. Variables outside a function should not be used inside.\n3. Function return values, not variables.\n\nPreviously, we learned about scope: the idea that variables inside a function cannot be used outside of the function, and variables outside a function should not be used inside the function.\nWe also learned that functions do not consume or return variables; instead, they consume and return _values_.\nThese ideas are critical in understanding how data flows through a program.\nThe goal as a programmer is to isolate variables to regions of the program so that those regions are easier to think about without having to keep the entire program in your mind all at once.\n\n## Data Flow\n\n![A picture of a winding river, with values (e.g., `64` and `\"Klaus\"`) inside. Some of the values are annotated with the names of variables.](bakery_functions_flow_river.png)\n\nThink of a program as a flowing, twisting river.\nRegular execution makes the river flow south, but functions disrupt this flow.\nAlong the way, values are carried by the current.\nAt times, we give these values names by using variables, but it is the values that flow through the program, not the variables.\n\n## Substitution\n\n```python substitution-model\ndef add(left, right):\n    return left + right\n\n5 + add(3, 4)\n# 5 + add(3, 4)\n# 5 + 7\n# 12\n```\n\nWhen you call a function, each parameter is assigned the value of a relevant argument.\nWhen you return from a function, the function call is substituted for the returned value.\nThese are the only tools we should use in Python to move data around a program.\nThis is just like what happens when you use an operator like plus or minus.\nEven though we do not see the substitution visually, it still happens.\n\n## Stack Frames\n\n![A block of code is shown on the left, demonstrating an `add_period` function. On the right, two rectangles are shown representing the call frames of the program. In the top Global Frame, the variable message is shown. In the bottom add_period frame, two local variables are shown.](bakery_functions_flow_add_period.png)\n\nEach time we call a function, we say that its local variables are _inside their own scope_.\nWe associate this scope with a _frame_, which can be used to show the current variables and their values.\nThe following stack diagram depicts these frames and their values at one point in time of the program.\nNotice that the _global frame_ is separate from the _local frame_.\nEach time we call a function, a new local frame will be added at the bottom as a \"stack\" of frames.\nThe frames on top are from if we stopped the program right before the `return` statement got executed.\nAfter the `return` statement is executed, we would cross out the `add_period` stack frame to indicate that the function's scope has ended.\n\n## Data between Functions\n\n```python data-between-functions\ndef calculate_grade(raw, weight):\n    grade = 10 * (weight+raw) ** .5\n    return grade\n    \ndef make_grade_message(grade):\n    return \"Your grade was:\" + str(grade)\n    \nraw = 45\nweight = 5\ngrade = calculate_grade(raw, weight)\nmessage = make_grade_message(grade)\nprint(message)\n```\n\nTo move data from one function to another, you cannot just look at the two functions.\nYou must also look at where the functions were called.\nThe returned value of one function should be fed into the next function.\nIn the following code, the variables defined inside `calculate_grade` are distinct from the variables outside of the function.\nIn fact, it is only the last 4 lines that move values between functions.\nWithout using return values and arguments, we cannot move data between functions.\n\n## Functions Calling Functions\n\n![Another stack frame diagram, with code on the left. The code has two functions, one of which calls the other. This results in three stack frames on the right, the bottom two being crossed out.](bakery_functions_flow_double_add3.png)\n\nThings get even more complicated when functions call other functions, but this happens all the time.\nWe are used to calling built-in functions, but we can call our own functions, too.\nWhen we call a function inside another function, we stack the new function call's frame below the current frame with the bottom frame being the current scope.\nWhen a function call ends, we remove that bottom stack and return to the one above it.\nEach function call's frame is separate from all other frames \u2014 even if they come from the same function or have variables with the same name.\n\nIn the these stack frames, you can see that the `number` variable has different values in the different scopes at the end of the program.\nYou can also see how some scopes have expired, resulting in their call frames being crossed out.\nTheir data is no longer available.\nRemember, even though each of the `number` variables have the same name, they are separate variables in their own frames and can have completely different values at any point during the program.\n\nThe global `number` variable only ever has the value `1` and keeps that value over the course of the program.\n\nThe `double_and_add3` frame's `number` variable initially has the value `1` but eventually ends up with the value `8` before the scope ends.\n\nThe `add3` frame's `number` variable initially has the value `1` but then takes on the value `4` before the scope ends.\n\n## Decomposition\n\n-   **Decomposition**: The process of breaking a large, complex problem into smaller, more manageable parts.\n\nOne of the most valuable benefits of using functions is decomposition.\nDecomposition is the process of breaking a large, complex problem into smaller, more manageable parts.\nEach part can be solved independently, and then the solutions can be combined to solve the original problem.\nThis makes it easier to understand, develop, and maintain code.\n\nFunctions are the smallest atomic units of code that can be composed together to build more complex functionality, much like how building blocks can be combined to create larger structures.\nThe syntactic mechanism for composing functions is functions calling other functions within their definitions.\n\n## Example of Decomposition\n\n```python\ndef format_phone_number(raw: str) -> str:\n    return format_us_phone(strip_separators(raw))\n\ndef strip_separators(phone_number: str) -> str:\n    \"\"\" Remove whitespace and separators \"\"\"\n    without_dashes = phone_number.replace(\"-\", \"\")\n    return without_dashes.replace(\" \", \"\")\n\ndef format_us_phone(digits: str) -> str:\n    \"\"\" Format 10 digits as a US phone number \"\"\"\n    area = digits[0:3]\n    first = digits[3:6]\n    last = digits[6:10]\n    return \"(\" + area + \") \" + first + \"-\" + last\n\nprint(format_phone_number(\"123- 456- 7890\"))\n# Output: (123) 456-7890\n```\n\nIn this example, we can see how decomposition allows us to break down the problem of formatting a phone number into smaller, more manageable functions.\nThe `format_phone_number` function needs to take in phone numbers and return them in a standard format.\nThis means that we have to remove any whitespace and separators, and then format the digits as a US phone number.\nIt's easier to tackle this problem in two distinct parts, first stripping the separators and then formatting the digits; once you've removed the extra characters, you can safely assume that there are 10 digits and extract them accordingly.\nTherefore, the decomposed version first calls the `strip_separators` function to clean up the input,\nand then passes its result to the `format_us_phone` function, before returning that final result.\n\nNow, you could definitely do this all in one function, and that wouldn't necessarily be wrong.\nBut as you start working on more and more complex programs, you need to keep an eye out for\nplaces where breaking down the program into smaller parts will make things easier.\nEach of these parts can be developed and tested independently, which can lead to more robust and maintainable code.\nAs your programs start reaching dozens and hundreds of lines of code, you'll find that having a clear structure with well-defined functions will make it much easier to understand and modify your code.\nIt's up to the programmer to decide when to break down a problem (and functions) into smaller parts.\n\n## Summary\n\n- There are three rules to keep in mind about scopes:\n  - Variables inside a function cannot be used outside.\n  - Variables outside a function should not be used inside.\n  - Functions return values, not variables.\n- Functions do not take in variables and cannot return variables. Instead, they take in values and assign them to parameters and return values.\n- If a value is returned by a function, it should be passed into another function, assigned to a variable, or otherwise used. Without being used, a value will be tossed away by Python.\n- Nested function calls are executed from the innermost call to the outermost.\n- Parameter names have no relationship to variables used as arguments, even if they are the same.\n- Functions can call other functions in their definitions.\n- Stack diagrams can help trace the value of variables over time and across functions.\n- Each time a function is called, a new frame (representing the function's scope) is added to a stack of frames. Variables that live in that scope are said to be in that frame.\n- When a function returns or otherwise ends, the function call's frame is removed from the stack frames.","ip_ranges":"","name":"2B3) Function Flow 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\": \"Function Data Flow\",\n  \"slides\": \"bakery_functions_flow.pdf\",\n  \"youtube\": {\n    \"Bart\": \"kWECzKYb8rM\",\n    \"Amy\": \"_1m1wqR2ICQ\"\n  },\n  \"video\": {\n    \"Bart\": \"https://blockpy.cis.udel.edu/videos/bakery_functions_flow-Bart.mp4\",\n    \"Amy\": \"https://blockpy.cis.udel.edu/videos/bakery_functions_flow-Amy.mp4\"\n  },\n  \"summary\": \"In this lesson, you will learn how data flows between functions in a program.\",\n  \"small_layout\": true\n}","starting_code":"","subordinate":true,"tags":[],"type":"reading","url":"bakery_functions_flow_read","version":7},"ip":"216.73.216.157","submission":{"_schema_version":3,"assignment_id":1009,"assignment_version":7,"attempts":0,"code":"","correct":false,"course_id":37,"date_created":"2026-05-20T14:01:53.004449+00:00","date_due":"","date_graded":"","date_locked":"","date_modified":"2026-05-20T14:01:53.004449+00:00","date_started":"","date_submitted":"","endpoint":"","extra_files":"","feedback":"","grading_status":"NotReady","id":2036927,"score":0.0,"submission_status":"Started","time_limit":"","url":"submission_url-2b2c2f74-d930-410c-b043-7f76c23f734c","user_id":2044668,"user_id__email":"","version":0},"success":true}
