# by default, only the result of the last expression in a cell is displayed after evaluation.
# the following forces display of *all* self-standing expressions in a cell.
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
if
-else
statements¶age=16 # != not equal
if age>=16: # colon starts a block, indent all lines in the block
print("old enough to drive")
print("not old enough to vote")
print("in high school")
old enough to drive not old enough to vote in high school
age=14 # != not equal
if age>=16: # colon starts a block, indent all lines in the block
print("old enough to drive")
print("not old enough to vote")
print("in high school")
in high school
age=15
if age>=16:
print("old enough to drive")
else:
print("NOT old enough to drive")
NOT old enough to drive
from random import randint # import java.util.Random in java the entire Random API
# in python only the randint method in the random module
score = randint(50, 100)
grade = None
if score >= 90:
grade = 'A'
elif score >= 80:
grade = 'B'
elif score >= 70:
grade = 'C'
elif score >= 60:
grade = 'D'
else:
grade = 'E'
print(score, grade)
99 A
from random import randint
score = randint(50, 100)
grade = None
if score >= 90:
grade = 'A'
else:
if score >= 80:
grade = 'B'
else:
if
#modules
import random
random
dir(random)
from random import randint
score = randint(50, 100)
grade = None
if score >= 90:
grade = 'A'
else:
if score >= 80:
grade = 'B'
else:
if
elif score >= 70:
grade = 'C'
elif score >= 60:
grade = 'D'
else:
grade = 'E'
import random
random
dir(random)
<module 'random' from 'C:\\Users\\bauerm\\anaconda3\\lib\\random.py'>
['BPF', 'LOG4', 'NV_MAGICCONST', 'RECIP_BPF', 'Random', 'SG_MAGICCONST', 'SystemRandom', 'TWOPI', '_Sequence', '_Set', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_accumulate', '_acos', '_bisect', '_ceil', '_cos', '_e', '_exp', '_inst', '_log', '_os', '_pi', '_random', '_repeat', '_sha512', '_sin', '_sqrt', '_test', '_test_generator', '_urandom', '_warn', 'betavariate', 'choice', 'choices', 'expovariate', 'gammavariate', 'gauss', 'getrandbits', 'getstate', 'lognormvariate', 'normalvariate', 'paretovariate', 'randint', 'random', 'randrange', 'sample', 'seed', 'setstate', 'shuffle', 'triangular', 'uniform', 'vonmisesvariate', 'weibullvariate']
?random.randint #docstring command
while
loops¶f0 = 0
f1 = 1
while f0 < 100:
print(f0)
f0, f1 = f1, f0+f1
f0
0 1 1 2 3 5 8 13 21 34 55 89
144
i = 0
to_find = 10
while i < 5:
i += 1
if i == to_find:
print('Found; breaking early')
break
else: #only excuted if the while condition fails
# not executed if break out of loop
print('Not found; terminated loop')
Not found; terminated loop
i = 0
to_find = 10
while i < 100:
i += 1
if i == to_find:
print('Found; breaking early')
break #leave iteration block without finishing
else:
print('Not found; terminated loop')
Found; breaking early
# "continue" will skip the rest of ther iteration block and
# go back to the start of the iteration block
while i<100:
if :
continue
# these statements in loop are skipped if the continue was run
#
#
#
raise Exception('Boom!')
--------------------------------------------------------------------------- Exception Traceback (most recent call last) <ipython-input-18-19c2dbb533f1> in <module> ----> 1 raise Exception('Boom!') Exception: Boom!
raise NotImplementedError() # in java used throw
--------------------------------------------------------------------------- NotImplementedError Traceback (most recent call last) <ipython-input-19-03b9be105f74> in <module> ----> 1 raise NotImplementedError() NotImplementedError:
try: # in java try catch
# any code in this block if an exception is raised, go see if there is
# an except statement for that exception
raise Exception('Boom')
#still in the block
except: # catching all exceptions because nospecific one is included
print('Exception encountered!')
Exception encountered!
try:
x = 1/0
except LookupError as e:
print('LookupError:', e)
except ArithmeticError as e: #ArithmeticError is the class of the exception
# e is the actual object
print('ArithmeticError:', e)
except Exception as e:
print(e)
finally: #optional if a finally is included, it is always run
# even if no exception is caught
print('Done')
ArithmeticError: division by zero Done
for
loops (iteration)¶x=range(10)
x[0]
x[3]
0
3
for x in range(10): # for (i=0;i<10;i++)
# range 10 generates the integers 0 through 9
print(x)
0 1 2 3 4 5 6 7 8 9
for i in range(9, 81, 9): # third argument is increment
print(i)
9 18 27 36 45 54 63 72
# you can for loop iterate over any sequence type
for c in 'hello world': # for each/every element in the sequence type
print(c)
h e l l o w o r l d
# non pythonic way # String a = "matt" a.charAt(0)
a="hello world"
for i in range(len(a)):
print(a[i])
h e l l o w o r l d
to_find = 50
for i in range(100):
if i == to_find:
break
else: # does not run becuase we exited the loop by break
print('Completed loop')
iter
and next
)¶# we want to support "for everyElement in ourDataStructure" syntax
# how does python implement walk over a sequence type
r = range(10)
r
it = iter(r) # create an iterator object on the range (sequence type)
# it is pointing to the first element of the sequence type
it
#iterator is used to walkthe sequence using "next" iterator method
range(0, 10)
<range_iterator at 0x222edb26530>
type(it)
range_iterator
next(it) # give me what the iterator is pointing to , and increment it
0
next(it)
1
next(it)
2
next(it)
3
next(it)
next(it)
next(it)
next(it)
next(it)
4
5
6
7
8
next(it)
9
next(it) #iterator raises a StopIteration exception when it reaches
# the end of the sequence type
--------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-36-1e5bd1bf0f8e> in <module> ----> 1 next(it) StopIteration:
r = range(5)
# this is code matching "for i in range(5):"
# print(i)
it = iter(r)
while True:
try:
x = next(it)
print(x)
except StopIteration:
break
0 1 2 3 4
it = iter(r) #r is 0 1 2 3 4
while True:
try:
x = next(it)
y = next(it)
print(x, y, x+y)
except StopIteration:
break
0 1 1 2 3 5
z=range(10)
a=iter(z)
b=iter(z)
next(b)
while True:
try:
print(next(a), next(b))
except StopIteration:
break
0
0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9
def foo():
pass
import math
def quadratic_roots(a, b, c): #ax^2+bx+c
disc = b**2-4*a*c
if disc < 0:
return None
else:
return (-b+math.sqrt(disc))/(2*a), (-b-math.sqrt(disc))/(2*a)
# returning a tuple comma seperated collection
quadratic_roots(1, -5, 6) # eq = (x-3)(x-2)
# arguments are positional a=1 b=-5 c=6
(3.0, 2.0)
quadratic_roots(a=1, b=-5, c=6)
(3.0, 2.0)
quadratic_roots(c=6, a=1, b=-5)
# or arguments can be specified by variable
def create_character(name, race, hitpoints, ability):
print('Name:', name)
print('Race:', race)
print('Hitpoints:', hitpoints)
print('Ability:', ability)
create_character('Legolas', 'Elf', 100, 'Archery')
Name: Legolas Race: Elf Hitpoints: 100 Ability: Archery
# when defining a fucntion you can specify default values for arguments
def create_character(name, race='Human', hitpoints=100, ability=None):
print('Name:', name)
print('Race:', race)
print('Hitpoints:', hitpoints)
if ability:
print('Ability:', ability)
create_character('Michael')
# if funtion is called without all arguments, defaults are used
# still positional
Name: Michael Race: Human Hitpoints: 100
def create_character(name, race='Human', hitpoints=100, abilities=()):
#abilities can be a sequence (tuple)
print('Name:', name)
print('Race:', race)
print('Hitpoints:', hitpoints)
if abilities:
print('Abilities:')
for ability in abilities:
print(' -', ability)
create_character('Gimli', race='Dwarf')
Name: Gimli Race: Dwarf Hitpoints: 100
create_character('Gandalf', hitpoints=1000)
Name: Gandalf Race: Human Hitpoints: 1000
create_character('Aragorn', abilities=('Swording', 'Healing'))
Name: Aragorn Race: Human Hitpoints: 100 Abilities: - Swording - Healing
def create_character(name, *abilities, race='Human', hitpoints=100):
# star syntax means that argument can be multiple arguments long
# variable number
print('Name:', name)
print('Race:', race)
print('Hitpoints:', hitpoints)
if abilities:
print('Abilities:')
for ability in abilities:
print(' -', ability)
create_character('Michael')
Name: Michael Race: Human Hitpoints: 100
create_character('Michael', 'Coding', 'Teaching', 'Sleeping', hitpoints=25 )
# any argument after the variable arguments need to be named
Name: Michael Race: Human Hitpoints: 25 Abilities: - Coding - Teaching - Sleeping
create_character('Michael', 'Coding', 'Teaching', 'Sleeping', 25 )
# any argument after the variable arguments need to be named
Name: Michael Race: Human Hitpoints: 100 Abilities: - Coding - Teaching - Sleeping - 25
def foo():
print('Foo called')
bar = foo # we can give another name to the same function
bar()
Foo called
# i can pass a fucntion as an argument to another function
def foo(f):
f() # call the argumnt function
def bar():
print('Bar called')
foo(bar) # send bar to foo, foo calls it
Bar called
foo = lambda: print('Anonymous function called')
foo()
Anonymous function called
f = lambda x,y: x+y
# f is a function that takes 2 arguments (x and y) adds them and returns value
f(1,2)
3
def my_map(f, it):
for x in it:
print(f(x))
my_map(lambda x: x*2, range(1,10))
2 4 6 8 10 12 14 16 18
my_map(lambda x: x*2, "matt")
mm aa tt tt
for x in map(lambda x: x*2, range(1,10)):
# map takes 2 arguments, a function and and iterable
#applies the function to each element in the iterable
# creates a new iterable with all those values
print(x)
2 4 6 8 10 12 14 16 18
# map filter reduce are three key functional programming exmaples
# filter is get a subset
# reduce reduce(function, iterable[, initializer]) reduce collection to single value
def foo():
print('Foo called')
type(foo)
function
dir(foo)
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
foo()
Foo called
foo.__call__()
Foo called
class Foo:
pass
# no need to declare instance attributes like in Java
# private int age;
# private String name;
Basic Class Example
class Foo:
def __init__(self, newX=1): # constructor
self.x=newX #any identifier in a class that is prefixed by self.
# is an instance attribute
# create them when we need them (usually in constructor)
# x is an instance attribute
print('I got constructed')
# any instance method needs "self" as the first argument
#
def increment(self):
self.x=self.x+1
print(self.x)
z = Foo() # z is self
z.increment()
I got constructed 2
z.increment()
3
class Foo:
def __init__(self, newX=1): # constructor
self.x=newX #any identifier in a class that is prefixed by self.
# is an instance attribute
# create them when we need them (usually in constructor)
# x is an instance attribute
print('I got constructed')
# any instance method needs "self" as the first argument
#
def increment(self):
self.x=self.x+1
print(self.x)
def __repr__(self):
return str(self.x)
def __str__(self): # toString
return "x="+str(self.x)
a=Foo(5)
print(a)
print(a.__repr__())
I got constructed x=5 5
b=Foo(5)
a==b # are they different objects (at different addresses)
I got constructed
False
class Foo:
def __init__(self, newX=1): # constructor
self.x=newX #any identifier in a class that is prefixed by self.
# is an instance attribute
# create them when we need them (usually in constructor)
# x is an instance attribute
print('I got constructed')
# any instance method needs "self" as the first argument
#
def increment(self):
self.x=self.x+1
print(self.x)
def __repr__(self):
return str(self.x)
def __str__(self): # toString
return "x="+str(self.x)
def __eq__(self, that):
return self.x==that.x
a=Foo(5)
b=Foo(5)
a==b
b==a
I got constructed I got constructed
True
True
Inheritance Example
class Shape:
def __init__(self, name):
self.name = name
def __repr__(self):
return self.name
def __str__(self):
return self.name.upper()
def area(self):
raise NotImplementedError()
s = Shape('circle')
s
circle
str(s)
'CIRCLE'
s.area()
--------------------------------------------------------------------------- NotImplementedError Traceback (most recent call last) <ipython-input-24-88799e7f1f86> in <module> ----> 1 s.area() <ipython-input-20-24ae96e78afe> in area(self) 10 11 def area(self): ---> 12 raise NotImplementedError() NotImplementedError:
class Circle(Shape): # Circle inherits from Shape
# Circle IS A Shape
def __init__(self, radius):
super().__init__('circle') # Call Shape's constructor
self.radius = radius # additional instance attrbute for every Circle object
def area(self):
return 3.14 * self.radius ** 2
c = Circle(5.0)
c # call the repr
c.area()
circle
78.5
class Circle(Shape):
def __init__(self, radius):
super().__init__('circle')
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
def __eq__(self, that):
return self.radius==that.radius
c1 = Circle(2.0)
c2 = Circle(4.0)
c3 = Circle(2.0)
c1==c2
c1==c3
False
True
s1=Shape('circle')
s1==c1
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-29-eb412bda5677> in <module> 1 s1=Shape('circle') ----> 2 s1==c1 <ipython-input-27-8be1ac7cfcfc> in __eq__(self, that) 8 9 def __eq__(self, that): ---> 10 return self.radius==that.radius AttributeError: 'Shape' object has no attribute 'radius'
class Circle(Shape):
def __init__(self, radius):
super().__init__('circle')
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
def __eq__(self, that):
if isinstance(that,Circle) and self.radius==that.radius:
return True
else:
return False
c1 = Circle(2.0)
s1=Shape('circle')
s1==c1
False
class Circle(Shape):
def __init__(self, radius):
super().__init__('circle')
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
def __eq__(self, that):
if isinstance(that,Circle) and self.radius==that.radius:
return True
else:
return False
def __add__(self, that): #implement the + operator for Circle objects
if isinstance(that,Circle):
return Circle(self.radius+that.radius)
else:
return None
c1 = Circle(2.0)
c2 = Circle(4.0)
c3 = Circle(2.0)
c1.area()
s1=Shape('foo')
c1, c2, c3
c1 == c2
c1 == c3
print((c1 + c2).area())
print(c1+s1)
12.56
(circle, circle, circle)
False
True
113.04 None
class Circle(Shape):
def __init__(self, radius):
super().__init__('circle')
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
def __eq__(self, that):
if isinstance(that,Circle) and self.radius==that.radius:
return True
else:
return False
def __add__(self, that): #implement the + operator for Circle objects
if isinstance(that,Circle):
return Circle(self.radius+that.radius)
else:
return None
@staticmethod
def anything():
print("class method")
c1 = Circle(10)
s1 = Shape('foo')
c1.area()
s1
Circle.anything()
314.0
foo
class method
Recall: All immutable sequences support the common sequence operations. For many sequence types, there are constructors that allow us to create them from other sequence types.
a='hello'
# 01234
a[4]
a[0]
'o'
'h'
a[0]='y'
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-42-456d321e84c3> in <module> ----> 1 a[0]='y' TypeError: 'str' object does not support item assignment
range(10) # 0 through 9
range(0, 10)
print(range(10, 20))
for i in range(10, 20):
print(i)
range(10, 20) 10 11 12 13 14 15 16 17 18 19
b=range(20, 50, 5)
b[0] #20 25 30 35 40 45
b[5]
20
45
range(10, 0, -1)
()
()
z=(1, 2, 3)
#0 1 2
z
z[1]
z[2]=5
(1, 2, 3)
2
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-49-fe82f8f70d96> in <module> 3 z 4 z[1] ----> 5 z[2]=5 TypeError: 'tuple' object does not support item assignment
('a', 10, False, 'hello')
('a', 10, False, 'hello')
tuple(range(10))
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
tuple('hello')
('h', 'e', 'l', 'l', 'o')
str(range(10))
'range(0, 10)'
a=str(('a', 4, False))
a[0]
a[1]
'('
"'"