Python Introduction

Abhishek Gupta, Artificial Intelligence Club, DA-IICT

version 0.1, Released 25/1/2014

This work is licensed under a GNU General Public License, version 2

Why Python?

Philosophy of python - PEP 20 (The Zen of Python):

  • Beautiful is better than ugly.
  • Explicit is better than implicit.
  • Simple is better than complex.
  • Complex is better than complicated.
  • Flat is better than nested.
  • Sparse is better than dense.
  • Readability counts.
  • There should be one-- and preferably only one --obvious way to do it.
  • If the implementation is hard to explain, it's a bad idea.
  • If the implementation is easy to explain, it may be a good idea.

Some supporting reasons:

  • Python is open.
  • Python is general purpose.
  • Python is dynamic.
  • Python is easy to read.
  • Python is great at introspection.
  • Documentation System.
  • Data Strucutres.
  • Available Libraries.

More:

Installation

I prefer to work in linux. I will follow linux way in this tutorial but will also give some directions for win user, if I know any.

Windows:
Just follow this Enthought Canopy. This is one click installation for windows.

Linux (src):

pre-requisite:

sudo apt-get install python-pip python-dev build-essential

Actual Packages:

sudo pip install numpy
sudo apt-get install libatlas-base-dev gfortran
sudo pip install scipy

Optional Packages:

sudo pip install ipython  OR  sudo apt-get install ipython
sudo apt-get install ipython-notebook
sudo pip install matplotlib   OR  sudo apt-get install python-matplotlib
sudo pip install -U scikit-learn
sudo pip install pandas

Python Overview

Basic Math


In [13]:
2 + 3


Out[13]:
5

In [203]:
2 - 3


Out[203]:
-1

In [4]:
4 / 2


Out[4]:
2

In [7]:
22 / 7.0       #pi


Out[7]:
3.142857142857143

In [8]:
191 * 7        #What is this??


Out[8]:
1337

In [27]:
2 ** 8


Out[27]:
256

Variables & Types


In [11]:
print type(1), type(1.0), type('a'), type(dir)


<type 'int'> <type 'float'> <type 'str'> <type 'builtin_function_or_method'>

In [12]:
dir()


Out[12]:
['In',
 'Out',
 '_',
 '_1',
 '_2',
 '_3',
 '_4',
 '_5',
 '_6',
 '_7',
 '_8',
 '__',
 '___',
 '__builtin__',
 '__builtins__',
 '__name__',
 '_dh',
 '_i',
 '_i1',
 '_i10',
 '_i11',
 '_i12',
 '_i2',
 '_i3',
 '_i4',
 '_i5',
 '_i6',
 '_i7',
 '_i8',
 '_i9',
 '_ih',
 '_ii',
 '_iii',
 '_oh',
 '_sh',
 'exit',
 'get_ipython',
 'help',
 'quit']

In [17]:
import math

golden_ratio = (1 + math.sqrt(_13)) / 2

print golden_ratio


1.61803398875

In [18]:
x = 1
type(x)


Out[18]:
int

In [19]:
x = 1.0
type(x)


Out[19]:
float

In [20]:
x = False
type(x)


Out[20]:
bool

In [22]:
x = 1j
print type(x)
print x.real, x.imag


<type 'complex'>
0.0 1.0

In [25]:
x = 10.12
print x is float
print int(x)


False
10

Opearators


In [32]:
5  ** 2 + 2 - 1 / 5.0 * 8


Out[32]:
25.4

In [35]:
print 4.3 / 4.1, 4.3 // 4.1


1.0487804878 1.0

Logical Operators


In [38]:
True and False


Out[38]:
True

In [39]:
True or False


Out[39]:
True

In [40]:
not False


Out[40]:
True

Boolean Operators


In [43]:
0b0101 | 0b0011


Out[43]:
7

In [44]:
0b0101 & 0b0011


Out[44]:
1

In [45]:
0b0101 ^ 0b0011


Out[45]:
6

Comparison Operators


In [49]:
2 > 1, 2 < 1


Out[49]:
(True, False)

In [50]:
2 >= 2, 2 <= 2


Out[50]:
(True, True)

In [51]:
1 == 1


Out[51]:
True

Compound Types

Strings


In [52]:
'Hello, World!', "Hello, World!"


Out[52]:
('Hello, World!', 'Hello, World!')

In [55]:
s = "Hello, World!"
print s


Hello, World!

In [56]:
type(s), len(s), s[0]


Out[56]:
(str, 13, 'H')

In [64]:
s[0:5], s[2:], s[2:-2]        #slicing


Out[64]:
('Hello', 'llo, World!', 'llo, Worl')

In [63]:
s[::3], s[-1::-1]


Out[63]:
('Hl r!', '!dlroW ,olleH')

In [70]:
s + ' ,' + s + s[-1] * 5


Out[70]:
'Hello, World! ,Hello, World!!!!!!'

String Formatting


In [72]:
s + str(42)


Out[72]:
'Hello, World!42'

In [75]:
num1 = 42
print 'What is universe? ', num1


What is universe?  42

In [78]:
num2 = 1.0
print 'Integer %d, Float %f' % (num1,num2),
print '.'


Integer 42, Float 1.000000 .

Lists


In [92]:
l = [1,2,3,4]
print type(l), len(l), l


<type 'list'> 4 [1, 2, 3, 4]

In [84]:
days_of_the_week = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]
print days_of_the_week


['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']

In [83]:
hybrid = ["Tuesday", 1, "Thursday", 5.0, "Saturday", l]
print hybrid


['Tuesday', 1, 'Thursday', 5.0, 'Saturday', [1, 2, 3, 4]]

In [107]:
l[2], days_of_the_week[::2], hybrid[5][2]


Out[107]:
(3, ['Sunday', 'Tuesday', 'Thursday', 'Saturday'], 3)

In [108]:
l.append(5)
l.append(-1)
l.append('numbers')
l.append('')
print l


[1, 2, 3, 4, 5, -1, 'numbers', '']

In [88]:
range(10), range(2,10), range(2,10,2)


Out[88]:
([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [2, 3, 4, 5, 6, 7, 8, 9], [2, 4, 6, 8])

In [97]:
helloList = list(s)

In [109]:
l.sort()
print l


[-1, 1, 2, 3, 4, 5, '', 'numbers']

In [114]:
del l[-2:]
print l


[-1, 1, 2, 3, 4, 5]

Tuples

Tuples are like lists, except that they cannot be modified once created, that is they are immutable.


In [115]:
point = (10, 20)

print type(point), len(point), point


<type 'tuple'> 2 (10, 20)

In [116]:
x = 4,
print x


(4,)

In [117]:
x,y = point
print x,y


10 20

In [118]:
point[0] = 4


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-118-14b93c6014c9> in <module>()
----> 1 point[0] = 4

TypeError: 'tuple' object does not support item assignment

Dictionaries

Dictionaries are also like lists, except that each element is a key-value pair.


In [119]:
params = {"parameter1" : 1.0,
          "parameter2" : 2.0,
          "parameter3" : 3.0,}

print type(params), len(params), params


<type 'dict'> 3 {'parameter1': 1.0, 'parameter3': 3.0, 'parameter2': 2.0}

In [120]:
params["parameter1"] = "A"
params["parameter2"] = "B"

# add a new entry
params["parameter4"] = "D"

print params


{'parameter4': 'D', 'parameter1': 'A', 'parameter3': 3.0, 'parameter2': 'B'}

In [122]:
print params.keys(), params.values()


['parameter4', 'parameter1', 'parameter3', 'parameter2'] ['D', 'A', 3.0, 'B']

Some points to ponder upon:

  • When to use what?
  • What is the benefit of keys?

Control Flow

Conditional Statements


In [124]:
statement1, statement2 = False, False

if statement1:
    print("statement1 is True")
    
elif statement2:
    print("statement2 is True")
    
else:
    print("statement1 and statement2 are False")


statement1 and statement2 are False

In [125]:
statement1 = statement2 = True

if statement1:
    if statement2:
        print("both statement1 and statement2 are True")


both statement1 and statement2 are True

Loops

For Loops


In [126]:
for x in [1,2,3]:
    print(x)


1
2
3

In [128]:
for x in range(4):
    print(x)


0
1
2
3

In [129]:
for key, value in params.items():
    print(key + " = " + str(value))


parameter4 = D
parameter1 = A
parameter3 = 3.0
parameter2 = B

In [130]:
for x in params:
    print(x + " = " + str(params[x]))


parameter4 = D
parameter1 = A
parameter3 = 3.0
parameter2 = B

In [131]:
for idx, x in enumerate(range(-3,3)):
    print(idx, x)


(0, -3)
(1, -2)
(2, -1)
(3, 0)
(4, 1)
(5, 2)

While loops


In [132]:
i = 0

while i < 5:
    print(i)
    
    i = i + 1
    
print("done")


0
1
2
3
4
done

Comprehensions

List Comprehensions


In [134]:
lst = [a for a in range(10)]
print lst


[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [135]:
squares = [x**2 for x in range(10)]
print squares


[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

In [137]:
evenSquares = [x**2 for x in range(10) if x%2 == 0]
print evenSquares


[0, 4, 16, 36, 64]

In [140]:
combos = []
for x in [1,2,3]:
    for y in [3,1,4]:
        if x != y:
            combos.append((x,y))
print combos

combosLCWay = [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
print combosLCWay


[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

In [146]:
mat = [[1,2],[3,4]]
nestedLC = [y for x in mat for y in x]
print nestedLC

#nestedLC Equivalent
nestedLCEq = []
for x in mat:
    for y in x:
        nestedLCEq.append(y)
print nestedLCEq


[1, 2, 3, 4]
[1, 2, 3, 4]

Dictionary Comprehensions


In [147]:
mat = [(1,2),[3,4]]
d = {key: value for (key, value) in mat}
print d


{1: 2, 3: 4}

Functions


In [149]:
def func0():   
    print("test")

func0()


test

In [150]:
def func1(arg1, arg2=2, *args, **kwargs):
    """
    Print a string 's' and tell how many characters it has    
    """
    
    print arg1, arg2, args, kwargs

In [151]:
func1('Hello')


Hello 2 () {}

In [152]:
func1('Hello', 5)


Hello 5 () {}

In [153]:
func1('Hello', 5, 8, 'Bye')


Hello 5 (8, 'Bye') {}

In [154]:
func1('Hello', 5, 8, 'Bye', name='John', age='15')


Hello 5 (8, 'Bye') {'age': '15', 'name': 'John'}

In [156]:
func1('Hello', 5, 8, 'Bye', name='John', age='15', 88)


  File "<ipython-input-156-8a66de430d80>", line 1
SyntaxError: non-keyword arg after keyword arg

Classes

A class is a structure for representing an object and the operations that can be performed on the object. In Python a class can contain attributes (variables) and methods (functions).

Each class method should have an argument self as it first argument. This object is a self-reference. Some class method names have special meaning, for example:

  • init: The name of the method that is invoked when the object is first created.
  • str : A method that is invoked when a simple string representation of the class is needed, as for example when printed.

For more: Special method names


In [157]:
class Point:
    """
    Simple class for representing a point in a Cartesian coordinate system.
    """
    
    def __init__(self, x, y):
        """
        Create a new Point at x, y.
        """
        self.x = x
        self.y = y
        
    def translate(self, dx, dy):
        """
        Translate the point by dx and dy in the x and y direction.
        """
        self.x += dx
        self.y += dy
        
    def __str__(self):
        return("Point at [%f, %f]" % (self.x, self.y))

To create a new instance of a class:


In [158]:
p1 = Point(0, 0) # this will invoke the __init__ method in the Point class

print(p1)         # this will invode the __str__ method


Point at [0.000000, 0.000000]

To invoke a class method in the class instance p:


In [159]:
p2 = Point(1, 1)

p1.translate(0.25, 1.5)

print(p1)
print(p2)


Point at [0.250000, 1.500000]
Point at [1.000000, 1.000000]

Iterators

Python iterator objects required to support two methods while following the iterator protocol.

  • iter returns the iterator object itself. This is used in for and in statements.
  • next method returns the next value from the iterator. If there is no more items to return then it should raise StopIteration exception.

In [163]:
class Counter(object):
    def __init__(self, low, high):
        self.current = low
        self.high = high
 
    def __iter__(self):
        'Returns itself as an iterator object'
        return self
 
    def next(self):
        'Returns the next value till current is lower than high'
        if self.current > self.high:
            raise StopIteration
        else:
            self.current += 1
            return self.current - 1

c = Counter(5,10)
for i in c:
    print i,


5 6 7 8 9 10

In [165]:
#Code behind previous iteration
iterator = iter(c)
while True:
    try:
        x = iterator.next()
        print x,
    except StopIteration as e:
        break

Generators

It is an easier way to create iterators using a keyword yield from a function.


In [166]:
def my_generator():
    print "Inside my generator"
    yield 'a'
    yield 'b'
    yield 'c'

In [168]:
print my_generator()


<generator object my_generator at 0x2500730>

In [170]:
for char in my_generator():
    print char
    print 'Hi'


Inside my generator
a
Hi
b
Hi
c
Hi

Counter using generator:


In [171]:
def counter_generator(low, high):
    while low <= high:
        yield low
        low += 1

for i in counter_generator(5,10):
    print i,


5 6 7 8 9 10

Generator are not re-usable:


In [173]:
g = my_generator()
for c in g:
    print c

print 'Second call'
for c in g:
    print c


Inside my generator
a
b
c
Second call

One way to create a reusable generator is Object based generators which does not hold any state. Any class with a __iter__ method which yields data can be used as a object generator.


In [177]:
class Counter(object):
	def __init__(self, low, high):
		self.low = low
		self.high = high

	def __iter__(self):
		counter = self.low
		while self.high >= counter:
			yield counter
			counter += 1

gobj = Counter(5, 10)
for num in gobj:
	print num,

print '\n\nSecond Call:\n'

for num in gobj:
	print num,


5 6 7 8 9 10 

Second Call:

5 6 7 8 9 10

More Python Functions and Keywords

Mapping


In [181]:
def sqr(x):return x**2

lSquare = map(sqr, l)
print l, lSquare


[-1, 1, 2, 3, 4, 5] [1, 1, 4, 9, 16, 25]

Zipping:


In [183]:
l1 = [1,2,3,4]
l2 = [6,7,8,5]

points = zip(l1,l2)
print points


[(1, 6), (2, 7), (3, 8), (4, 5)]

In [185]:
#Reverse Zipping
l1_new, l2_new = zip(*points)

print l1_new, l2_new


(1, 2, 3, 4) (6, 7, 8, 5)

In [199]:
zip?

Versions


In [201]:
import sys
print sys.version


2.7.4 (default, Sep 26 2013, 03:20:26) 
[GCC 4.7.3]