## Functions
### Function Basics
A function is, essentially, a mini-program inside of a program. The primary purpose of a function is to group code blocks that execute multiple times.
#### The DRY Principle
Functions support the DRY (*Don't Repeat Yourself*) principle. If the same code blocks are used multiple time throughout a program, place those code blocks inside a function, then call the function when needed. This way, if the code block needs updates, it'll only need updated in a single location.
#### Defining a Function
Functions are defined using a `def` statement.
```python
def printHello():
print("Hello")
```
#### Calling a Function
Typing the function name, without the `def` statement, calls the function.
```python
printHello() # "Hello"
```
#### Function Arguments
Functions can optionally accept arguments. Arguments are values passed to a function.
For a function to accept arguments they must be written as parameters (i.e. variables that contain arguments) inside a function's parentheses.
```python
def printHelloName(name):
print("Hello, " + name)
printHelloName("John") # 'Hello, John'
```
*Note: Most arguments passed to a function are positional (i.e. the order the arguments are passed matters). Keyword arguments are arguments identified by a keyword. Parameters can also be optional.*
#### RETURN Statements
Rather then performing an action, a function can also return a value. This is done using the `return` keyword, followed by a value, or expression, to be returned.
```python
def add(a, b):
return a + b
print(str(add(1, 2))) # '3'
```
*Note: All functions evaluate to a return value. Python automatically adds `return None` to the end of any function definition that doesn't include a return statement. Functions without a return statement are of the `NoneType` data type.*
#### Summary
*Defining a Function*: a `def` statement defines (i.e. creates) a function
*Argument*: a value that's passed to the function
*Parameter*: function variables that have arguments passed to them
*RETURN Statement*: the `return` keyword, followed by the value or express the function should return
*Return Value*: the value a function call evaluates to
*Call a Function*: A function is called by typing the function name without the `def` statement. Calling a function sends the program's execution to the top of the function's code.
### Built-In Functions
#### print()
The `print()` function outputs the provides argument(s).
```python
print("Hello, World!") # "Hello, World!"
```
By default `print()` adds a newline character to the end of the print statement. `end` is an optional keyword argument that augments the trailing character at the end of a print statement.
```python
print("Hello", end="")
print("World") # 'HelloWorld'
```
By default `print()` automatically separates multiple string values with a single space. `sep` is an optional keyword argument that can overwrite this behavior.
```python
print("bacon", "eggs", "sausage", sep="") # 'baconeggssausage'
```
#### abs()
The `abs()` function returns the absolute value of the parameter.
```python
abs(-7.25) # 7.25
```
#### input()
The `input()` function waits for the user to enter text, then returns the text the user typed.
```python
print('Please Enter your name: ')
name = input()
```
#### len()
The `len()` function returns the number of characters in a string.
```python
len("Hello, World!") #13
```
### The Call Stack
The *Call Stack* is a stack Python uses to remembers which line of code called a function, so that execution returns to that location when it encounters the function's return statement.
Each *Frame Object* stores the line number of the original function call
### Function Scope
Python variables exist is one of two scopes, either local or global.
*local variable*: a variable that exists in a local scope
Variables that are assigned when a function is called exist in that function's local scope. When the scope is destroyed (e.g. a function's return statement is executed), the variables in that scope are forgotten. Code in a local scope can't access variables from a different local scope.
*global variable*: a variable that exists in the global scope
Variables that are assigned outside of all functions exist in the global scope. Code in the global scope can't access local variables, but code in a local scope can access global variables.
*Note: It's bad practice for local variable names to match global variable names, as this can lead to difficulties when troubleshooting.*
A `global` statement, inside a function, tells Python to modify a global variable from within that function.
```python
def spam():
global eggs
eggs='spam'
eggs = 'global'
spam()
print(eggs) # prints 'spam'
```
In a function, a variable with either ALWAYS be global, or ALWAYS be local.
- If there's a `global` statement for that variable in a function, then its a global variable.
- If the variable is used in an assignment statement in the function, then it's a local variable.
- If the variable is not used in an assignment statement, then it's a global variable.
- If a variable is being used in the global scope, then its a global variable.
```python
def spam():
global eggs
eggs = 'spam' # this is the global
def bacon():
eggs = 'bacon' # this is a local
def ham():
print(eggs) #this is the global
```
### Exception/Error Handling
By default, if a program returns an error, then the program crashes. To prevent crashes, code that could potentially have an error should be placed in a `try` clause. If an error occurs when using a `try` clause, then the program's execution will move to the start of the following `except` clause. After an `except` clause is ran, the program's execution will continue as normal.
```python
def spam(divideBy):
try:
return 42 / divideBy
except ZeroDivisionError:
print('Error: Invalid argument.')
```