0% found this document useful (0 votes)
42 views47 pages

Python List Comprehensions & Functions

The document covers concepts related to list comprehensions, functions as objects, and testing/debugging in Python. It explains how to create new lists using list comprehensions, the importance of default parameters in functions, and the process of testing and debugging code effectively. Additionally, it emphasizes defensive programming practices and different classes of tests such as unit testing and regression testing.

Uploaded by

Dalya Al-Delaimy
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
42 views47 pages

Python List Comprehensions & Functions

The document covers concepts related to list comprehensions, functions as objects, and testing/debugging in Python. It explains how to create new lists using list comprehensions, the importance of default parameters in functions, and the process of testing and debugging code effectively. Additionally, it emphasizes defensive programming practices and different classes of tests such as unit testing and regression testing.

Uploaded by

Dalya Al-Delaimy
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

LIST COMPREHENSION,

FUNCTIONS AS OBJECTS,
TESTING, DEBUGGING
(download slides and .py files to follow along)
6.100L Lecture 12
Ana Bell

1
LIST COMPREHENSIONS

6.100L Lecture 12
LIST COMPREHENSIONS

 Applying a function to every element of a sequence, then


creating a new list with these values is a common concept
 Example:
def f(L):
Lnew = []
for e in L:
[Link](e**2)
return Lnew
 Python provides a concise one-liner way to do this, called a list
comprehension
 Creates a new list
 Applies a function to every element of another iterable
 Optional, only apply to elements that satisfy a test

[expression for elem in iterable if test]


3

6.100L Lecture 12
LIST COMPREHENSIONS

 Create a new list, by applying a function to every element of


another iterable that satisfies a test

def f(L):
Lnew = []
for e in L: Lnew = [e**2 for e in L]
[Link](e**2)
return Lnew

6.100L Lecture 12
LIST COMPREHENSIONS

 Create a new list, by applying a function to every element of


another iterable that satisfies a test

def f(L):
Lnew = []
for e in L: Lnew = [e**2 for e in L]
[Link](e**2)
return Lnew

def f(L):
Lnew = []
for e in L:
if e%2==0:
[Link](e**2)
return Lnew
5

6.100L Lecture 12
LIST COMPREHENSIONS

 Create a new list, by applying a function to every element of


another iterable that satisfies a test

def f(L):
Lnew = []
for e in L: Lnew = [e**2 for e in L]
[Link](e**2)
return Lnew

def f(L):
Lnew = []
for e in L:
if e%2==0:
[Link](e**2) Lnew = [e**2 for e in L if e%2==0]
return Lnew
6

6.100L Lecture 12
LIST COMPREHENSIONS

 Create a new list, by applying a function to every element of


another iterable that satisfies a test

def f(L):
Lnew = []
for e in L: Lnew = [e**2 for e in L]
[Link](e**2)
return Lnew

def f(L):
Lnew = []
for e in L:
if e%2==0:
[Link](e**2) Lnew = [e**2 for e in L if e%2==0]
return Lnew
7

6.100L Lecture 12
LIST COMPREHENSIONS

 Create a new list, by applying a function to every element of


another iterable that satisfies a test

def f(L):
Lnew = []
for e in L: Lnew = [e**2 for e in L]
[Link](e**2)
return Lnew

def f(L):
Lnew = []
for e in L:
if e%2==0:
[Link](e**2) Lnew = [e**2 for e in L if e%2==0]
return Lnew
8

6.100L Lecture 12
LIST COMPREHENSIONS

[expression for elem in iterable if test]


 This is equivalent to invoking this function (where expression is
a function that computes that expression)
def f(expr, old_list, test = lambda x: True):
new_list = []
for e in old_list:
if test(e):
new_list.append(expr(e))
return new_list

[e**2 for e in range(6)]  [0, 1, 4, 9, 16, 25]


[e**2 for e in range(8) if e%2 == 0]  [0, 4, 16, 36]
[[e,e**2] for e in range(4) if e%2 != 0]  [[1,1], [3,9]]
9

