Formatting & Functions


In [1]:
# this block is just for the style sheet for the notebook
from IPython.core.display import HTML
def css_styling():
    styles = open("styles/custom.css", "r").read()
    return HTML(styles)
css_styling()


Out[1]:

Formatting

The following was obtained from ebeab.com


In [36]:
# define variables
x = 3.1415926
y = 1

In [3]:
# 2 decimal places 
print "{:.2f}".format(x)


3.14

In [4]:
# 2 decimal palces with sign
print "{:+.2f}".format(x)


+3.14

In [37]:
# 2 decimal palces with sign
print "{:.2f}".format(-y)


-1.00

In [11]:
# print with no decimal palces
print "{:.0f}".format(x)


3

In [12]:
# left padded with 0's - width 2
print "{:0>2d}".format(y)


01

In [13]:
# right padd with x's - total width 4
print "{:x<4d}".format(y)


1xxx

In [14]:
# right padd with x's - total width 4
print "{:x<4d}".format(10*y)


10xx

In [16]:
# insert a comma separator
print "{:,}".format(10000000000000)


10,000,000,000,000

In [21]:
# % format
print "{:.4%}".format(0.1235678)


12.3568%

In [38]:
# exponent notation
print "{:.3e}".format(10000000000000)


1.000e+13

In [22]:
#  right justified, with 10
print "{:10d}".format(100)


       100

In [23]:
#  left justified, with 10
print "{:<10d}".format(100)


100       

In [24]:
#  center justified, with 10
print "{:^10d}".format(100)


   100    

In [28]:
# string substitution
s1 = 'so much depends upon {}'.format('a red wheel barrow')
s2 = 'glazed with {} water beside the {} chickens'.format('rain', 'white')
print s1
print s2


so much depends upon a red wheel barrow
glazed with rain water beside the white chickens

In [39]:
# another substitution
s1 = " {0} is better than {1} ".format("emacs", "vim")
s2 = " {1} is better than {0} ".format("emacs", "vim")
print s1
print s2


 emacs is better than vim 
 vim is better than emacs 

In [40]:
## defining formats
email_f = "Your email address was {email}".format

## use elsewhere
print(email_f(email="bob@example.com"))


Your email address was bob@example.com

Functions

Why Use Functions? (from your textbook)

Before we get into the details, let’s establish a clear picture of what functions are all about. Functions are a nearly universal program-structuring device. You may have come across them before in other languages, where they may have been called subroutines or procedures. As a brief introduction, functions serve two primary development roles:


Maximizing code reuse and minimizing redundancy

As in most programming languages, Python functions are the simplest way to package logic you may wish to use in more than one place and more than one time. Up until now, all the code we’ve been writing has run immediately. Functions allow us to group and generalize code to be used arbitrarily many times later. Because they allow us to code an operation in a single place and use it in many places, Python functions are the most basic factoring tool in the language: they allow us to reduce code redundancy in our programs, and thereby reduce maintenance effort.


Procedural decomposition

Functions also provide a tool for splitting systems into pieces that have well-defined roles. For instance, to make a pizza from scratch, you would start by mixing the dough, rolling it out, adding toppings, baking it, and so on. If you were programming a pizza-making robot, functions would help you divide the overall “make pizza” task into chunks—one function for each subtask in the process. It’s easier to implement the smaller tasks in isolation than it is to implement the entire process at once. In general, functions are about procedure—how to do something, rather than what you’re doing it to. We’ll see why this distinction matters in Part VI, when we start making new objects with classes. In this part of the book, we’ll explore the tools used to code functions in Python: function basics, scope rules, and argument passing, along with a few related concepts such as generators and functional tools. Because its importance begins to become more apparent at this level of coding, we’ll also revisit the notion of polymorphism, which was introduced earlier in the book. As you’ll see, functions don’t imply much new syntax, but they do lead us to some bigger programming ideas.

Examples

Fibonacci series has the reccursive relation
$$ F_n = F_{n-1} + F_{n-2} $$ with the seed values $$ F_1 = 1,\; F_2 = 1 $$ or $$ F_0 = 0,\; F_1 = 1 $$


In [44]:
# code that computes Fibonacci series up to n
def fibSeries(n):
    f0, f1 = 0, 1
    while f0 < n:
        print f0,
        f0, f1 = f1, f0 + f1

In [45]:
# evaluate the series up to 100
fib(100)


