Python

CS314

Review

Previously

  • OCaml, Prolog.

This lecture

  • A Crash Course in Python

Int Expression

In [1]:
2
Out[1]:
2
In [2]:
2 + 4
Out[2]:
6
In [3]:
(2+5) * (3-5)
Out[3]:
-14

Float Expression

In [4]:
2.7 + 4.5
Out[4]:
7.2
In [5]:
(2 + 3.5) * (2.7 -4)
Out[5]:
-7.149999999999999
In [6]:
0.1 + 0.11
Out[6]:
0.21000000000000002
In [7]:
2 + 3.5
Out[7]:
5.5

What's different from OCaml?

  • Type coersion! Python does type conversion on its own.

  • OCaml would have simply rejected (2 + 3.5).

  • Its the same + for ints and floats and as we'll see, a lot of other things.

    • It's just the same "+" message name, and the objects take care of doing the right thing.
    • In python, its actually exploiting the fact that everything is an object...

What about this?

In [8]:
2 + 3j
Out[8]:
(2+3j)
In [9]:
-5.2 + 6j
Out[9]:
(-5.2+6j)
In [10]:
(2 + 3j) * (-5.2 + 6j)
Out[10]:
(-28.4-3.6000000000000014j)

String Expressions:

In [11]:
"this "
Out[11]:
'this '
In [12]:
"this is " + "cool"
Out[12]:
'this is cool'
In [13]:
"this is w" + "a"*10 + "y cool"
Out[13]:
'this is waaaaaaaaaay cool'
In [14]:
"this is so cool you'll fall off your seat"
Out[14]:
"this is so cool you'll fall off your seat"

Say I want the string: Tom says: "this is way cool"

In [15]:
'Tom says: "this is way cool"'
Out[15]:
'Tom says: "this is way cool"'

conversion functions...

In [16]:
str(50)
Out[16]:
'50'
In [17]:
str(92.7)
Out[17]:
'92.7'
In [18]:
str("cool stuff, dude!")
Out[18]:
'cool stuff, dude!'
In [19]:
int("22")
Out[19]:
22
In [20]:
int("abc")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-20-2dda1cc00c48> in <module>()
----> 1 int("abc")

ValueError: invalid literal for int() with base 10: 'abc'
In [21]:
int(3.9)
Out[21]:
3
In [22]:
float(22)
Out[22]:
22.0
In [23]:
float("3.14")
Out[23]:
3.14
  • These are special built-in functions that do the conversion.
  • Dynamic typing: the float function can take anything as a parameter.
    • The correct "method" is determined dynamically.

assignment statements

In [24]:
x = 3
In [25]:
y = x + 4
In [26]:
y
Out[26]:
7
In [27]:
s = "so "
In [28]:
t = "Python is " + s * y + "much fun" + "!" * x
In [29]:
t
Out[29]:
'Python is so so so so so so so much fun!!!'

Sequence

  • It turns out that strings are a "Sequence" Types. Such types have many cool properties, the first of which is that they have lengths:
In [30]:
s
Out[30]:
'so '
In [31]:
len(s)
Out[31]:
3
In [32]:
t
Out[32]:
'Python is so so so so so so so much fun!!!'
In [33]:
len(t)
Out[33]:
42
  • We can access the i'th element of a sequence...
In [34]:
s
Out[34]:
'so '
In [35]:
s[0]
Out[35]:
's'
In [36]:
s[1]
Out[36]:
'o'
In [37]:
t
Out[37]:
'Python is so so so so so so so much fun!!!'
In [38]:
t[7]
Out[38]:
'i'
  • slicing: s[i:j] is the (sub)sequence of characters from position i through j-1.
In [39]:
t
Out[39]:
'Python is so so so so so so so much fun!!!'
In [40]:
t[0:3]
Out[40]:
'Pyt'
In [41]:
t[3:6]
Out[41]:
'hon'
In [42]:
t[3:] 
Out[42]:
'hon is so so so so so so so much fun!!!'
In [43]:
t[:4] 
Out[43]:
'Pyth'
  • What about t[100]? What about t[-1]
In [44]:
t
Out[44]:
'Python is so so so so so so so much fun!!!'
In [45]:
t[100]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-45-717657040d75> in <module>()
----> 1 t[100]

