<jupyter_start><jupyter_text>Pass by Value; Pass by ReferenceThis is an important topic in the study of computing. It's tricky to understand at first, but you'll get it with practice. Once you understand this topic (and you will) your programming skills will really take off.In an Object Oriented Programming (OOP) language like Python, an Object contains both the data itself and a set of methods (like functions) that can operate on that data. When an Object is created it is assigned a unique Object id, often referred-to as its memory address or ***Pointer***. An immutable Object can't be changed once it's created; and a mutable Object can be changed once it's created. Here's a list of mutable and immutable data types that we've seen so far: Immutable Data Types* String* Int* Bool* Float* Tuple Mutable Data Types* List* Dictionary* SetThe concept of mutability can be difficult to understand. We've discussed it in previous notebooks, but consider the code below:<jupyter_code>s = "Go Navy"
print(s)
s = "Beat Army"
print(s)<jupyter_output><empty_output><jupyter_text>Doesn't that make `s` mutable? Saying a variable is immutable means that it can't be changed, but it sure looks like `s` is changing. What's going on?In the code above, we're not changing (mutating) `s`, we're actually throwing away the old Object associated with `s` and creating an entirely new Object for `s`. To illustrate this, remember: ***When an Object is created it is assigned a unique Object id.*** Python provides a built-in function to display an Object's id and we can use it to see how `s` is assigned a new string Object as the code runs:<jupyter_code>s = "Go Navy"    # Create a new string Object
print(s)
print(id(s))
s = "Beat Army"  # Create a different string Object (throwing the old one away)
print(s)
print(id(s))<jupyter_output><empty_output><jupyter_text>Run the code above and observe how `s` gets a new Object id when it goes from `Go Navy` to `Beat Army`. The variable `s` is immutable, but we can discard its Object and create a new one. That's different from changing an immutable variable. To see this, examine the code below. Since the variable `s` is immutable, the code will crash:<jupyter_code>s = "Go Navy"
print("The first letter is", s[0])
s[0] = 'B'
print("The first letter is", s[0])<jupyter_output><empty_output><jupyter_text>We can *access* individual letters in a string (line 2), but the code crashes at line 3 because we cannot *change* (mutate) individual letters in a string.  Passing Variables to FunctionsUnderstanding how Python handles Objects is key to understanding the difference between ***Pass by Value*** and ***Pass by Reference***. A simple set of rules emerges:* If you pass an immutable variable to a function as an argument, any changes the function makes to the associated parameter **will not** affect the value of the original argument. We call this ***Pass by Value***.* If you pass a mutable variable to a function, any changes the function makes to the associated parameter **will** affect the value of the original argument. We call this ***Pass by Reference***.Programming with those simple rules in mind is enough, and you'll get it right if you understand them. It's okay if you just memorize them for now, but you're more advanced than that. You're becoming a skilled programmer and the sky is the limit. It's been long journey, and the journey will continue throughout your entire life, but as you embark on the next phase you're now ready to hear the unvarnished truth: [***All Python Variables are Actually Pointers to Objects***](https://medium.com/@abdullah.tech/python-variables-are-pointers-c8b85880f21e).Let's start with a simple function that takes an integer and returns double that value:<jupyter_code>def doubleIt(base):
    return 2 * base


n = int(input("Enter an integer: "))
print(f"2 x {n:,d} = {doubleIt(n):,d}")<jupyter_output><empty_output><jupyter_text>Run the code above and explore how it works. You should be comfortable with the use of *f-strings*.Now let's use Python's [id()](https://docs.python.org/3/library/functions.html) function to examine the unique id numbers of the variables being used:<jupyter_code>def doubleIt(x):
    print(f"Inside function: x = {x:,d}; id(x) = {id(x):d}")
    return 2 * x


n = int(input("Enter an integer: "))
print(f"Outside function before call: n = {n:,d}; id(n) = {id(n):d}")
print(f"2 x {n:,d} = {doubleIt(n):,d}")
print(f"Outside function after call: n = {n:,d}; id(n) = {id(n):d}")<jupyter_output><empty_output><jupyter_text>The id of `x` (the function parameter) should be the same as the id of `n` (the argument in the function call). That's because Python is passing `n` as a Pointer for use in the function `doubleIt()`. Now let's examine what happens if we change the value of the `x` parameter inside the function:<jupyter_code>def doubleIt(x):
    print(f"Inside function before mod: x = {x:,d}; id(x) = {id(x):d}")
    x *= 2
    print(f"Inside function after mod: x = {x:,d}; id(x) = {id(x):d}")
    return x


n = int(input("Enter an integer: "))
print(f"Outside function before call: n = {n:,d}; id(n) = {id(n):d}")
print(f"2 x {n:,d} = {doubleIt(n):,d}")
print(f"Outside function after call: n = {n:,d}; id(n) = {id(n):d}")<jupyter_output><empty_output><jupyter_text>Run the code. Notice that the parameter `x` starts with the same id as the argument `n`. It then gets a new id inside the function, however the id of `n` never changes. Since the argument `n` is an immutable type (integer) any changes to `x` are local in scope to `doubleIt()` and have no impact on the value of `n`. We we would call this situation ***Pass by Value***. Passing by ReferenceSo, if you pass an immutable variable to a function as an argument, any changes the function makes to the associated parameter **will not** affect the value of the original argument. We call this ***Pass by Value***. Now let's take a look at how it works using a mutable variable type. We'll tweak the code to take a Python list and double the second item in the list:<jupyter_code>def modifySecond(aList):
    print(
        f"Inside function before mod: aList = {str(aList):s}; id(aList) = {id(aList):d}")
    aList[1] = 100
    print(
        f"Inside function after mod: aList = {str(aList):s}; id(aList) = {id(aList):d}")
    return


L = [2, 4, 6]
print(f"Outside function before call: L = {str(L):s}; id(L) = {id(L):d}")
modifySecond(L)
print(f"Outside function after call: L = {str(L):s}; id(L) = {id(L):d}")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10771113831089352, 'fraction_numerical': 0.004130966952264382, 'mean_word_length': 4.899819494584838, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '666692', 'license': 'MIT', 'n_tokens_mistral': 1992, 'n_tokens_neox': 1923, 'n_words': 935, 'path': 'content/07_collections04.ipynb', 'repo_name': 'geozeke/notebooks', 'size': '6536'}