0 1 1 2 3 5 8 13 21 34 55 89

In [50]:
# code that computes Fibonacci series up to n
def fibSeries(n):
    """compute Fibonacci series up to n"""
    f0, f1 = 0, 1
    while f0 < n:
        print f0,
        f0, f1 = f1, f0 + f1

In [51]:
# what does the function do????
fibSeries.__doc__


Out[51]:
'compute Fibonacci series up to n'

In [55]:
# sometimes we don't want to put the print statement inside the function
# create a function that returns a list
def fibSeries(n):
    """compute Fibonacci series up to n and returns the series as a list"""
    
    series = [] # store numbers here
    f0, f1 = 0, 1 # seed values
    
    while f0 < n:
        series.append(f0)
        f0, f1 = f1, f0 + f1
        
    # return the list
    return series

In [57]:
# now call the function
result = fibSeries(1000)
print result


[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]

In [58]:
# define a function inside a function
def f1():
    x = 99
    print x + 2
    def f2():
        print x + 1
        def f3():
            print x + 3 # Found in f1's local scope!
        f3()
    f2()

In [59]:
# you can only call the top-level function
f1()


101
100
102

In [22]:
def changer(a, b): 
    a = 2 
    b[0] = 'spam'

In [35]:
X = 1
L = [1, 2]
changer(X, L)
X, L


Out[35]:
(1, ['spam', 2])

In [34]:
X = 1
L = [1, 2]
changer(X, L[:])
X, L


Out[34]:
(1, [1, 2])

In [26]:
X = 1
a = X
a = 2
print (X)
print (a)


3
2

In [27]:
L = [1, 2]
b = L
b[0] = 'spam'
print L


['spam', 2]

In [28]:
L[1] = 'jam'
print b


['spam', 'jam']

In [ ]:


In [ ]:

Scope

In [69]:
# x is a global variable
x = 5
def func():
    print x # x has the same value as the global value

func()


5

In [72]:
# x is a global variable
x = 5
def func():
    x = 9 # redefine x here
    print x
    

func()
print x


9
5

In [70]:
# x gets overridden inside the function only
x = 5
def func(x):
    print x

func(10)
print x


10
5

In [12]:
# x is a global variable but gets changed inside a function
x = 5
def func():
    global x
    x = 9 # change here
    print x
    

func()
print x


9
9

In [13]:
def maker(N):
    def action(X):
        return X ** N
    return action

In [14]:
f = maker(2)

In [15]:
f(3)


Out[15]:
9

In [16]:
f(4)


Out[16]:
16

In [17]:
g = maker(3)

In [19]:
g(3)


Out[19]:
27

In [20]:
g(4)


Out[20]:
64

In [21]:
# another way to define it with lambda
def maker2(N):
    return lambda X: X ** N


h = maker2(3)
h(4)


Out[21]:
64
Return values

In [1]:
# return a value from the function
def times(a, b):
    return a * b

print times(10, 2)
print times(3.1415, 4)


20
12.566

In [5]:
# functions are typeless
times('No!', 4)


Out[5]:
'No!No!No!No!'

In [7]:
# complex objects can be passed to the function
def intersect(seq1, seq2):
    res = []                            # Start empty
    
    for x in seq1:                      # Scan seq1
        if x in seq2:                   # Common item?
            res.append(x)               # Add to end
   
    return res


s1 = "SPAM"
s2 = "SCAM"
intersect(s1, s2)


Out[7]:
['S', 'A', 'M']

In [9]:
# this could have been done in an easy and compact way
[x for x in s1 if x in s2]


Out[9]:
['S', 'A', 'M']

In [11]:
# passing on 2 types of objects
x = intersect([1, 2, 3], (1, 4))
print x


[1]
Default Arguments
Packing and Unpacking
Anonymous Functions: lambda

In [64]:
L = [lambda x: x ** 2, # Inline function definition
    lambda x: x ** 3,
    lambda x: x ** 4] # A list of three callable functions


for f in L:
    print(f(2)) # Prints 4, 8, 16


4
8
16

In [65]:
print(L[0](3)) # Prints 9


9

In [66]:
def f1(x): return x ** 2
def f2(x): return x ** 3 # Define named functions
def f3(x): return x ** 4

L = [f1, f2, f3] # Reference by name

for f in L:
    print(f(2)) # Prints 4, 8, 16


4
8
16

In [67]:
print(L[0](3)) # Prints 9


9

In [ ]: