# Python Functions¶

Functions are used everywhere and are very useful.

• Reusing code blocks
• Organizing code
• Many libraries provide and require functions

Think of a function f(x) like a machine:

1. You put something in: x
2. You operate on x inside the function
3. The function returns some result f(x).

Keywords

• def
• return
• :

Format

def myFuncName(var_1, var_2, others):
# Insert any python code here
# You can create new variables, they can use var_1, var_2, etc.
# You can print things, load data from files, make plots, etc.

return XYZ       # Often a function returns a value
# This is not required though
# XYZ can be be an expression, a variable you defined, etc.


Then we call the function like so:

myValue = myFuncName(5.5,8.8, etc)


Or define variables and use them in calling the function

x = 5.5
y = 8.8

z = myFuncName(x, y)


Or use the function where a value is wanted:

radius = 3


Or:

print("cylinder volume =", height*circle_area(radius))


### Practice¶

• Write a function called my_sum that takes two numbers as arguments and returns the sum.
• Then call the function and store it as a variable.
• Then print the result
In [16]:
def my_sum(a, b):
return a + b

s = my_sum(5, 6)

print(s)

11


### Examples¶

• Compare the various versions of sum functions below
In [1]:
def sum_1(x,y):
z = x + y
return z

my_sum = sum_1(5,6)

print("The sum of 5 and 6 is", my_sum)

The sum of 5 and 6 is 11

In [20]:
def sum_2(x,y):
print("The sum of", x, "and", y, "is", x+y)

sum_2(5,6)

The sum of 5 and 6 is 11

In [21]:
def sum_3(x,y):
return x+y

print( sum_3(5,6) )

11

In [22]:
def sum_4(x,y):
z = x+y
return z
print("This will not print: it's after the return")

print( sum_4(5,6) )

11

In [9]:
def sum_5(x,y):
the_sum = x+y
return the_sum

x = 6
y = 7
z = sum_5(x, y)

print("The sum of", my_x, "and", my_y, "is", my_z)

The sum of 6 and 7 is 13

In [6]:
def add_and_multiply(x,y):
return x+y, x*y


11 30


### Key points¶

• Remember the def and the : and the return
• Return statements are optional, depending on what you want to do.
• We can call functions with arguments as values, like sum_3(5,6).
• We can create variables to hold values, then pass those variables as function arguments,
• like
x=5
y=7
z = sum_5(x,y)
• The names of variables in the function argument list are independent of the variable names you pass to the function.
• If I write $f(x) = x^2$, it is fine to write $f(5)$.
• The function will take $x$ to be 5, then compute $5^2$.
• If I write $f(x) = x^2$, it is fine to write $a=3$, $f(a)$.
• The function will take $x$ to be $a$, then will compute $a^2$.
• Since $a=3$, the result will be $3^2$.
• If the function returns a value, we can use it wherever a value is expected
• As in z = sum_3(x,y)
• Or this print(sum_3(x,y))

### Practice¶

• Write a function called ft_to_m that will take a length in feet and convert it to a length in meters.
• Use the converstion 1 m = 3.28084 ft.
In [1]:
def ft_to_m(L_in_ft):
return L_in_ft / 3.28084  #  = L in m

L = 6.3   # ft
ft_to_m(L)

R = 8314.46   # J/(kmol*K)


### Practice¶

• Write a function called P_IG that takes the number of moles, temperature, and volume as aguments, and returns the ideal gas pressure.
• Try out the function.
• Use good variable names.
In [2]:
def P_IG(n, T, V):
R = 8314.46     # J/kmol*K
P = n*R*T/V     # Pa
return P

P = P_IG(1,300,1)
print(P)

2494337.9999999995


### Docstrings: documentation¶

A triple quoted string at the beginning of the function is a docstring that is output when getting "help" on the function.

In [3]:
def square_it(x):
"""
input:   x
return:  x**2
type "help(square_it)" to see these comments.
"""

return x*x

help(square_it)

Help on function square_it in module __main__:

square_it(x)
input:   x
return:  x**2
type "help(square_it)" to see these comments.



### Functions can have default arguments¶

In [4]:
def get_force(m, g=9.81) : # if not given, g defaults to 9.81
print("g = ", g)
return m*g

print( get_force(10) )     # no "g" --> g=9.81
print()
print( get_force(20,2) )   # g = 2, not 9.81
print()
print( get_force(20,g=4) ) # can be explicit about it

g =  9.81
98.10000000000001

g =  2
40

g =  4
80

In [5]:
help(print)

Help on built-in function print in module builtins:

print(...)
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file:  a file-like object (stream); defaults to the current sys.stdout.
sep:   string inserted between values, default a space.
end:   string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.



### Practice¶

