<jupyter_start><jupyter_text>Functions, Part II  ScopeThe *scope* of a variable is the part of a program within which that variable can be "seen": assigned to, used in a computation, printed, and so on.[Here is more detail on scope.](https://en.wikipedia.org/wiki/Scope_(computer_science))[And here is a discussion of scoping in Python in particular.](https://www.w3schools.com/python/python_scope.asp)Let's look at a code example illustrating scoping in Python.<jupyter_code>dbl_name = "BoutrosBoutros"

def f1(s):
    print("\nFrom within f1:", s)
    return s + s

dbl_name = f1("Naomi")
# the next line won't work... name is out of scope
# print(name)
def f2():
    # print("From within main f2:", name)
    vehicle = "Ford"
    print("\nFrom within f2:", vehicle)
    
f2()
# can't print vehicle from here -- variable out of scope:
# print(vehicle)<jupyter_output>From within f2: Ford<jupyter_text>Scopes can be nested, like Russian dolls.<jupyter_code>def main():
    name = "Bernard"
    vehicle = "Volvo"
    print("From within main:", name, vehicle)

    f1("Dolores")
    print("\nFrom within main:", name, vehicle)

    f2()
    print("\nFrom within main:", name, vehicle)


main()<jupyter_output><empty_output><jupyter_text>Default parametersThe terms *parameter* and *argument* are often used interchangeably. However, if we want to be strictly correct, a *parameter* is the placeholder for an *argument* in a function definition, and an *argument* is the actual value passed in to the function. But don't worry too much about this: even professional programmers are often sloppy with this technical distinction.Python allows passing function arguments by position, which is what we have been exclusively dealing with so far. So we might define a function called `place_agent(x, y)`, where `x` and `y` are the coordinates on a grid where an agent will be placed.But Python also allows *default* parameters. These take the form `param=default_val`. All purely positional parameters must come before any parameters with default values.The default parameters may be skipped, in which case the function will be passed the default value. This facility is very valuable, as it allows one to extend a function to take new arguments without breaking existing code.Here is an example of a function with one positional parameter and one default parameter:<jupyter_code>from math import log, e

log_e = log(e)
log_e_b2 = log(e, 2)
log_e_b10 = log(e, 10)

print("log of e base e =", log_e)
print("log of e base 2 =", log_e_b2)
print("log of e base 10 =", log_e_b10)
def weather(today="sunny"):
    print ("Today's weather is", today)
    
weather()
weather("rainy")
weather("foggy")<jupyter_output>Today's weather is sunny
Today's weather is rainy
Today's weather is foggy<jupyter_text>Keyword argumentsPython functions also can accept *keyword* arguments, meaning we can pass arguments by name. Let's see how those work.<jupyter_code>def rhyme(flower1, flower2, color1, color2):
    # three ways to do same output:
    print(flower1 + " are " + color1)
    # print(flower1, "are", color1)
    # print("{} are {},".format(flower1, color1))
    print("{} are {},".format(flower2, color2))
    print("Sugar is sweet, and so are you")


rhyme("Roses", "Violets", "red", "blue")
def rhyme_two(flower1, flower2="Violets", color1="red",
              color2="blue"):
    print("{} are {},".format(flower1, color1))
    print("{} are {},".format(flower2, color2))
    print("Sugar is sweet, and so are you")

print()
# rhyme_two("Pine needles")
rhyme_two("Pine needles", "green")
# rhyme_two(color1="green")
rhyme_two(flower1="Daisies", color2="white")
rhyme_two("Tulips")<jupyter_output>Tulips are red,
Violets are blue,
Sugar is sweet, and so are you
{'fraction_non_alphanumeric': 0.11211959423384944, 'fraction_numerical': 0.012279765082754938, 'mean_word_length': 4.782407407407407, 'pattern_counts': {'":': 1, '<': 14, '<?xml version=': 0, '>': 14, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, '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': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '593567', 'license': 'Apache-2.0', 'n_tokens_mistral': 1196, 'n_tokens_neox': 1139, 'n_words': 454, 'path': 'notebooks/Functions2.ipynb', 'repo_name': 'gcallah/IntroPython', 'size': '3746'}