# Functions

## Encapsulating a series of operations

First, we will define a not-too-useful function that calculates y give a slope of 5, a y-intercept of -3, and an x-value of 9 (exactly as above). We do this by wrapping a function around the sequence of operations above. The return value of this function is the computed y value:
```    def y():
m = 5
x = 9
b = -3
return m * x + b```
`The keyword def indicates that a function definition is occurring. The name of this particular function is y. The names of the things being sent to the function are given between the parentheses; since there is nothing between the parentheses, we don't need to send any information to this function when we use it. Together, the first line is known as the function signature, which tells you the name of the function and how many values it expects to be sent when it is used.`
`The stuff indented from the first line of the function definition is called the function body and is the code that will be evaluated (or executed) when the function is used.The use of a function is known as a function call. Most function calls look similar: the name of the function to be called followed by a parenthesized list of information to send the function so that it can do its job. Thus, the parentheses after the y indicate that we wish to call the y function and get its value. Because we designed the function to take no information when called, we do not place any information between the parentheses.`
```
Passing arguments

A hallmark of a good function is that it lets you compute more than one thing. We can modify our y function to take in the value of x in which we are interested. In this way, we can compute more than one value of y. We do this by passing in some information. This information that is passed to a function in a function call is known as an argument, in this case, the value of x.
def y(x):
slope = 5
intercept = -3
return slope * x + intercept
Note that we have moved the variable x from the body of the function to between the parentheses. We have also refrained from giving it a value since its value is to be sent to the function when the function is called. What we have done is to parameterize the function to make it more general and more useful. The variable x is now called a formal parameter since it sits between the parentheses in the first line of the function definition.
>>> y(0)
-3
>>> y(-2)
-13

What if we wish to compute a y-value for a given x for a different line? One approach would be to pass in the slope and intercept as well as x:
def y(x,m,b):
return m * x + b
>>> y(0,5,-3)
-3

Creating functions on the fly (ADVANCED)

Since creating functions is hard work (lots of typing) and Computer Scientists avoid unnecessary work like the plague, somebody early on got the idea of writing a function that itself creates functions! Brilliant! We can do this for our line problem. We will tell our creative function to create a y function for a particular slope and intercept! While we are at it, let's change the variable names m and b to slope and intercept, respectively:
def makeLine(slope,intercept):
def y(x):
return slope * x + intercept
return y  # the value of y is returned, y is NOT CALLED!
>>> a = makeLine(5,-3)
>>> b = makeLine(6,2)
>>> a(9)
42

The Function and Procedure Patterns

When a function calculates (or obtains) a value and returns it, we say that it implements the function pattern. If a function does not have a return value, we say it implements the procedure pattern.

Here is an example of the function pattern:
def square(x):
return x * x

This function takes a value, stores it in x, computes the square of x and returns the result of the computation.

Here is an example of the procedure pattern:
def greeting(name):
print("hello,",name)
return "done"

Another common mistake is to inadvertently implement a procedure pattern when a function pattern is called for. This happens when the return keyword is omitted.
def psquare(x):
x * x

Calling this kind of function yields a surprising result:
>>> x = psquare(4)
>>>print(x)
None

When you do not specify a return value, Python will supply one for you anyway. This supplied value is the special symbol `None`. Since psquare did not explicitly return a value, `None` was returned and assigned to the variable x.

```