• Rewrite your P_IG function above to use a default value for Rg.
In [ ]:



Type help(print) and see the default arguments.

In [19]:
print(1,2,3, sep="\n")

1
2
3


### Function arguments can be specified out of order if we are explicit about the names¶

In [9]:
def myfunc(a,b) :
print("a = ", a)
print("b = ", b)

myfunc(b=7,a=5)            # note, calling with the opposite argument order

a =  5
b =  7


### Functions can be passed as arguments to other functions¶

• Example
• For given $x_1$, and $x_2$, compute $S = f(x_1)+f(x_2)$ for any function $f$
In [6]:
#-------------- Define the sum function

def sum_func(f, x1, x2):
return f(x1) + f(x2)

#-------------- Define the functions to be summed

def f_a(x):
return 2*x
def f_b(x):
return x**0.5

#-------------- Define the values of x and call sum_func

x1 = 4
x2 = 9

print(  sum_func(f_a, x1, x2)  )
print(  sum_func(f_b, x1, x2)  )

26
5.0


### Practice¶

• Write a function that computes the following integral for any function $f(x)$ $$I = \int_a^bf(x)dx$$
• Evaluate the integral using the areas of two trapazoids.
• Find a midpoint $m=(a+b)/2$. $$I = \underbrace{(m-a)\frac{f(a)+f(m)}{2}}_{\text{trapazoid 1}} + \underbrace{(b-m)\frac{f(m)+f(b)}{2}}_{\text{trapazoid 2}}$$
• Try this on $I = \int_1^2x^2dx = 2.33333$
• Question: what is the structure?
• How many functions do you need to define?
• How to call the function?
• What order to define things in.
In [7]:
def integrate_f(f, a, b) :
m = 0.5*(a + b)
return (m-a)*(f(a) + f(m))/2   +   (b-m)*(f(m) + f(b))/2

#---------- define a couple functions

def f_xSquared(x) :
return x**2.0

#----------- integrate the function

a = 1
b = 2

I = integrate_f( f_xSquared, a, b )

print("I       =", I)
print("I_exact =", 2**3/3 - 1/3)

I       = 2.375
I_exact = 2.333333333333333


### Scope: global, local¶

• Variables or functions defined inside a function are local to that function and cannot be seen outside of it.
• Variables or functions defined outside a function are global and can be seen inside later functions.
In [8]:
a = 5.5                 # a has global scope

def ff():
print("a = ", a)    # a isn't passed in, but is known

ff()

a =  5.5

In [9]:
a = 1.1

def ff2():
a = 2.2     # this is a NEW local a, not the same as above
print("inside:  a = ", a)

ff2()
print("outside: a = ", a)

inside:  a =  2.2
outside: a =  1.1


### Note¶

• Often you are given problems with many known parameters.
• It is normally best to put the parameters inside the function, rather than outside the function.
• This lets the function stand alone.
• (There may be reasonable exceptions to this rule though.)

Previously we used the following vapor pressure equation, with values of A, B, C given for Benzene. $$P_i^{sat}(T) = \exp\left(A_i - \frac{B_i}{T+C_i}\right)$$.

• A = 13.7819
• B = 2726.81
• C = 217.572

Code this function.

In [10]:
import numpy as np

#---------- DO THIS

def Psat_B(T):
A = 13.7819
B = 2726.81
C = 217.572
return np.exp(A - B/(T+C))

#---------- NOT THIS

A = 13.7819
B = 2726.81
C = 217.572

def Psat_B(T):
return np.exp(A - B/(T+C))


### A function must be defined before it is USED¶

• If you write some code that uses functions that are not defined until later, it won't work, because python doesn't know about the functions yet.
In [11]:
a = 5.5
print(f_below(a))   # function that is not defined yet!

def f_below(x):
return x*x

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-11-b2074d4227db> in <module>
1 a = 5.5
----> 2 print(f_below(a))   # function that is not defined yet!
3
4 def f_below(x):
5     return x*x

NameError: name 'f_below' is not defined

But note that the following works just fine.

• function a uses function b, but b is defined below a
• But this works because both a and b are defined when a is actually called
In [25]:
def a(x):
return b(x)

def b(x):
return x**2

print( a(3) )

9


Similarly, consider this example

• The function uses g, which is not defined until after the function is defined.
• Will this work?
In [17]:
def fma(m):
return m*g

g = 9.81

F = fma(100)

print(F)

981.0

• This works because g is defined when the function is called, that is, it is defined at the time it is needed.

In [9]:
help(print)

Help on built-in function print in module builtins:

print(...)
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file:  a file-like object (stream); defaults to the current sys.stdout.
sep:   string inserted between values, default a space.
end:   string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.


In [ ]: