Note: this is not a language course! Though I'll cover the important bits of the language (and standard library) that are relevant to class material, I expect you to master the language on your own time.
Python ...
# integers
a = 2
b = 5
c = a + b
d = a * b + 2
e = b // a # integer div
f = b % a # modulus, remainder
g = a ** b # exponentiation (power)
print(c, d, e, f, g)
type(2)
type(a)
int()
int(1)
int('25')
dir(1)
(2).__add__(4)
2 + 4
abs(-20)
(-20).__abs__()
1 + 2
(1).__add__(2)
a, b
a + b
a.__add__(b)
a, b
class MyInt(int):
def __add__(self, b):
return self * b
m = MyInt(10)
m
m + 5
f = 5.0
type(f)
dir(f)
# strings (`str`)
name = 'John' + " " + 'Doe'
Strings are an example of a sequence type; https://docs.python.org/3.5/library/stdtypes.html#typesseq
Other sequence types are: ranges, tuples (both also immutable), and lists (mutable).
All immutable sequences support the common sequence operations, and mutable sequences additionally support the mutable sequence operations
name
"Michael's cat"
len(name)
name[0]
name[1]
name[len(name)]
name[-1]
name[-2]
name[-8]
name[100]
name[-100]
"Slice" syntax: [A:B:C]
name[0:]
name[1:]
name[5:]
name[1:4]
name[1:-1]
name[1:-1:1]
name[1:-1:2]
name
name[::2]
name[-1:0:-1]
'J' in name
name.__contains__('J')
'z' not in name
dir(name)
name.__contains__('J')
min(name)
max(name)
name.index('o')
name.index('o', 2)
name.count('o')
name * 10
name
it = iter(name)
next(it)
it = iter(name)
while True:
try:
print(next(it))
except StopIteration:
break
for c in name:
print(c)
# ranges
r1 = range(10)
r2 = range(10, 20)
r3 = range(100, 5, -10)
for i in range(10, 0, -1):
print(i)
5 in range(10)
range(1) + range(3)
range(100000000)
tup = ('lions', 'tigers', 'bears', (0, 1, 2), True, False)
len(tup)
len(tup[3])
tup[3][0]
5+(5)
5 + (5,)
5, 6, 7
a, b = 1, 2
a, b
a, (b1, b2), c = 1, (4, 5), "hello" # destructuring assignment
a, b1, b2, c
a, *rest = 1, 2, 3, 4, 5, 6
a
rest
a, *rest = 1, 2
a, rest
a, *rest = 1
tup = ("hello", "world", 1, 2, 3)
tup[1]
tup[1] = "planet"
'hello'[1] = 'a'
Tuples and Strings are immutable data containers
s1 = 'hello'
s2 = 'world'
s1 + ' some ' + s2
l = []
len(l)
100 in l
l[0]
l.append(100)
l
for i in range(10):
l.append(i)
l
l = list(range(10))
l
type(l)
dir(list)
l
l = ["apples", "bananas", "pears", "lions", "tigers", "bears"]
l[1:2] = 100
l
l[1:3] = [1, 2, 3, 4, 5]
l
l = ["apples", "bananas", "pears", "lions", "tigers", "bears"]
del l[0]
l
del l[3]
l
l.remove('pears')
l
l.remove('whale')
l = []
for n in range(1, 11):
l.append(2*n)
l
[2*x for x in range(1, 11)]
[2**x for x in range(10)]
n = 10
l = []
for a in range(1, n+1):
for b in range(1, n+1):
for c in range(1, n+1):
if a**2 + b**2 == c**2:
l.append((a, b, c))
l
l =[(a, b, c) for a in range(1, n+1)
for b in range(1, n+1)
for c in range(1, n+1)
if a**2 + b**2 == c**2]
l
l = [(x, y) for x in range(1,4) for y in range(100,103)]
l[0] = "hello"
l
l = [[]] * 5
l
l[0].append("hello")
l
l = [[], [], [], [], []]
l[0].append("hello")
l
l = [[] for x in range(10)]
l
l[0].append('hello')
l
from random import random
[random()] * 10
[random() for _ in range(10)]
l
for x in l:
print(x)
for a, b, c in l:
print(a, b, c)
Iteration is based on two functions: iter
and next
l
it = iter(l)
next(it)
l1 = [1, 2, 3, 4]
l2 = ["hello", "world"]
l1 + l2
l3 = l1 + l2
l3
l1, l2
l1.extend(l2)
l1
l2
ll = [list(range(10)) for _ in range(10)]
ll
ll[4][4] = 100
ll
d = dict()
d
d = {}
d
d[0] = 'one'
d
d[0]
d[2] = 'two'
d
d['name'] = 'Michael'
d['color'] = 'Blue'
d
d[0] = 'zero'
d
del d[2]
d
list(d.keys())
list(d.values())
list(d.items())
for k in d.keys():
print(k)
for k in d:
print(k)
for k, v in d.items():
print(k, '=>', v)
d
d[100]
0 in d
100 in d
import urllib.request
peter_pan_text = urllib.request.urlopen('https://www.gutenberg.org/files/16/16-0.txt').read().decode()
peter_pan_text[:100]
peter_pan_words = peter_pan_text.split()
peter_pan_words[1000:1025]
peter_pan_words.count('Peter')
peter_pan_words.count('Tink')
peter_pan_words.index('Hook')
peter_pan_word_count = {}
for w in peter_pan_words:
if w in peter_pan_word_count:
peter_pan_word_count[w] += 1
else:
peter_pan_word_count[w] = 1
peter_pan_word_count['the']
peter_pan_word_count['The']
peter_pan_word_count
def foo():
pass
foo()
foo(1)
def say_hi(name):
print('hello', name)
'hello {}'.format('Michael')
s = 'hel{}lo{}'
s.format('Michael', 'Jane')
def say_hi(name):
print('hello {}'.format(name))
say_hi('Michael')
def say_hi(n1, n2):
print('hello', n1, 'and', n2)
say_hi('Michael', 'Jane')
say_hi(n1='Michael', n2='Jane')
say_hi(n2='Michael', n1='Jane')
args = {'n1': 'Michael', 'n2': 'Jane'}
say_hi(**args) # '**' unpacks args from dictionary
def say_hi(names):
for n in names:
print('hello', n)
say_hi(['Michael', 'Jane', 'Tarzan'])
say_hi('Michael', 'Jane', 'Tarzan')
def say_hi(*names):
for n in names:
print('hello', n)
say_hi('Michael', 'Jane', 'Tarzan')
say_hi('Jane', 'Tarzan')
say_hi()
say_hi
type(say_hi)
dir(say_hi)
say_hi()
say_hi.__call__()
say_hi.__call__('Michael', 'Jane')
f = say_hi
f('Joe')
We refer to functions that can be passed around and stored as "first class functions"
sorted(['i', 'like', 'cakes'])
?sorted
sorted(['i', 'like', 'cakes'], reverse=True)
sorted(['i', 'like', 'cakes'], key=len, reverse=True)
coords = [(0, 0), (-5, 0), (1, -100), (2, 2), (50, 50)]
sorted(coords)
import math
def dist(coord):
return math.sqrt(coord[0]**2 + coord[1]**2)
dist((1, 0))
dist((1, 1))
sorted(coords, key=dist)
sorted(coords, key=dist, reverse=True)
def sum_of_x_and_y(coord):
return coord[0] + coord[1]
sorted(coords, key=sum_of_x_and_y)
f = lambda x: x+1
f(10)
(lambda x: x+1)(10)
(lambda x, y: x+y)(2, 5)
sorted(coords, key=lambda c: c[0]+c[1])
coords
dist((1, 0))
distances = [] # NOT PYTHONIC!
for c in coords:
distances.append(dist(c))
distances
[dist(c) for c in coords]
def mymap(f, lst): # higher order function (HOF) — it takes a function as an argument
return [f(x) for x in lst]
mymap(dist, coords)
list(map(dist, coords))
sorted(peter_pan_word_count.items(), key=lambda t: t[1], reverse=True)
list(filter(lambda wc: wc[0][0].isupper(),
sorted(peter_pan_word_count.items(), key=lambda t: t[1], reverse=True)))
f = lambda x: x + 1
f(10)
def foo(x):
x += 1
return (lambda y : y + x) # "closure": "closes over" all variables it uses --- keeps them around
f = foo(10)
f(20)
f(30)
g = foo(100)
g(10)
f(10)
def foo(a):
return a + 10
foo(100)
foo()
def foo(a=-10):
return a + 10
foo()
foo(100)
def foo(l="hello"):
return l
foo()
s = foo()
s
s = 'goodbye'
foo()
class Foo:
pass
Foo()
f = Foo()
f.attrib
f.attrib = 10
f.attrib
f.x = f.y = f.z = 100
f.x, f.y, f.z
dir(f)
dir(Foo())
Foo.w = 100
Foo
f.w
f.w = 150
f.w
Foo.w
Foo.w = 170
f.w
class Foo:
def bar():
pass
f = Foo()
f.bar()
Foo.bar()
class Foo:
def bar(x):
print(x)
f = Foo()
f.bar()
f
Foo.bar()
Foo.bar(f) # equiv to f.bar()
class Foo:
def bar(self):
try:
self.x += 1
except AttributeError:
self.x = 1
return self.x
f = Foo()
f.bar()
class Shape:
def __init__(self):
print('I got constructed')
Shape()
class Shape:
def __init__(self, name):
self.name = name
s = Shape('Circle')
s.name
s
class Shape:
def __init__(self, name):
self.name = name
def __repr__(self):
return self.name
def __str__(self):
return self.name.upper()
Shape('Circle')
str(Shape('Circle'))
print(Shape('Circle'))
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()
Shape('Circle').area()
class Circle(Shape):
def __init__(self, radius):
super().__init__('Circle')
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
c = Circle(10)
c.name
c.area()
Circle(10.0) == Circle(10.0)
id(Circle(10.0))
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, other):
return isinstance(other, Circle) and self.radius == other.radius
def __add__(self, other):
return Circle(self.radius + other.radius)
def __repr__(self):
return 'Circle(r={})'.format(self.radius)
@staticmethod
def whatever():
print('hello from a static circle method')
Circle.whatever()
c = Circle(10.0)
c.whatever()
Circle(10.0)
Circle(10) == Circle(10)
Circle(10).__eq__(Circle(10))
Circle(5) + Circle(10)
Circle(10) == Shape(5)
cs = [Circle(r) for r in range(1,10)]
cs
[c.area() for c in cs]
if __name__ == '__main__':
print('hi!')
dir()
import random
random
dir(random)
?random.random
random.random()
?random.randrange
random.randrange(1, 100)
from random import random, randrange
random()
randrange(10, 200)
import random as r
r.random()