IndexError: string index out of range
In [46]:
t[-1]
Out[46]:
'!'
  • forall t. t[:i] + t[i:] is always equal to t
In [47]:
t
Out[47]:
'Python is so so so so so so so much fun!!!'
In [48]:
t[:2] + t[2:]
Out[48]:
'Python is so so so so so so so much fun!!!'
In [49]:
t[:6] + t[6:]
Out[49]:
'Python is so so so so so so so much fun!!!'
In [50]:
t[:-1] + t[-1:]
Out[50]:
'Python is so so so so so so so much fun!!!'

Tuples

In [51]:
t1 = (3,5)
In [52]:
t2 = ("abc",2.9,99)
In [53]:
t3 = (t1,t2)
In [54]:
t3
Out[54]:
((3, 5), ('abc', 2.9, 99))

What do you think this will do?

In [55]:
(1,2) + (3, 4)
Out[55]:
(1, 2, 3, 4)

What about this?

In [56]:
t4 = ("abc",10) * 4
In [57]:
t4
Out[57]:
('abc', 10, 'abc', 10, 'abc', 10, 'abc', 10)

Tuples are also sequences

In [58]:
t1
Out[58]:
(3, 5)
In [59]:
len(t1)
Out[59]:
2
In [60]:
t3
Out[60]:
((3, 5), ('abc', 2.9, 99))
In [61]:
len(t3)
Out[61]:
2
In [62]:
t4
Out[62]:
('abc', 10, 'abc', 10, 'abc', 10, 'abc', 10)
In [63]:
len(t4)
Out[63]:
8

Can select:

In [64]:
t1
Out[64]:
(3, 5)
In [65]:
t1[0]
Out[65]:
3
In [66]:
t2
Out[66]:
('abc', 2.9, 99)
In [67]:
t2[2]
Out[67]:
99
In [68]:
t2[1:2]
Out[68]:
(2.9,)
In [69]:
t2[1:]
Out[69]:
(2.9, 99)

What other type do you think is a sequence?

Another sequence type: Lists!

In [70]:
l1 = [9,1,1]
  • no resriction on types! "heterogeneous lists"
In [71]:
l2 = [1, "a", 3.0, ["moo", "stew", "bamboo", "woohoo"]]
In [72]:
len(l1)
Out[72]:
3
In [73]:
len(l2)
Out[73]:
4
In [74]:
l1
Out[74]:
[9, 1, 1]
In [75]:
l1[0]
Out[75]:
9
In [76]:
l2
Out[76]:
[1, 'a', 3.0, ['moo', 'stew', 'bamboo', 'woohoo']]
In [77]:
l2[1]
Out[77]:
'a'
In [78]:
l2[3]
Out[78]:
['moo', 'stew', 'bamboo', 'woohoo']
In [79]:
l2[3][0]
Out[79]:
'moo'
In [80]:
l2[1:3]
Out[80]:
['a', 3.0]
In [81]:
l1
Out[81]:
[9, 1, 1]
In [82]:
l2
Out[82]:
[1, 'a', 3.0, ['moo', 'stew', 'bamboo', 'woohoo']]
In [83]:
l1 + l2
Out[83]:
[9, 1, 1, 1, 'a', 3.0, ['moo', 'stew', 'bamboo', 'woohoo']]
In [84]:
l1 * 3
Out[84]:
[9, 1, 1, 9, 1, 1, 9, 1, 1]
In [85]:
2 * l2
Out[85]:
[1,
 'a',
 3.0,
 ['moo', 'stew', 'bamboo', 'woohoo'],
 1,
 'a',
 3.0,
 ['moo', 'stew', 'bamboo', 'woohoo']]

mutation

In [86]:
l2
Out[86]:
[1, 'a', 3.0, ['moo', 'stew', 'bamboo', 'woohoo']]
In [87]:
l2[0] = "zzz"
In [88]:
l2
Out[88]:
['zzz', 'a', 3.0, ['moo', 'stew', 'bamboo', 'woohoo']]
In [89]:
x = [1,2,3,4,5]
In [90]:
y = x
In [91]:
y[0] = "a"
In [92]:
y
Out[92]:
['a', 2, 3, 4, 5]
In [93]:
x
Out[93]:
['a', 2, 3, 4, 5]

What's the moral?

  • moral: there is aliasing!

slice assignment

