Python data types

Python can be a little strange in providing lots of data types, dynamic type allocation, and some interconversion.

Numbers

Integers, Floating point numbers, and complex numbers are available automatically.


In [ ]:
f = 1.0
i = 1

print f, i
print 
print "Value of f is {}, value of i is {}".format(f,i)
print 
print "Value of f is {:f}, value of i is {:f}".format(f,i)

In [ ]:
## BUT !! 

print "Value of f is {:d}, value of i is {:f}".format(f,i)

In [ ]:
c = 0.0 + 1.0j

print c

print "Value of c is {:f}".format(c)

print "Value of c**2 is {:f}".format(c**2)

The math module needs to be imported before you can use it.


In [ ]:
import math
math.sqrt(f)

In [ ]:
math.sqrt(c)

In [ ]:
math.sqrt(-1)

In [ ]:
import cmath

print cmath.sqrt(f)
print cmath.sqrt(c)
print cmath.sqrt(-1)

numbers as objects

Virtually everything in python is an object. This means that it is a thing that can have multiple copies made (all of which behave independently) and which knows how to do certain operations on itself.

For example, a floating point number knows certain things that it can do as well as simply "being" a number:


In [ ]:
help(f)

In [ ]:
print f.is_integer()  # Strange eh ?
print f.conjugate()
print c.conjugate()
print f.__div__(2.0)  # This looks odd, but it is the way that f / 2.0 is implemented underneath

Strings


In [ ]:
s = 'hello'
print s[1]  
print s[-1]
print len(s)        
print s + ' world'

In [ ]:
ss = "\t\t hello \n \t\t world\n  \t\t !!!\n\n "
print ss
print ss.partition(' ')

In [ ]:
print s[-1]," ", s[0:-1]

But one of the problems with strings as data structures is that they are immutable. To change anything, we need to make copies of the data


In [ ]:
s[1] = 'a'

tuples and lists and sets

Tuples are bundles of data in a structured form but they are not vectors ... and they are immutable


In [ ]:
a = (1.0, 2.0, 0.0)
b = (3.0, 2.0, 4.0)

print a[1]
print a + b

In [ ]:
print a-b

In [ ]:
print a*b

In [ ]:
print 2*a

In [ ]:
a[1] = 2

In [ ]:
e = ('a', 'b', 1.0)
2 * e

Lists are more flexible than tuples, they can be assigned to, have items removed etc


In [ ]:
l  = [1.0, 2.0, 3.0]
ll = ['a', 'b', 'c']
lll = [1.0, 'a', (1,2,3), ['f','g', 'h']]

print l
print ll
print l[2], ll[2]
print 2*l
print l+l
print lll
print lll[3], " -- sub item 3 --> ", lll[3][1]

In [ ]:
print 2.0*l

In [ ]:
l[2] = 2.99
print l

In [ ]:
l.append(3.0)
print l

In [ ]:
ll += 'b'
print ll
ll.remove('b')  # removes the first one !
print ll

In [ ]:
l += [5.0]
print "1 - ", l
l.remove(5.0)
print "2 - ", l
l.remove(3.0)
print "3 - ", l
l.remove(4.0)
print "4 - ", l

Sets are special list-like collections of unique items. NOTE that the elements are not ordered (no such thing as s[1]


In [ ]:
s = set([6,5,4,3,2,1,1,1,1])
print s
s.add(7)
print s
s.add(1)

s2 = set([5,6,7,8,9,10,11])

s.intersection(s2)
s.union(s2)

Dictionaries

These are very useful data collections where the information can be looked up by name instead of a numerical index. This will come in handy as a lightweight database and is commonly something we need to use when using modules to read in data.


In [ ]:
d = { "item1": ['a','b','c'], "item2": ['c','d','e']}

print d["item1"]
print d["item1"][1]

d1 = {"Small Number":1.0, "Tiny Number":0.00000001, "Big Number": 100000000.0}

print d1["Small Number"] + d1["Tiny Number"]
print d1["Small Number"] + d1["Big Number"]

print d1.keys()

for k in d1.keys():
    print "{:>15s}".format(k)," --> ", d1[k]

More useful is the fact that the dictionary can have as a key, anything that can be converted using the hash function into a unique number. Strings, obviously, work well but anything immutable can be hashed:


In [ ]:
def hashfn(item):
    try:
        h = hash(item)
        print "{:>25}".format(item), " --> ", h
    except:
        print "{:>25}".format(item), " -->  unhashable type {}".format(type(item))
    return


hashfn("abc")
hashfn("abd")
hashfn("alphabeta")
hashfn("abcdefghi")

hashfn(1.0)
hashfn(1.00000000000001)
hashfn(2.1)

hashfn(('a','b'))
hashfn((1.0,2.0))

hashfn([1,2,3])

import math
hashfn(math.sin)  # weird ones !!


Exercise: Build a reverse lookup table

Suppose you have this dictionary of phone numbers:

phone_book = { "Achibald":   ("04", "1234 4321"), 
               "Barrington": ("08", "1111 4444"),
               "Chaotica" :  ("07", "5555 1234") }

Can you construct a reverse phone book to look up who is calling from their phone number ?

Solution: Here is a possible solution for the simple version of the problem but this could still use some error checking (if you type in a wrong number)


In [ ]:
# Name: ( area code, number )
phone_book = { "Achibald":   ("04", "1234 4321"), 
               "Barrington": ("08", "1111 4444"),
               "Chaotica" :  ("07", "5555 1234") }

reverse_phone_book = {}

for key in phone_book.keys():
    reverse_phone_book[phone_book[key]] = key

    
print reverse_phone_book[('07','5555 1234')]