6.100L Lecture 12
YOU TRY IT!
 What is the value returned by this expression?
 Step1: what are all values in the sequence
 Step2: which subset of values does the condition filter out?
 Step3: apply the function to those values

[len(x) for x in ['xy', 'abcd', 7, '4.0'] if type(x) == str]

10

6.100L Lecture 12
FUNCTIONS: DEFAULT
PARAMETERS

11

6.100L Lecture 12
SQUARE ROOT with BISECTION

def bisection_root(x):
epsilon = 0.01
low = 0
high = x
guess = (high + low)/2.0
while abs(guess**2 - x) >= epsilon:
if guess**2 < x:
low = guess
else:
high = guess
guess = (high + low)/2.0
return guess

print(bisection_root(123))
12

6.100L Lecture 12
ANOTHER PARAMETER

 Motivation: want a more accurate answer


def bisection_root(x)can be improved
 Options?
 Change epsilon inside function (all function calls are affected)
 Use an epsilon outside function (global variables are bad)
 Add epsilon as an argument to the function

13

6.100L Lecture 12
epsilon as a PARAMETER

def bisection_root(x, epsilon):


low = 0
high = x
guess = (high + low)/2.0
while abs(guess**2 - x) >= epsilon:
if guess**2 < x:
low = guess
else:
high = guess
guess = (high + low)/2.0
return guess

print(bisection_root(123, 0.01))
14

6.100L Lecture 12
KEYWORD PARAMETERS &
DEFAULT VALUES
def bisection_root(x, epsilon)can be improved
 We added epsilon as an argument to the function
 Most of the time we want some standard value, 0.01
 Sometimes, we may want to use some other value
 Use a keyword parameter aka a default parameter

15

6.100L Lecture 12
Epsilon as a KEYWORD
PARAMETER
def bisection_root(x, epsilon=0.01):
low = 0
high = x
guess = (high + low)/2.0
while abs(guess**2 - x) >= epsilon:
if guess**2 < x:
low = guess
else:
high = guess
guess = (high + low)/2.0
return guess

print(bisection_root(123))
print(bisection_root(123, 0.5))
16

6.100L Lecture 12
RULES for KEYWORD PARAMETERS

 In the function definition:


 Default parameters must go at the end

 These are ok for calling a function:


 bisection_root_new(123)
 bisection_root_new(123, 0.001)
 bisection_root_new(123, epsilon=0.001)
 bisection_root_new(x=123, epsilon=0.1)
 bisection_root_new(epsilon=0.1, x=123)

 These are not ok for calling a function:


 bisection_root_new(epsilon=0.001, 123) #error
 bisection_root_new(0.001, 123) #no error but wrong

17

6.100L Lecture 12
FUNCTIONS RETURNING
FUNCTIONS

18

6.100L Lecture 12
OBJECTS IN A PROGRAM
function
my_func object
named
is_even is_even

def is_even(i): r int object 2


return i%2 == 0
float object
pi
r = 2 3.14285714

pi = 22/7
a False
my_func = is_even
b True
a = is_even(3)

b = my_func(4)

19

6.100L Lecture 12
FUNCTIONS CAN RETURN
FUNCTIONS
def make_prod(a):
def g(b):
return a*b
return g

val = make_prod(2)(3) doubler = make_prod(2)


print(val) val = doubler(3)
print(val)

20

6.100L Lecture 12
SCOPE DETAILS FOR WAY 1

def make_prod(a):
def g(b):
return a*b
return g

val = make_prod(2)(3)
print(val)

21

6.100L Lecture 12
SCOPE DETAILS FOR WAY 1

def make_prod(a): Global scope


def g(b):
make_prod Some
return a*b
code
return g

val = make_prod(2)(3)
print(val)

22

6.100L Lecture 12
SCOPE DETAILS FOR WAY 1 NOTE: definition
of g is done
within scope of
make_prod, so
binding of g is
def make_prod(a): Global scope make_prod within that
scope frame/scope
def g(b):
make_prod Some Since g is bound
return a*b a 2 in this frame,
code
cannot access it
return g by evaluation in
Some global frame
g
code g can only be
val = make_prod(2)(3) accessed within
call to
print(val) make_prod, and
each call will
create a new,
internal g

