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
cylinder_volume = circle_area(radius)*height

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     

add, prod = add_and_multiply(5,6)
print(add, prod)
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.
  • Don't forget to comment your code, including comments.
  • 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.
    • After you have thought about this, look at the previous example and consider it's structure.
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.

See also:

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 [ ]: