{ "cells": [ { "cell_type": "markdown", "id": "d91692eb-ef0b-4dab-a519-aa6da1f88e41", "metadata": {}, "source": [ "###
San Jose State University
Department of Applied Data Science

**DATA 200
Computational Programming for Data Analytics**

Spring 2023
Instructor: Ron Mak
" ] }, { "cell_type": "markdown", "id": "4286f4e5-4839-4d43-9909-2e6f7c3e8b13", "metadata": {}, "source": [ "## Global vs. Local Variables" ] }, { "cell_type": "markdown", "id": "d7fa787d-0f27-4415-bf3d-ea739e148dd8", "metadata": {}, "source": [ "#### _TL;DR:_ Just read **The Bottom Line** at the end of all this!" ] }, { "cell_type": "markdown", "id": "d2a73f60-8a10-46a9-8883-ba0d94680f75", "metadata": {}, "source": [ "#### Variable `x` is **global**." ] }, { "cell_type": "code", "execution_count": null, "id": "e808e4fd-435e-44b5-b37c-2abb793e32a1", "metadata": {}, "outputs": [], "source": [ "x = 3" ] }, { "cell_type": "markdown", "id": "d3678e6d-ddba-4348-a7b1-9bcd72e86501", "metadata": {}, "source": [ "#### Function `my_func_1()` below demonstrates that a function can access a global variable such as `x` as long as it doesn't try to modify it. The `id()` function shows that it's been the same variable all along." ] }, { "cell_type": "code", "execution_count": null, "id": "26803e7f-84a3-4b85-b129-6f56b08583c3", "metadata": {}, "outputs": [], "source": [ "def my_func_1():\n", " print(f'{\"In my_func1:\":>25} {id(x) = } {x = }')" ] }, { "cell_type": "code", "execution_count": null, "id": "ae5bf4b0-befd-4ca0-bbea-72fc9fd593c5", "metadata": {}, "outputs": [], "source": [ "print(f'{\"In main before the call:\":>25} {id(x) = } {x = }')\n", "my_func_1()\n", "print(f'{\"In main after the call:\":>25} {id(x) = } {x = }')" ] }, { "cell_type": "markdown", "id": "0fcf2545-0863-483c-bbe7-a665749e09cc", "metadata": {}, "source": [ "#### Function `my_func_2` below modifies variable `x` and therefore, it silently creates a **local** variable `x` that overrides the global variable `x`. The `id()` function confirms that the local `x` is a different variable from the global `x`. After the return to the main, the value of the global `x` is unchanged." ] }, { "cell_type": "code", "execution_count": null, "id": "c26fd9dd-95ec-4b49-8de5-b2d97b1a681d", "metadata": {}, "outputs": [], "source": [ "def my_func_2():\n", " x = 7\n", " print(f'{\"In my_func1:\":>25} {id(x) = } {x = }')" ] }, { "cell_type": "code", "execution_count": null, "id": "2c13c8a9-98f7-45bc-8841-6e8dc4281efe", "metadata": {}, "outputs": [], "source": [ "print(f'{\"In main before the call:\":>25} {id(x) = } {x = }')\n", "my_func_2()\n", "print(f'{\"In main after the call:\":>25} {id(x) = } {x = }')" ] }, { "cell_type": "markdown", "id": "fc8fad4a-ec7d-4a93-b6d6-890713c1e06c", "metadata": {}, "source": [ "#### _Oops!_ Function `my_func3` below fails with an error. It tries to modify global variable `x` and so it must create a local variable `x`. However, `x += 7` is equivalent the `x = x + 7` and so the `x` on the right side of the assignment is the local `x` which doesn't yet have a value (it's \"unbound\")." ] }, { "cell_type": "code", "execution_count": null, "id": "c7746ed8-620d-4e51-b4cf-edfdf52ea55f", "metadata": {}, "outputs": [], "source": [ "def my_func_3():\n", " x += 7\n", " print(f'{\"In my_func1:\":>25} {id(x) = } {x = }')" ] }, { "cell_type": "code", "execution_count": null, "id": "978ae10c-1052-466e-8513-8f9f682bc4b3", "metadata": {}, "outputs": [], "source": [ "print(f'{\"In main before the call:\":>25} {id(x) = } {x = }')\n", "my_func_3()\n", "print(f'{\"In main after the call:\":>25} {id(x) = } {x = }')" ] }, { "cell_type": "markdown", "id": "28970e76-c069-4ce5-9bc6-ea7138b4048f", "metadata": {}, "source": [ "## Function Parameters" ] }, { "cell_type": "markdown", "id": "7c7b1e38-f7be-4527-8be7-cb46d293cc41", "metadata": {}, "source": [ "#### Function `my_parm_1()` below confirms that its parameter `p` is a **reference** to the global variable `x` and therefore, parameter `p` is the same variable as `x`. Of course, `x` is unchanged after returning from the call." ] }, { "cell_type": "code", "execution_count": null, "id": "a3e3586b-c8b4-45cd-a620-fb6b4ff979d3", "metadata": {}, "outputs": [], "source": [ "def my_parm_1(p):\n", " print(f'{\"In my_parm_1:\":>30} {id(p) = } {p = }')" ] }, { "cell_type": "code", "execution_count": null, "id": "07dacef8-1d8a-459e-81c6-809f3a372fe6", "metadata": {}, "outputs": [], "source": [ "print(f'{\"In main before the call:\":>30} {id(x) = } {x = }')\n", "my_parm_1(x)\n", "print(f'{\"In main after the call:\":>30} {id(x) = } {x = }')" ] }, { "cell_type": "markdown", "id": "a80b3d2b-1850-4c76-81b1-c4a44ce5c1d7", "metadata": {}, "source": [ "#### Function `my_parm_2()` below modifies its parameter `p`. But before doing so, `p` starts out as a reference to global variable `x`. The statement `p += 7` modifies `p`. Therefore, the function silently creates a new local variable `p`, as confirmed by `id(p)`, and continues executing without an unbound error. After returning from the call, global variable `x` is unchanged." ] }, { "cell_type": "code", "execution_count": null, "id": "10cf5100-29b0-4692-adbc-a400c43eab07", "metadata": {}, "outputs": [], "source": [ "def my_parm_2(p):\n", " print(f'{\"In my_parm_2 before modifying p:\":>35} {id(p) = } {p = }')\n", " p += 7\n", " print(f'{\"In my_parm_2 after modifying p:\":>35} {id(p) = } {p = }')" ] }, { "cell_type": "code", "execution_count": null, "id": "ea12e076-026e-4217-9777-808531e130bc", "metadata": {}, "outputs": [], "source": [ "print(f'{\"In main before the call:\":>35} {id(x) = } {x = }')\n", "my_parm_2(x)\n", "print(f'{\"In main after the call:\":>35} {id(x) = } {x = }')" ] }, { "cell_type": "markdown", "id": "f13d131f-2853-4483-8bf4-9910ed1f4520", "metadata": {}, "source": [ "## The Bottom Line\n", "\n", "#### This is all somewhat confusing and a source of logic errors that are hard to find. Therefore, follow these guidelines to stay out of trouble:\n", "- A function should not access any global variables, even if they don't modify them. If a function needs to use the value of a global variable, you should pass the variable as an argument when you call the function. Then the function should use the corresponding parameter.\n", "- A function should not directly modify the value of its parameters. If a function must modify a parameter's value, it should first **explitly** create a local variable and then work with the local variable instead. For example:\n", "```\n", "def func(p):\n", " local_p = p # explicitly create a local variable\n", " # Now you can work with local_p and\n", " # modify its value in subsequent statements.\n", "```" ] }, { "cell_type": "markdown", "id": "5db44871-2daa-43cb-b0cc-89f034b4ebf1", "metadata": {}, "source": [ "#### Later, you'll learn that if you pass a global **list** as an argument to a function, it's OK for the function to directly modify the **contents** of the corresponding list parameter. Doing so **will change** the global list's contents." ] }, { "cell_type": "code", "execution_count": null, "id": "1e9ce3cd-18d7-4ba3-8baa-c4493483d62e", "metadata": {}, "outputs": [], "source": [ "# Copyright (c) 2023 by Ronald Mak" ] } ], "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.5" } }, "nbformat": 4, "nbformat_minor": 5 }