Basic python syntax

A friend of mine has just started using Python, and asked me for a quick run down of the basic syntax. Given that, wherever possible, I try to live my life according to the above xkcd comic, I figured it would be worth my while typing out a short tutorial for her. Of course, there are thousands of similar (and probably far better) scripts available on the internet. But this seemed as good a place as any to use as a storage facility.

#Python has a few differerent types of built in objects.

#Integers
itg = 3

#Floats
flt = 3.

#If you divide an integer by another, you will get the floor of the answer
print 'Dividing integers'
print itg/2

#But you can change the object type:
print 'Converting to floats'
print float(itg)/2

#You can also convert to integers
print int(flt)

#And strings
print str(flt)

#Actually, when printing, there is an easier way to do this using the percentage symbol
print 'Using the percentage symbol %f' %flt

#Here %f means - find the float
#Likewise %s means - find the string
print 'Another example %s' %'Here'

#this is a good way to do print statements as you can use more than one simultaneously
print '.2d means to two significant figures like this %.2d or include a float %f' %(flt, flt)

#You can pull out bits of strings using the index labels, which start from zero.
name = 'Minnie'

#Then the command:
print name[0]
#Should print 'M'

#Working backwards, the labels start with -1:
print name[-1]
#Will print 'e'

#This labelling system works for lists too - another important python object
a = [] #An empty list
b = [1, 4, 'hello']#A list with three items.

#Then:
print b[-1]
#Should print 'hello'

#You can add items on to the end of lists like this:
b.append('new item')

#See?
print b

#Which is especially usefull when you're creating lists using loops
for n in name: #Will loop through all the letters in name
    a.append(n)#And add them to the list a as individual items

print a
#See?

#Another thing to note is that no end statements are used in python. Everything is based on indentation

#There are a few other things you can do with lists, because they are objects. Type a. and then press tab in the shell window to
#see the possible commands. they include a.pop, a.index and so on. 

#You can also put for loops inside lists like this - which is the same as above, just written on one line
a2 = [n for n in name]

#Lists are also super useful because they can contain objects themselves.

#To explain this, we need to use an example of a class
class Girl():
    def __init__(self, name, age):
        self.name  = name
        self.age = age

#The init function, within a class, initialises the instance of the class. For example
g = Girl('Minnie', 30)

#Makes a girl object with name minnie and age 30. Because of the self tag, you can now type
print g.name

#to get Minnie or
print g.age

#To get 30.

#Back to lists, you don't even need to give a handle to each instance of the girl class. Instead, you could make a list, 'girls'
girls = []
girls.append(g)
girls.append(Girl('Hannah', 27))

#Now the first item in the girls list takes the place of your g handle above:
print girls[0].name

#Same with the last item
print girls[-1].name

#Infact typing girls[1]. and then tab in the shell will give you the options which we defined in Girl: age and name.

#Geddit?

#There's one thing you need to be careful of with lists/python in general which is when setting things equal to each other.
list1 = [1]
list2 = list1

#Now, list2 isn't *actually* equal to list1, it just points to the same address on the computer.
print list2

#Now if you change list1:
list1[0] = 5

#List2 will automatically update itself
print list2

#You should be careful of this when coding as it can catch you out (it certainly has me in the past). Actually though,
#Although it initally seems stupid, it's actually a really useful (and quick) feature.

#Say you're working out a function f which depends on itself at the previous time step
#f(t+1) = f(f(t))

#You can code it like this:
#fnew = f**2 + 3 (or whatever the dependence is)
#Then when you're done, you can swap the pointers over
#fnew, f = f, fnew

#The other important built in object in python are dictionaries
D = {} #An empty dictionary

#You could use this instead of the girls object above
girlsD = {'Hannah':27, 'Minnie':30}

#Or to add a new item:
girlsD['Nenna'] = 26

#These are especailly useful when doing stuff with networks, but you should bear in mind that dictionaries DO NOT preserve order (lists do).

#Again type girlsD. and then tab in the shell to see the options available to you.

#That pretty much brings us to the end of what you can do without importing any other packages, so we'll move on to the most useful python
#package (as far as mathematical programming is concerned) Scipy.

#It's custom to import it with a shortcut handle
import scipy as sp

#Then anything that's in scipy can be called using the sp handle
sp.exp(5.)

#Actually, you can call the handle anything you like
import scipy as anything
anything.exp(5.)

#Or, not use one
import scipy
scipy.exp(5.)

#Or import everything, so you don't need to use a handle at all
from scipy import *
exp(5.)

#This is not that efficient though tbh, so probs best avoided.

#Now scipy has lots of cool stuff that you can see online, but the most important feature is the arrays. With lists you see, you can't add them
#Or do any arithmetic with them
a = [1,2,3]
b = [3,2,1]

#Now, if you typed a+b, it would produce an error.

#If a and b were arrays though:
a = sp.array([1,2,3])
b = sp.array([3,2,1])

#Now a+b would work.
print a+b

#and a*b gives element-wise multiplication
print a*b

#Geddit?

#a and b are 1d arrays, but you can also make vectors and matrices with sp.array:
row= sp.array([[1,2,3]])

#row is a 1x3 array
print sp.shape(row)

#likewise
col = sp.array([[1],[2],[3]])

#Is a 3x1
print sp.shape(col)

#Now, you could do matrix multiplication with these bad boys:
sp.dot(row, col)

#Which isn't the nicest notation, but it'll do.

#There are two other sp things that are quite useful:
xvals = sp.linspace(0, 100, 200)

#Auto generates an array from 0 to 100 with 200 points

#The other:
yvals = sp.arange(0, 10, 0.05)

#Lets you define your stepsize instead.

#Now, lets say we wanted to plot these, we'd need the plotting library
import pylab as plt

#Guess what the command is to plot something?
plt.plot(xvals, yvals)

#And if you want to save the figure?
plt.savefig('test')

#Phwoar. Got to love python.