23

6.100L Lecture 12
SCOPE DETAILS FOR WAY 1

def make_prod(a): Global scope make_prod


scope
def g(b):
make_prod Some
return a*b a 2
code
return g
g’s g Some
code! code
val = make_prod(2)(3)
print(val)

Evaluating make_prod(2) has


Returns pointer
returned an anonymous procedure
24
to g code
6.100L Lecture 12
SCOPE DETAILS FOR WAY 1

def make_prod(a): Global scope make_prod g scope


scope
def g(b):
make_prod Some b
return a*b a 2 3
code
return g
g’s g Some
code! code
val = make_prod(2)(3)
print(val)

25

6.100L Lecture 12
SCOPE DETAILS FOR WAY 1

def make_prod(a): Global scope make_prod g scope


scope
def g(b):
make_prod Some b
return a*b a 2 3
code
return g
g’s g Some
code! code 6
val = make_prod(2)(3)
print(val)
val 6
Internal procedure only
accessible within scope from
parent procedure’s call

How does g get value for a?


Interpreter can move up hierarchy
26
of frames to see both b and a values
6.100L Lecture 12
SCOPE DETAILS FOR WAY 2

def make_prod(a):
def g(b):
return a*b
return g

doubler = make_prod(2)
val = doubler(3)
print(val)

27

6.100L Lecture 12
SCOPE DETAILS FOR WAY 2

def make_prod(a): Global scope make_prod


scope
def g(b):
make_prod Some
return a*b a 2
code
return g

doubler g’s g Some


doubler = make_prod(2) code! code
val = doubler(3)
print(val)

28

6.100L Lecture 12
SCOPE DETAILS FOR WAY 2

def make_prod(a): Global scope make_prod


scope
def g(b):
make_prod Some
return a*b a 2
code
return g

doubler g’s g Some


doubler = make_prod(2) code! code
val = doubler(3)
print(val)

29

6.100L Lecture 12
SCOPE DETAILS FOR WAY 2

def make_prod(a): Global scope make_prod doubler scope


scope
def g(b):
make_prod Some
return a*b a 2 b 3
code
return g
doubler g’s g Some
code! code 6
doubler = make_prod(2)
val = doubler(3)
print(val) val 6

Returns value
30

6.100L Lecture 12
WHY BOTHER RETURNING
FUNCTIONS?
 Code can be rewritten without returning function objects
 Good software design
 Embracing ideas of decomposition, abstraction
 Another tool to structure code
 Interrupting execution
 Example of control flow
 A way to achieve partial execution and use result somewhere else
before finishing the full evaluation

31

6.100L Lecture 12
TESTING and
DEBUGGING

32

6.100L Lecture 12
DEFENSIVE PROGRAMMING
• Write specifications for functions
• Modularize programs
• Check conditions on inputs/outputs (assertions)

TESTING/VALIDATION DEBUGGING
• Compare input/output • Study events leading up
pairs to specification to an error
• “It’s not working!” • “Why is it not working?”
• “How can I break my • “How can I fix my
program?” program?”

33

6.100L Lecture 12
SET YOURSELF UP FOR EASY
TESTING AND DEBUGGING

 From the start, design code to ease this part


 Break program up into modules that can be tested and
debugged individually
 Document constraints on modules
• What do you expect the input to be?
• What do you expect the output to be?
 Document assumptions behind code design

34

6.100L Lecture 12
WHEN ARE YOU READY TO TEST?

 Ensure code runs


• Remove syntax errors
• Remove static semantic errors
• Python interpreter can usually find these for you
 Have a set of expected results
• An input set
• For each input, the expected output

35

6.100L Lecture 12
CLASSES OF TESTS

 Unit testing
• Validate each piece of program
• Testing each function separately
 Regression testing
• Add test for bugs as you find them
• Catch reintroduced errors that were previously
fixed
 Integration testing