In [94]:
l2
Out[94]:
['zzz', 'a', 3.0, ['moo', 'stew', 'bamboo', 'woohoo']]
In [95]:
l1
Out[95]:
[9, 1, 1]
In [96]:
l2[0:3] = l1 * 3
In [97]:
l2
Out[97]:
[9, 1, 1, 9, 1, 1, 9, 1, 1, ['moo', 'stew', 'bamboo', 'woohoo']]

Statements:

  • If
In [98]:
x = -10
if x < 0:
  x = abs(x)
  print("Negative, flipped", x)
elif x == 0:
  print("Zero!")
else:
  print("Positive", x)
('Negative, flipped', 10)

Overall structure is:

if cond:

if-body-statement

elif cond:

elif-body-statement

else:

else-body-statement

Here the "elif" stands for "else if" -- a convenient shorthand. This is how you can do switch/case statements in Python.

indentation matters!!!

In [99]:
x
Out[99]:
10
In [100]:
pass
if x==15:
   y = 0
   print("is 15")

different from above!!!

In [101]:
pass
if x==15:
  y = 0
print("is 15")
is 15

what do think pass does?

  • "pass" is a dummy statement that is used when you need to have something in a statement block (like the above).
  • Ensure that the statement block is not empty.
    • As the name suggests, it doesnt do anything.
In [ ]:
if x==15:
   y = 0
   print("is 15")
  • Conditions (for if, elif) are like the usual.

    • Can use comparators ==, <,>,<=,>=,!=.
    • Unlike in OCaml you dont have to use an explicit boolean type.
  • Anything thats "not zero" is true and zero is false.

    • However, you CANNOT use = because that's assignment.
    • you cannot assign inside an if conditional. That's a separate statement!
In [102]:
if 1: print("true")
true
In [103]:
if 0: print("true")
In [104]:
if ["a"]: print("true")
true

What about this?

In [105]:
if []: print("true")
  • while - statement
In [106]:
a,b = 0,1
while b < 20:
  print(b)
  a, b = b, a+b
1
1
2
3
5
8
13
  • Multiple assignment: All of rhs is evaluated and then "simultaneously" stuck into LHS (like pattern-matching in OCaml). Assigning to the tuple (a,b) the value (0,1).

  • Indentation: The body of the while is indented appropriately.

while cond:

while-body-statement

  • For nested while loops, make sure you get indentation right!
  • Function
In [107]:
def fib(n):
  a,b = 0,1
  while (b < n):
    print(b)
    a,b = b,a+b

Easy enough. Note that the "body" of the function is indented appropriately. General form:

def fname(x1,x2,...):

<fbody-statement>
In [108]:
print(fib(5))
1
1
2
3
None

Can return something different using a return statement:

In [109]:
def fac(n):
  if n == 0:
    return 1
  else:
    return n * fac(n-1)
In [110]:
fac(10)
Out[110]:
3628800

This returns an integer, but python is dynamically-typed so it can return different values.

In [111]:
def fac(n):
  if n < 0:
    return "Rubbish negative arg"
  elif n == 0:
    return 1
  else:
    return n * fac(n-1)
In [112]:
fac(-10)
Out[112]:
'Rubbish negative arg'
In [113]:
fac(10)
Out[113]:
3628800

"default" parameters.

In [114]:
def greet(i,name="Bob"):
    print("H" + "e"*i + "y", name)
In [115]:
greet(3, "Sally")
('Heeey', 'Sally')
In [116]:
greet(3)
('Heeey', 'Bob')
  • Functional Programming
In [117]:
fac
Out[117]:
<function __main__.fac>

So this means that ...

  • You can nest function definitions -- just defines a "local" function
  • You can take functions as arguments
  • You can return functions as return values

  • All of the functional goodness is still there!!! Woohoo, party time!

Check it out:

In [118]:
def compose(f,g):
  def foo(x):
    return f(g(x))
  return foo
In [119]:
def times_3(x):
  return 3*x

def first_2_elems(x):
  return x[0:2]
In [120]:
baz = compose(times_3,first_2_elems)

baz([1, 2, "three", 4, "five"]) #works for sequences
Out[120]:
[1, 2, 1, 2, 1, 2]
In [121]:
baz("this is the end, my friend.")  #works for sequences
Out[121]:
'ththth'