• Does overall program work?
• Tend to rush to do this
36

6.100L Lecture 12
TESTING APPROACHES

 Intuition about natural boundaries to the problem


def is_bigger(x, y):
""" Assumes x and y are ints
Returns True if y is less than x, else False """
• can you come up with some natural partitions?
 If no natural partitions, might do random testing
• Probability that code is correct increases with more tests
• Better options below
 Black box testing
• Explore paths through specification
 Glass box testing
• Explore paths through code
37

6.100L Lecture 12
BLACK BOX TESTING

def sqrt(x, eps):


""" Assumes x, eps floats, x >= 0, eps > 0
Returns res such that x-eps <= res*res <= x+eps """

 Designed without looking at the code


 Can be done by someone other than the implementer to
avoid some implementer biases
 Testing can be reused if implementation changes
 Paths through specification
• Build test cases in different natural space partitions
• Also consider boundary conditions (empty lists, singleton list, large
numbers, small numbers)

38

6.100L Lecture 12
BLACK BOX TESTING

def sqrt(x, eps):


""" Assumes x, eps floats, x >= 0, eps > 0
Returns res such that x-eps <= res*res <= x+eps """

CASE x eps
boundary 0 0.0001
perfect square 25 0.0001
less than 1 0.05 0.0001
irrational square root 2 0.0001
extremes 2 1.0/2.0**64.0
extremes 1.0/2.0**64.0 1.0/2.0**64.0
extremes 2.0**64.0 1.0/2.0**64.0
extremes 1.0/2.0**64.0 2.0**64.0
extremes 2.0**64.0 39 2.0**64.0
6.100L Lecture 12
GLASS BOX TESTING

 Use code directly to guide design of test cases


 Called path-complete if every potential path through
code is tested at least once
 What are some drawbacks of this type of testing?
• Can go through loops arbitrarily many times
• Missing paths
 Guidelines
• Branches
• For loops
• While loops

40

6.100L Lecture 12
GLASS BOX TESTING

def abs(x):
""" Assumes x is an int
Returns x if x>=0 and –x otherwise """
if x < -1:
return –x
else:
return x
 Aa path-complete test suite could miss a bug
 Path-complete test suite: 2 and -2
 But abs(-1) incorrectly returns -1
 Should still test boundary cases

41

6.100L Lecture 12
DEBUGGING

 Once you have discovered that your code does not run
properly, you want to:
 Isolate the bug(s)
 Eradicate the bug(s)
 Retest until code runs correctly for all cases
 Steep learning curve
 Goal is to have a bug-free program
 Tools
• Built in to IDLE and Anaconda
• Python Tutor
• print statement
• Use your brain, be systematic in your hunt
42

6.100L Lecture 12
ERROR MESSAGES – EASY

 Trying to access beyond the limits of a list


test = [1,2,3] then test[4]  IndexError
 Trying to convert an inappropriate type
int(test)  TypeError
 Referencing a non-existent variable
a  NameError
 Mixing data types without appropriate coercion
'3'/4  TypeError
 Forgetting to close parenthesis, quotation, etc.
a = len([1,2,3]
print(a)  SyntaxError
43

6.100L Lecture 12
LOGIC ERRORS - HARD

 think before writing new code


 draw pictures, take a break
 explain the code to
• someone else
• a rubber ducky

44

6.100L Lecture 12
DEBUGGING STEPS

 Study program code


• Don’t ask what is wrong
• Ask how did I get the unexpected result
• Is it part of a family?
 Scientific method
• Study available data
• Form hypothesis
• Repeatable experiments
• Pick simplest input to test with

45

6.100L Lecture 12
PRINT STATEMENTS

 Good way to test hypothesis


 When to print
• Enter function
• Parameters
• Function results
 Use bisection method
• Put print halfway in code
• Decide where bug may be depending on values

46

6.100L Lecture 12
MITOpenCourseWare
[Link]

6.100L Introduction to Computer Science and Programming Using Python


Fall 2022

For information about citing these materials or our Terms ofUse,visit: [Link]

47

You might also like