Basic Python

Introduction

Python in a powerful, high-level, interpreted and multi-platform programming language with an elegant and readable syntax, efficient high-level data structures and a simple but effective approach to object programming.

Python is easy to learn. It has been designed to help the programmer concentrate on solving the problem at hand and not worry about the programming language idiosyncrasies. Programmers often fall in love with Python, for the increased productivity it brings.

Python was created by Guido van Rossum. The idea of Python was conceived in December 1989. The name Python comes from the 70s comedy series “Monty Python’s Flying Circus” and has nothing to do with the reptilian.

Why Python?

  • Python code is extremely readable. It has no braces and semi-colons and uses indentation, instead, for defining code blocks. This forces the programmers to write readable code.
  • It is interactive and the interactive environment offers a very fast edit-test-debug cycle.
  • It has a good set of high-level data structures and has been designed to let the programmer focus on the problem, rather than worry about the idiosyncrasies of the language.
  • It handles memory management and takes the burden, of allocating and de-allocating memory to variables off the programmer.
  • It is a Batteries included language. It comes with a huge standard library that allows us to do a wide range of tasks.
  • It is object-oriented.
  • It interfaces with other programming languages such as C, C++ and FORTRAN. This allows us to use legacy code available in these languages.
  • It not as fast as some of the compiled languages like C or C++. But, we think that the programmer’s time is more valuable than machine time. Given the flexibility and power that Python gives the programmer, Python is a valuable tool to learn.

The Interpreter

Let us get our hands dirty, right away. Typing python at the terminal, will start up the Python interpreter. You should see something like this, if you do have Python installed.

Python 2.7.1 (r271:86832, Feb 21 2011, 01:28:26)
[GCC 4.5.2 20110127 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

The first line shows the version of Python that we are using. In this example the version of Python being used is 2.7.1

>>> is called the prompt and it implies that the interpreter is ready and waiting for your command!

Let’s write our first line of Python code, the ubiquitous Hello World.

>>> print 'Hello, World!'
Hello, World!

Typing print 'Hello World' and hitting enter, printed out the words Hello World.

Let us now exit the interpreter. Hitting Ctrl-D, exits the python interpreter.

Now we shall learn to use IPython, an enhanced interpreter, instead of the vanilla interpreter, which we just saw.

A note on Versions

Before we continue, a not on the versions of Python is in order. Python currently has two stable branches or versions, 2.x and 3.x. 3.x branch was created with the idea of cleaning up some areas of Python, to make it more consistent, without bothering about backward compatibility with older versions. So, 3.x is not compatible with 2.x, and is deemed to be the future of Python. But, we shall use 2.x for this course, since the ecosystem around 3.x is still growing and a lot of packages don’t yet work with Python 3.x.

IPython - An enhanced interactive Python interpreter

IPython is an enhanced Python interpreter that provides features like tabcompletion, easier access to help and lot of other functionality which are not available in the vanilla Python interpreter.

invoking IPython

First let us see how to invoke the ipython interpreter.

We type

ipython

at the terminal prompt to invoke the ipython interpreter.

The prompt is now, In [1]: instead of the >>> in the vanilla Python interpreter. We also get the same information about the version of Python installed. But additionally, we get some IPython help information, instead of the vanilla interpreter’s help.

In stands for input and the number in the brackets indicates the number of the current command in this session. We shall see how it’s useful in a short while.

If you get an error saying something like ipython is not installed, install it and continue with the course.

Let’s try out the same Hello World in ipython.

print 'Hello World!'

Now, to quit the ipython interpreter, type Ctrl-D. You are prompted asking if you really want to exit, type y to say yes and quit ipython.

Start ipython again, as you did before.

History and Arrow Keys

Now let us see, how we can type some commands into the interpreter.

Start with the simplest thing, addition.

Let’s type

1 + 2

at the prompt. IPython promptly gives back the output as 3. Notice that the output is displayed with an Out[1] indication.

Let’s try out few other mathematical operations.

5 - 3
7 - 4
6 * 5

Now let’s print 1+2. Instead of typing the whole thing, we make use of the fact that IPython remembers the history of the commands that you have already used. We use the up arrow key to go back the command 1+2. We then use the left-arrow key to navigate to the beginning of the line and add the word print and a space. Then hit enter and observe that the interpreter prints out the value as 3, without the Out[] indication.

Now, let’s change the previous command print 1+2 to print 10*2. We use the up arrow again to navigate to the previous command and use the left arrow key to move the cursor on to the + symbol and then use the delete key to remove it and type 0 and * to change the expression as required. We hit enter to see the output of print.

Tab-completion

Now, let’s say we want to use the function round. We type ro at the prompt and hit the tab key. As you can see, IPython completes the command. This feature is called the tab-completion.

Now, we remove all the characters and just type r and then hit tab. IPython does not complete the command since there are many possibilities. It just lists out all the possible completions.

Now, let’s see what these functions are used for. We will use the help features of ipython to find this out.

Help using ?

To get the help of any function, we first type the function, abs in our case and then add a ? at the end and hit enter.

As the documentation says, abs accepts a number as an input and returns it’s absolute value.

We say,

abs(-19)

abs(19)

We get 19, as expected, in both the cases.

Does it work for decimals (or floats)? Let’s try typing abs(-10.5) and we do get back 10.5.

Let us look at the documentation of the round function.

round?

If you notice, there are extra square brackets around the ndigits. This means that ndigits is optional and 0 is the default value. Optional parameters are shown in square brackets anywhere in Python documentation.

The function round, rounds a number to a given precision.

round(2.48)
round(2.48, 1)
round(2.48, 2)

round(2.484)
round(2.484, 1)
round(2.484, 2)

We get 2.0, 2.5 and 2.48, which are what we expect.

Interrupting

Let’s now see how to correct typing errors that we make while typing at the terminal. As already shown, if we haven’t hit the enter key already, we could navigate using the arrow keys and make deletions using delete or backspace key and correct the errors.

Let’s now type round(2.484 and hit enter, without closing the parenthesis. We get a prompt with dots. This prompt is the continuation prompt of ipython. It appears, the previous line is incomplete in some way. We now complete the command by typing, the closing parenthesis and hitting enter. We get the expected output of 2.5.

In other instances, if we commit a typing error with a longer and more complex expression and end up with the continuation prompt, we can type Ctrl-C to interrupt the command and get back the ipython input prompt.

For instance,

round(2.484
^C

round(2.484, 2)

Now that we know how to use the interpreter, we shall move look at the basic data-types Python provides, and basic operators.

Basic Datatypes and Operators

Python provides the following basic datatypes.

  • Numbers
    • int
    • float
    • complex
  • Boolean
  • Sequence
    • Strings
    • Lists
    • Tuples

Numbers

We shall start with exploring the Python data types in the domain of numbers.

There are three built-in data types in python to represent numbers, namely:

  • int
  • float
  • complex

Let us first talk about int

a = 13
a

Now, we have our first int variable a.

To verify this, we say

type(a)
<type 'int'>

int data-type can hold integers of any size lets see this by an example.

b = 99999999999999999999
b

As you can see, even when we put a value of 9 repeated 20 times Python did not complain.

Let us now look at the float data-type. Decimal numbers in Python are represented by the float data-type

p = 3.141592
p

If you notice the value of output of p isn’t exactly equal to p. This is because floating point values have a fixed precision (or bit-length) and it is not possible to represent all numbers within the given precision. Such numbers are approximated and saved. This is why we should never rely on equality of floating point numbers in a program.

Finally, let us look at the complex data-type.

c = 3+4j

gives us a complex number, c with real part 3 and imaginary part 4.

To get the real and imaginary parts of c, we say

c.real
c.imag

Note that complex numbers are a combination of two floats, i.e., the real and the imaginary parts, 3 and 4 are floats and not integers.

type(c.real)
type(c.imag)

We can get the absolute value of c, by

abs(c)

Let’s now look at some operators common operations on these data-types.

23 + 74
23 - 56
45 * 76

8 / 3
8.0 / 3

The first division, 8/3 is an integer division and results in an integer output. In the second division, however, the answer is a float. To avoid integer division, at least one of the operands should be a float.

% is used for the modulo operation.

87 % 6

and ** is for exponentiation.

7 ** 8

All of the above operations can be performed with variables, as well.

a = 23
b = 74
a * b

c = 8
d = 8.0
f = c / 3
g = d / 3

In the last two commands, the results of the operations are being assigned to new variables.

In case, we wish to assign the result of an operation on the variable to itself, we can use a special kind of assignment.

c /= 3

is the same as

c = c / 3

Booleans

Now let us look at the Boolean data-type.

t = True

creates a boolean variable t, whose value is True. Note that T in true is capitalized.

You can apply different Boolean operations on t now.

For example

f = not t
f
f or t
f and t

What if you want to use multiple operators? Here’s an example.

(f and t) or t

Note that we have used parenthesis, to explicitly state what we want to do. We are not going to discuss operator precedence and shall use parenthesis, when using multiple operators.

The following expression, for instance is different from the one above.

f and (t or t)

Sequences

Let’s now discuss the sequence data types in Python. The data-types which hold a bunch of elements in them, in a sequential order are called sequence data-types. The elements can be accessed using their position in the sequence.

The sequence datatypes in Python are -

  • str
  • list
  • tuple
greet_str = "hello"

greet_str is now a string variable with the value hello

Anything within quotes is a string.

Items enclosed in square brackets separated by commas constitute a list.

num_list = [1, 2, 3, 4, 5, 6, 7, 8]
num_list

To create a tuple we use parentheses (‘(‘) instead of square brackets (‘[‘)

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

Operations on sequences

Due to their sequential nature, there are certain kind of operations, which can be performed on all of them.

Firstly, accessing elements. Elements in sequences can be accessed using indexes.

num_list[2]
num_tuple[2]
greet_str[2]

As you can see, indexing starts from 0.

Secondly, you can add two sequences of the same type, to each other to give new sequences.

num_list + [3, 4, 5, 6]
greet_str + " world!"

Thirdly, you can get the length of a sequence, by using the len function.

len(num_list)
len(greet_str)

Fourthly, we can check the containership of an element using the in keyword

3 in num_list
'h' in greet_str
'w' in greet_str
2 in num_tuple

We see that it gives True and False accordingly.

Next, we can find the maximum and minimum elements from a sequence.

max(num_tuple)
min(greet_str)

As a consequence of their order, we can access a group of elements in a sequence. They are called called slicing and striding.

First lets discuss slicing, on the list num_list. We can access a part of this sequence by slicing the sequence. Lets say we want elements starting from 2 and ending in 5.

num_list[1:5]

Note that the elements starting from the first index to the last one, the last one not included are being returned. We shall look at the details, later.

Striding is similar to slicing except that the step size here is not one.

num_list[1:8:2]

The colon two added in the end signifies all the alternate elements. This is why we call this concept striding because we move through the list with a particular stride or step. The step in this example being 2.

This brings us to the end of our discussion on basic data-types and operations on them.

Strings

We looked at strings, when looking at the sequence data-types of Python. We shall now look at them in a greater detail.

So, what are strings? In Python anything within either single quotes or double quotes or triple single quotes or triple double quotes are strings.

'This is a string'
"This is a string too'
'''This is a string as well'''
"""This is also a string"""
'p'
""

Note that it really doesn’t matter how many characters are present in the string. The last example is a null string or an empty string.

Having more than one control character to define strings is handy when one of the control characters itself is part of the string. For example:

"Python's string manipulation functions are very useful"

By having multiple control characters, we avoid the need for escaping characters – in this case the apostrophe.

The triple quoted strings let us define multi-line strings without using any escaping. Everything within the triple quotes is a single string no matter how many lines it extends

"""Having more than one control character to define
strings come as very handy when one of the control
characters itself is part of the string."""

We can assign this string to any variable

a = 'Hello, World!'

Now a is a string variable. A string is a sequence of characters, as we have already seen. In addition string is an immutable collection. So all the operations that are applicable to any other immutable collection in Python works on string as well. So we can add two strings

a = 'Hello'
b = 'World'
c = a + ', ' + b + '!'

We can add string variables as well as the strings themselves all in the same statement. The addition operation performs the concatenation of two strings.

Similarly we can multiply a string with an integer

a = 'Hello'
a * 5

gives another string in which the original string ‘Hello’ is repeated 5 times.

Let’s now look at accessing individual elements of strings. Since, strings are collections we can access individual items in the string using the subscripts

a[0]

gives us the first character in the string. The indexing starts from 0 for the first character and goes up to n-1 for the last character. We can access the strings from the end using negative indices

a[-1]

gives us the last element of the string and

a[-2]

gives us second element from the end of the string

Let us attempt to change one of the characters in a string:

a = 'hello'
a[0] = 'H'

As said earlier, strings are immutable. We cannot manipulate a string. Although there are some methods which let us manipulate strings, we will look at them in the advanced session on strings. In addition to the methods that let us manipulate the strings we have methods like split which lets us break the string on the specified separator, the join method which lets us combine the list of strings into a single string based on the specified separator.

Let us now learn to manipulate strings, specifically slicing and reversing them, or replacing characters, converting from upper to lower case and vice-versa and joining a list of strings.

Let us consider a simple problem, and learn how to slice strings and get sub-strings.

Let’s say the variable week has the list of the names of the days of the week.

week = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"]

Now given a string s, we should be able to check if the string is a valid name of a day of the week or not.

s = "saturday"

s could be in any of the forms — sat, saturday, Sat, Saturday, SAT, SATURDAY. For now, shall now be solving the problem only for the forms, sat and saturday. We shall solve it for the other forms, at the end of the tutorial.

So, we need to check if the first three characters of the given string exists in the variable week.

As, with any of the sequence data-types, strings can be sliced into sub-strings. To get the first three characters of s, we say,

s[0:3]

Note that, we are slicing the string from the index 0 to index 3, 3 not included.

s = "saturday"
s[:3]

Now, we just check if that substring is present in the variable week.

s[:3] in week

Let us now consider the problem of finding out if a given string is palindromic or not. First of all, a palindromic string is a string that remains same even when it has been reversed.

Let the string given be malayalam.

s = "malayalam"

Now, we need to compare this string with it’s reverse.

Again, we will use a technique common to all sequence data-types, [::-1]

So, we obtain the reverse of s, by simply saying,

s[::-1]

Now, to check if the string is s is palindromic, we say

s == s[::-1]

As, expected, we get True.

Now, if the string we are given is Malayalam instead of malayalam, the above comparison would return a False. So, we will have to convert the string to all lower case or all upper case, before comparing. Python provides methods, s.lower and s.upper to achieve this.

Let’s try it out.

s = "Malayalam"

s.upper()

s

As you can see, s has not changed. It is because, upper returns a new string. It doesn’t change the original string.

s.lower()

s.lower() == s.lower()[::-1]

So, as you can see, now we can check for presence of s in week, in whichever format it is present – capitalized, or all caps, full name or short form.

We just convert any input string to lower case and then check if it is present in the list week.

Now, let us consider another problem. We often encounter e-mail id’s which have @ and periods replaced with text, something like info[at]fossee[dot]in. We now wish to get back proper e-mail addresses.

Let’s say the variable email has the email address.

email = "info[at]fossee[dot]in"

Now, we first replace the [at] with the @, using the replace method of strings.

email = email.replace("[at]", "@")
print email

email = email.replace("[dot]", ".")
print email

Now, let’s look at another interesting problem where we have a list of e-mail addresses and we wish to obtain one long string of e-mail addresses separated by commas or semi-colons.

email_list = ["info@fossee.in", "enquiries@fossee.in",  "help@fossee.in"]

Now, if we wish to obtain one long string, separating each of the email id by a comma, we use the join operator on ,.

email_str = ", ".join(email_list)
print email_str

Notice that the email ids are joined by a comma followed by a space.

That brings us to the end of our discussion on strings. Let us now look at conditionals.

Conditionals

Whenever we have two possible states that can occur depending on a whether a certain condition we can use if/else construct in Python.

For example, say, we have a variable a which stores integers and we are required to find out whether a is even or odd. an even number or an odd number. Let’s say the value of a is 5, now.

a = 5

In such a case we can write the if/else block as

if a % 2 == 0:
    print "Even"
else:
    print "Odd"

If a is divisible by 2, i.e., the result of “a modulo 2” is 0, it prints “Even”, otherwise it prints “Odd”.

Note that in such a case, only one of the two blocks gets executed depending on whether the condition is True or False.

There is a very important sytactic element to understand here. Every code block begins with a line that ends with a :, in this example the if and the else lines. Also, all the statements inside a code block are intended by 4 spaces. Returning to the previous indentation level, ends the code block.

The if/else blocks work for a condition, which can take one of two states. What do we do for conditions, which can take more than two states?

Python provides if/elif/else blocks, for such conditions. Let us take an example. We have a variable a which holds integer values. We need to print “positive” if a is positive, “negative” if it is negative or “zero” if it is 0.

Let us use if/elif/else ladder for it. For the purposes of testing our code let us assume that the value of a is -3

a = -3

if a > 0:
    print "positive"
elif a < 0:
    print "negative"
else:
    print "zero"

All the syntax and rules as said for if/else statements hold. The only addition here is the elif statement which can have another condition of its own.

Here too, exactly one block of code is executed – the block of code which first evaluates to True. Even if there is a situation where multiple conditions evaluate to True all the subsequent conditions other than the first one which evaluates to True are neglected. Consequently, the else block gets executed if and only if all the conditions evaluate to False.

Also, the else block in both if/else statement and if/elif/else is optional. We can have a single if statement or just if/elif statements without having else block at all. Also, there can be any number of elif’s within an if/elif/else ladder. For example

if user == 'admin':
    # Do admin operations
elif user == 'moderator':
    # Do moderator operations
elif user == 'client':
    # Do customer operations

is completely valid. Note that there are multiple elif blocks and there is no else block.

In addition to these conditional statements, Python provides a very convenient ternary conditional operator. Let us take the following example where we have a score string, which can either be a number in the range 0 to 100 or the string ‘AA’, if the student is absent. We wish to convert the score string, into an integer, whenever possible. If the score string is ‘AA’, we wish to make the corresponding value 0. Let us say the string score is stored in score_str variable. We can do it using an if-else construct as below

if score_str != 'AA':
    score = int(score_str)
else:
    score = 0

The same thing can be done using a ternary operator, which reads more natural and has greater brevity.

score = int(score_str) if score_str != 'AA' else 0

Moving on, there are certain situations where we will have no operations or statements within a block of code. For example, we have a code where we are waiting for the keyboard input. If the user enters “c”, “d” or “x” as the input we would perform some operation nothing otherwise. In such cases “pass” statement comes very handy.

a = raw_input("Enter 'c' to calculate and exit, 'd' to display the existing
results exit and 'x' to exit and any other key to continue: ")

if a == 'c':
   # Calculate the marks and exit
elif a == 'd':
   # Display the results and exit
elif a == 'x':
   # Exit the program
else:
   pass

In this case “pass” statement acts as a place holder for the block of code. It is equivalent to a null operation. It literally does nothing. It can used as a place holder when the actual code implementation for a particular block of code is not known yet but has to be filled up later.

That brings us to the end of our discussion of conditionals.

Loops

We shall now, look at while and for loops. We shall look at how to use them, how to break out of them, or skip some iterations in loops.

We shall first begin with the while loop. The while loop is used for repeated execution as long as a condition is True.

Let us print the squares of all the odd numbers less than 10, using the while loop.

i = 1

while i<10:
    print i*i
    i += 2

This loop prints the squares of the odd numbers below 10.

The while loop, repeatedly checks if the condition is true and executes the block of code within the loop, if it is. As with any other block in Python, the code within the while block is indented to the right by 4 spaces.

Let us now solve the same problem of printing the squares of all odd numbers less than 10, using the for loop. The for loop iterates over a list or any other sequential data type.

for n in [1, 2, 3]:
    print n

Each of the elements of the list, gets printed. The variable n, called the loop variable, successively takes the value of each of the elements in the list, in each iteration.

Now, we could solve the problem of calculating the squares, by

for n in [1, 3, 5, 7, 9]:
    print n*n

But, it is “unfair” to generate the list by hand. So, we use the range function to get a list of odd numbers below 10, and then iterate over it and print the required stuff.

for n in range(1, 10, 2):
    print n*n

The first argument to the range function is the start value, the second is the stop value and the third is the step-size. The range function returns a list of values from the start value to the stop value (not included), moving in steps of size given by the step-size argument.

Also, The start and the step values are optional. For instance, the code below prints numbers from 0 to 9.

for n in range(10):
    print n

Let us now look at how to use the keywords, pass, break and continue.

As we already know, pass is just a syntactic filler. It is used for the sake of completion of blocks, that do not have any code within them.

for n in range(2, 10, 2):
    pass

break is used to break out of the innermost loop. The while loop to print the squares of all the odd numbers below 10, can be modified using the break statement, as follows

i = 1

while True:
    print i*i
    i += 2
    if i<10:
        break

continue is used to skip execution of the rest of the loop on this iteration and continue to the end of this iteration.

Say, we wish to print the squares of all the odd numbers below 10, which are not multiples of 3, we would modify the for loop as follows.

for n in range(1, 10, 2):
    if n%3 == 0:
        continue
    print n*n

This brings us to the end of the section on loops. We have learned how to use the for and while loops.

Lists

We have already seen lists as a kind of sequence data-type. We shall look at them in greater detail, now.

We will first create an empty list with no elements.

empty = []
type(empty)

This is an empty list without any elements.

Let’s now define a non-empty list.

p = ['spam', 'eggs', 100, 1.234]

Thus the simplest way of creating a list is typing out a sequence of comma-separated values (or items) between two square brackets.

As we can see lists can contain different kinds of data. They can be heterogeneous. In the previous example ‘spam’ and ‘eggs’ are strings whereas 100 and 1.234 are integer and float respectively. Below, is another example.

q = [[4, 2, 3, 4], 'and', 1, 2, 3, 4]

As you already know, we access an element of a list using its index. Index of the first element of a list is 0.

::
p[0] p[1] p[3]

List elements can also be accessed using negative indexing. p[-1] gives the last element of p.

::
p[-1]

As you can see you get the last element which is 1.234.

Similarly, -2 gives the second to last element and -4 gives the fourth from the last which, in this case, is the first element.

p[-2]
p[-4]

Using len function we can check the number of elements in the list p.

len(p)

We can append elements to the end of a list using the method append.

p.append('onemore')
p
p.append([1, 6])
p

As we can see p is appended with ‘onemore’ and [1, 6] at the end.

Just like we can append elements to a list we can also remove them. There are two ways of doing it. First, is by using the del command and the index of the element.

del p[1]

will delete the element at index 1, i.e the second element of the list, ‘eggs’.

The other way is removing element by choosing the item. Let’s say one wishes to delete 100 from p list the syntax of the command would be

p.remove(100)

but what if there were two 100’s. To check that lets do a small experiment.

p.append('spam')
p
p.remove('spam')
p

If we check now we will see that the first occurence ‘spam’ is removed and therefore remove removes the first occurence of the element in the sequence and leaves others untouched.

Another other basic operation that we can perform on lists is concatenation of two or more lists. We can combine two lists by using the “plus” operator. Say we have

a = [1, 2, 3, 4]
b = [4, 5, 6, 7]
a + b

When we concatenate lists using the “plus” operator we get a new list. We can store this list in a new variable

c = a + b
c

It is important to observe that the “plus” operator always returns a new list without altering the lists being concatenated in any way.

Let us now look at slicing and striding on lists. Let’s create a list primes.

primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

To obtain all the primes between 10 and 20 from the above list of primes we say

primes[4:8]

This gives us all the elements in the list starting from the element with the index 4, which is 11 in our list, upto the element with index 8 (not included).

primes[0:4]

will give us the primes below 10. Recall that the element with the index 4 is not included in the slice that we get.

By default the slice fetches all the elements between start and stop (stop not-included). But, Python also provides the functionality to specify a step size, when picking elements. Say, we have

num = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

If we want to obtain all the odd numbers less than 10 from the list num we have to start from element with index 1 upto the index 10 in steps of 2

num[1:10:2]

When no step is specified, it is assumed to be 1. Similarly, there are default values for start and stop indices as well. If we don’t specify the start index it is implicitly taken as the first element of the list

num[:10]

This gives us all the elements from the beginning upto the 10th element but not including the 10th element in the list “num”. Similary if the stop index is not specified it is implicitly assumed to be the end of the list, including the last element of the list

num[10:]

gives all the elements starting from the 10th element in the list “num” upto the final element including that last element. Now

num[::2]

gives us all the even numbers in the list “num”.

We know that a list is a collection of data. Whenever we have a collection we run into situations where we want to sort the collection. Lists support sort method which sorts the list in-place

a = [5, 1, 6, 7, 7, 10]
a.sort()

Now the contents of the list a will be

a
[1, 5, 6, 7, 7, 10]

As the sort method sorts the elements of a list, the original list we had is overwritten or replaced. We have no way to obtain the original list back. One way to avoid this is to keep a copy of the original list in another variable and run the sort method on the list.

However, Python also provides a built-in function called sorted which sorts the list which is passed as an argument to it and returns a new sorted list

a = [5, 1, 6, 7, 7, 10]
sorted(a)

We can store this sorted list another list variable

sa = sorted(a)

Python also provides the reverse method which reverses the list in-place

a = [1, 2, 3, 4, 5]
a.reverse()

reverses the list a and stores the reversed list inplace i.e. in a itself. Let’s see the list a

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

But again the original list is lost.

To reverse a list, we could use striding with negative indexing.

a[::-1]

We can also store this new reversed list in another list variable.

That brings us to the end of our discussion on lists.

I/O

Input and Output are used in almost every program, we write. We shall now learn how to

  • Output data
  • Take input from the user

Let’s start with printing a string.

a = "This is a string"
a
print a

print a, obviously, is printing the value of a.

As you can see, even when you type just a, the value of a is shown. But there is a difference.

Typing a shows the value of a while print a prints the string. This difference becomes more evident when we use strings with newlines in them.

b = "A line \n New line"
b
print b

As you can see, just typing b shows that b contains a newline character. While typing print b prints the string and hence the newline.

Moreover when we type just a, the value a is shown only in interactive mode and does not have any effect on the program while running it as a script.

We shall look at different ways of outputting the data.

print statement in Python supports string formatting. Various arguments can be passed to print using modifiers.

x = 1.5
y = 2
z = "zed"
print "x is %2.1f y is %d z is %s" %(x, y, z)

As you can see, the values of x, y and z are substituted in place of %2.1f, %d and %s respectively.

We can also see that print statement prints a new line character at the end of the line, everytime it is called. This can be suppressed by using a ”,” at the end print statement.

Let us see this by typing out following code on an editor as print_example.py

Open an editor, like scite, emacs or vim and type the following.

print "Hello"
print "World"

print "Hello",
print "World"

Now we run the script using %run /home/fossee/print_example.py in the interpreter. As we can see, the print statement when used with comma in the end, prints a space instead of a new line.

Note that Python files are saved with an extension .py.

Now we shall look at taking input from the user. We will use the raw_input for this.

Let’s type

ip = raw_input()

The cursor is blinking indicating that it is waiting for input. We now type some random input,

an input

and hit enter.

Now let us see what is the value of ip by typing.

ip

We can see that it contains the string “an input”

Note that raw_input always gives us a string. For example

c = raw_input()
5.6
c

Now let us see the type of c.

type(c)

We see that c is a string. This implies that anything you enter as input, will be taken as a string no matter what you enter.

raw_input can also display a prompt to assist the user.

name = raw_input("Please enter your name: ")

prints the string given as argument and then waits for the user input.

Files

We shall, now, learn to read files, and do some basic actions on the file, like opening and reading a file, closing a file, iterating through the file line-by-line, and appending the lines of a file to a list.

Let us first open the file, pendulum.txt present in /home/fossee/. The file can be opened using either the absolute path or relative path. In all of these examples we shall assume that our present working directory is /home/fossee/ and hence we only need to specify the file name. To check the present working directory, we can use the pwd command and to change our working directory we can use the cd command.

pwd
cd /home/fossee

Now, to open the file

f = open('pendulum.txt')

f is called a file object. Let us type f on the terminal to see what it is.

f

The file object shows, the file which is open and the mode (read or write) in which it is open. Notice that it is open in read only mode, here.

We shall first learn to read the whole file into a single variable. Later, we shall look at reading it line-by-line. We use the read method of f to read, all the contents of the file into the variable pend.

pend = f.read()

Now, let us see what is in pend, by typing

print pend

We can see that pend has all the data of the file. Type just pend to see more explicitly, what it contains.

pend

We can split the variable pend into a list, pend_list, of the lines in the file.

pend_list = pend.splitlines()

pend_list

Now, let us learn to read the file line-by-line. But, before that we will have to close the file, since the file has already been read till the end.

Let us close the file opened into f.

f.close()

Let us again type f on the prompt to see what it shows.

f

Notice, that it now says the file has been closed. It is a good programming practice to close any file objects that we have opened, after their job is done.

Let us, now move on to reading files line-by-line.

To read the file line-by-line, we iterate over the file object line-by-line, using the for command. Let us iterate over the file line-wise and print each of the lines.

for line in open('pendulum.txt'):
    print line

As we already know, line is a dummy variable, sometimes called the loop variable, and it is not a keyword. We could have used any other variable name, but line seems meaningful enough.

Instead of just printing the lines, let us append them to a list, line_list. We first initialize an empty list, line_list.

line_list = [ ]

Let us then read the file line-by-line and then append each of the lines, to the list. We could, as usual close the file using f.close and re-open it. But, this time, let’s leave alone the file object f and directly open the file within the for statement. This will save us the trouble of closing the file, each time we open it.

for line in open('pendulum.txt'):
    line_list.append(line)

Let us see what line_list contains.

line_list

Notice that line_list is a list of the lines in the file, along with the newline characters. If you noticed, pend_list did not contain the newline characters, because the string pend was split on the newline characters.

Let us now look at how to parse data, learn some string operations to parse files and get data out of them, and data-type conversions.

We have a file containing a huge number of records. Each record corresponds to the information of a student.

A;010002;ANAND R;058;037;42;35;40;212;P;;

Each record consists of fields seperated by a ”;”. The first record is region code, then roll number, then name, marks of second language, first language, maths, science and social, total marks, pass/fail indicatd by P or F and finally W if withheld and empty otherwise.

Our job is to calculate the arithmetic mean of all the maths marks in the region B.

Now what is parsing data.

From the input file, we can see that the data we have is in the form of text. Parsing this data is all about reading it and converting it into a form which can be used for computations – in our case, sequence of numbers.

Let us learn about tokenizing strings or splitting a string into smaller units or tokens. Let us define a string first.

line = "parse this           string"

We are now going to split this string on whitespace.

line.split()

As you can see, we get a list of strings. Which means, when split is called without any arguments, it splits on whitespace. In simple words, all the spaces are treated as one big space.

split also can split on a string of our choice. This is acheived by passing that as an argument. But first lets define a sample record from the file.

record = "A;015163;JOSEPH RAJ S;083;042;47;AA;72;244;;;"
record.split(';')

We can see that the string is split on ‘;’ and we get each field seperately. We can also observe that an empty string appears in the list since there are two semi colons without anything in between.

To recap, split splits on whitespace if called without an argument and splits on the given argument if it is called with an argument.

Now that we know how to split a string, we can split the record and retrieve each field seperately. But there is one problem. The region code “B” and a “B” surrounded by whitespace are treated as two different regions. We must find a way to remove all the whitespace around a string so that “B” and a “B” with white spaces are dealt as same.

This is possible by using the strip method of strings. Let us define a string,

word = "     B    "
word.strip()

We can see that strip removes all the whitespace around the sentence.

The splitting and stripping operations are done on a string and their result is also a string. Hence the marks that we have are still strings and mathematical operations are not possible on them. We must convert them into numbers (integers or floats), before we can perform mathematical operations on them.

We have seen that, it is possible to convert float into integers using int. We shall now convert strings into floats.

mark_str = "1.25"
mark = float(mark_str)
type(mark_str)
type(mark)

We can see that string, mark_str is converted to a float. We can perform mathematical operations on them now.

Now that we have all the machinery required to parse the file, let us solve the problem. We first read the file line by line and parse each record. We see if the region code is B and store the marks accordingly.

math_B = [] # an empty list to store the marks
for line in open("sslc1.txt"):
    fields = line.split(";")

    reg_code = fields[0]
    reg_code_clean = reg_code.strip()

    math_mark_str = fields[5]
    math_mark = float(math_mark_str)

    if reg_code == "B":
        math_B.append(math_mark)

Now we have all the maths marks of region “B” in the list math_marks_B. To get the mean, we just have to sum the marks and divide by the length.

math_B_mean = sum(math_B) / len(math_B)
math_B_mean

Functions

We are now going to learn about functions in Python — how to define them, passing arguments to them, docstrings, and return values.

While writing code, fewer lines of code is a good thing, since it reduces the scope of error. Also, we would like to reduce duplication of code and abstract out pieces of code, wherever possible. Functions allow us to do all of this.

Now let us at functions in a greater detail,

Consider a mathematical function f(x) = x^2. Here x is a variable and with different values of x the value of function will change. When x is one f(1) will return the value 1 and f(2) will return us the value 4. Let us now see how to define the function f(x) in Python.

def f(x):
    return x*x

Well that defined the function, so before learning what we did let us see if it returns the expected values, try,

f(1)
f(2)

Yes, it returned 1 and 4 respectively. And now let us see what we did. We wrote two lines: The first line def f(x): defines the name of the function and specifies the parameters to the function. The second line specifies what the function is supposed to return. def is a keyword and f is the name of the function and x the parameter of the function.

You can also have functions without any arguments.

Let us define a new function called greet which will print Hello World.

def greet():
    print "Hello World!"

now try calling the function,

greet()

Well that is a function which takes no arguments. Also note that it is not mandatory for a function to return values. The function greet isn’t taking any argument. Also, it is not returning any value explicitly. But for such functions, Python returns a None object by default

Now let us see how to write functions with more than one argument.

def avg(a, b):
    return (a + b)/2

If we want a function to accept more arguments, we just list them separated with a comma between the parenthesis after the function’s name in the def line.

It is always a good practice to document the code that we write, and for a function we define we should write an abstract of what the function does, and that is called a docstring.

Let us modify the function avg and add docstring to it.

def avg(a,b):
    """ avg takes two numbers as input, and
    returns their average"""

    return (a+b)/2

Note that docstrings are entered in the line immediately after the function definition and put as a triple quoted string.

Now we try this in the IPython interpreter,

avg?

it displays the docstring as we gave it. Thus docstring has practical utility also, and is not just a good “practice”.

Try to do this,

greet?

It doesn’t have a docstring associated with it. Also we cannot infer anything from the function name, and thus we are forced to read the code to understand about the function.

Let’s now write a function named circle which returns the area and perimeter of a circle given radius r.

The function needs to return two values instead of just one which was being returned until now.

def circle(r):
    """returns area and perimeter of a circle given radius r"""
    pi = 3.14
    area = pi * r * r
    perimeter = 2 * pi * r
    return area, perimeter

Similarly, you could have a function returning three or four or any number of values. A Python function can return any number of values and there is not restriction on it.

Let us call the function circle as,

a, p = circle(6)
print a
print p

Let us now do a little code reading, as opposed to writing.

What does the function what do?

def what( n ):
    if n < 0: n = -n
    while n > 0:
        if n % 2 == 1:
            return False
        n /= 10
    return True

The function returns True if all the digits of the number n are even, otherwise it returns False.

def even_digits( n ):
   """returns True if all the digits in the number n are even,
   returns False if all the digits in the number n are not even"""
    if n < 0: n = -n
    while n > 0:
        if n % 2 == 1:
            return False
        n /= 10
    return True

Now one more code reading exercise,

What does this function what do?

def what( n ):
    i = 1
    while i * i < n:
        i += 1
    return i * i == n, i

The function returns True and the square root of n if n is a perfect square, otherwise it returns False and the square root of the next perfect square.

def is_perfect_square( n ):
    """returns True and square root of n, if n is a perfect square,
    otherwise returns False and the square root of the
    next perfect square"""
    i = 1
    while i * i < n:
        i += 1
    return i * i == n, i

Default & Keyword Arguments

Let us now look at specifying default arguments to functions when defining them and calling functions using keyword arguments.

Let’s use the round function as an example to understand what a default value of an argument means. Let’s type the following expressions in the terminal.

round(2.484)

round(2.484, 2)

Both the first expression and the second are calls to the round function, but the first calls it with only one argument and the second calls it with two arguments. By observing the output, we can guess that the first one is equivalent to call with the second argument being 0. 0 is the default value of the argument.

s.split() # split on spaces.
s.split(';') # split on ';'

range(10) # returns a list with numbers from 0 to 9
range(1, 10) # returns a list with numbers from 1 to 9
range(1, 10, 2) # returns a list with odd numbers from 1 to 9

Let’s now define a simple function that uses default arguments. We define a simple function that prints a welcome message to a person, given a greeting and his/her name.

def welcome(greet, name="World"):
    print greet, name

Let us first call the function with two arguments, one for greet and other for name.

welcome("Hi", "Guido")

We get the expected welcome message, “Hi Guido”.

Now let us call the function with just one argument “Hello”.

welcome("Hello")

“Hello” is treated as the greet and we get “Hello World” as the output. “World” is the default value for the argument name.

If we redefined the function welcome, by interchanging it’s arguments and placed the name argument with it’s default value of “World” before the greet argument, what happens?

def welcome(name="World", greet):
    print greet, name

We get an error that reads SyntaxError: non-default argument follows default argument. When defining a function all the argument with default values should come at the end.

Let us now learn what keyword arguments or named arguments are. We shall refer to them as keyword arguments, henceforth.

When you are calling functions in Python, you don’t need to remember the order in which to pass the arguments. Instead, you can use the name of the argument to pass it a value. Let us understand this using the welcome function that we have been using all along. Let us call it in different ways and observe the output to see how keyword arguments work.

welcome()
welcome("Hello", "James")

welcome("Hi", name="Guido")

When no keyword is specified, the arguments are allotted based on their position. So, “Hi” is the value of the argument greet and name is passed the value “Guido”.

welcome(name="Guido", greet="Hey! ")

When keyword arguments are used, the arguments can be called in any order.

welcome(name="Guido", "Hey")

This call returns an error that reads, non keyword arg after keyword arg. Python expects all the keyword to be present towards the end.

That brings us to the end of what we wanted to learn about keyword arguments.

Before defining a function of your own, make sure that you check the standard library, for a similar function. Python is popularly called a “Batteries included” language, for the huge library that comes along with it. Refer here.

Variable scope

Before we end the discussion on functions, a short note on the scope of variables in Python is in order.

Arguments passed to a function are local. They are not available outside of the function.

def change(q):
    q = 10
    print q

change(1)
print q

The variables used inside a function definition are considered to be “local” variables and their existence is restricted to within the function. Global variables are those variables, which are accessible from anywhere within a Python program.

Variables that are assigned to within a function, are treated as local variables by default.

n = 5

def change():
    n = 10
    print n

change()
print n

As you can see, the value of n hasn’t changed after the function change was called.

To assign to global variables (or variables which can be accessed from outside the function), we need to use the global statement. We could redefine the change function as shown below.

def change():
    global n
    n = 10
    print n

change()
print n

There is a subtle difference in the behavior when we assign not directly to a variable, but a list element or a list slice etc. In this case, Python looks up for the name, from the innermost scope (the function), outwards, until it finds the name.

For example

name = ['Mr.', 'Steve', 'Gosling']

def change_name():
    name[0] = 'Dr.'

change_name()
print name

As, you can see, even though there was no variable name within the scope of the function change_name, calling it has changed the list name.

Also, let us tweak the examples above to learn about the way values are passed to functions.

n = 5

def change(n):
    n = 10
    print "n = %s, inside change" %n

change(n)
print n
name = ['Mr.', 'Steve', 'Gosling']

def change_name(n):
    n[0] = 'Dr.'
    print "n = %s, inside change_name" %n

change_name(n)
print name

Notice that the value of n does not get changed in the first case, because numbers are immutable datatypes and they cannot be modified. In the second case when a list was passed to the function change_name, it is changed because a list is mutable and it’s first element is chaned by the function.

That brings us to the end of this section on functions. We have learnt how to define functions, use them with default values and keyword arguments. We have also looked briefly at variables and their scopes.

We shall now look at a few more datatypes available in Python, namely, tuples, dictionaries and sets. Let us start with tuples.

Tuples

We shall learn

  • what are tuples
  • their similarities and dissimilarities with lists
  • why are they needed

Let’s get started by defining a tuple. A tuple is defined by enclosing parentheses around a sequence of items seperated by commas. It is similar to defining a list except that parentheses are used instead of square brackets.

t = (1, 2.5, "hello", -4, "world", 1.24, 5)
t

defines a tuple.

It is not always necessary to use parenthesis around a tuple

::

a = 1, 2, 3 a (1, 2, 3)

b = 1, b (1,)

The items in the tuple are indexed using numbers and can be accessed by using their position.

t[3]

prints -4 which is the fourth item of the tuple.

t[1:5:2]

prints the corresponding slice

This is the behaviour similar as to lists. But the difference can be seen when we try to change an element in the tuple.

t[2] = "Hello"

We can see that, it raises an error saying tuple does not support item assignment. Tuples are immutable, and cannot be changed after creation.

Then, what’s the use of tuples?

We shall understand that soon. But let us look at a simple problem of swapping values.

a = 5 and b = 7. swap the values of a and b

We define the two values

a = 5
b = 7

a
b

Traditionally, we swap them using a temporary variable.

temp = a
a = b
b = temp

a
b

The Python way, would be

a
b

a, b = b, a

a
b

We see that the values are swapped. This idiom works for different data-types also.

a = 2.5
b = "hello"

a
b

Moreover this type of behaviour is something that feels natural and you’d expect to happen.

This is possible because of the immutability of tuples. This process is called tuple packing and unpacking.

Let us first see what is tuple packing. Type

5,

What we see is a tuple with one element.

5, "hello", 2.5

Now it is a tuple with three elements.

So when we are actually typing two or more elements seperated by commas, those elements are packed into a tuple.

When you type

a, b = b, a

First the values of b and a are packed into a tuple on the right side and then unpacked into the variables a and b.

Immutability of tuples ensures that the values are not changed during the packing and unpacking.

That brings us to the end of our discussion of tuples. Let us now look at dictionaries.

Dictionaries

A dictionary in general, are designed to be able to look up meanings of words. Similarly, the Python dictionaries are also designed to look up for a specific key and retrieve the corresponding value. Dictionaries are data structures that provide key-value mappings. Dictionaries are similar to lists except that instead of the values having integer indexes, dictionaries have keys or strings as indexes.

We shall now look at creating dictionaries, accessing elements of dictionaries, checking for presence of elements and iterating over the elements.

Let us start by creating an empty dictionary, type the following in your IPython interpreter.

mt_dict = {}

Notice that curly braces are used define dictionaries.

Now let us see how to create a non-empty dictionary,

extensions = {'jpg' : 'JPEG Image',
              'py' : 'Python script',
              'html' : 'Html document',
              'pdf' : 'Portable Document Format'}

Notice that each key-value pair is separated by a comma, and each key and value are separated using a colon.

Here, we defined four entries in the dictionary extensions. The keys are jpg, py, html, and pdf.

Simply type,

extensions

in the interpreter to see the content of the dictionary. Notice that in dictionaries the order cannot be predicted and you can see that the values are not in the order that we entered in.

Like in lists, the elements in a dictionary can be accessed using the index, here the index is the key. Try,

print extensions['jpg']

It printed JPEG Image. And now try,

print extensions['zip']

As expected it gave us an error. Obviously, our dictionary didn’t have any key ‘zip’, and that’s what the error message says.

Well that was about creating dictionaries, now how do we add or delete items.

extensions['cpp'] = 'C++ code'

Adds a new key value pair, cpp : C++ code

We delete items using the del keyword

del extension['pdf']

Let us check the content of the dictionary now,

extensions

So the changes have been made. Now let us try one more thing,

extensions['cpp'] = 'C++ source code'
extensions

As you can see, it neither added a new thing nor gave an error, but it simply replaced the existing value with the new one.

Now let us learn how to check if a particular key is present in the dictionary. For that we can use in,

'py' in extensions
'odt' in extensions

It will return True if the key is found in the dictionary, and will return False if key is not present. Note that we can check only for container-ship of keys in dictionaries and not values.

Now let us see how to retrieve the keys and values. We can use the method keys() for getting a list of the keys in a particular dictionary and the method values() for getting a list of values. Let us try them,

extensions.keys()

It returned the list of keys in the dictionary extensions. And now the values,

extensions.values()

It returned the list of values in the dictionary.

Now let us print the data in the dictionary. We can use for loop to iterate.

for each in extensions.keys():
    print each, "-->", extensions[each]

This brings us to the end of our discussion on dictionaries. Let us now look at sets.

Sets

We shall look at,

  • sets
  • operations on sets

Sets are collections of unique elements. set datastructure in Python provides an implementation of this.

Lets look at how to input sets.

a_list = [1, 2, 1, 4, 5, 6, 2]
a = set(a_list)
a

We can see that duplicates are removed and the set contains only unique elements.

f10 = set([1, 2, 3, 5, 8])
p10 = set([2, 3, 5, 7])
  • f10 is the set of fibonacci numbers from 1 to 10.
  • p10 is the set of prime numbers from 1 to 10.

Various operations that we do on sets are possible here also.

The | (pipe) character stands for union

f10 | p10

gives us the union of f10 and p10

The & (ampersand) character stands for intersection.

f10 & p10

gives the intersection

similarly,

f10 - p10

gives all the elements that are in f10 but not in p10

f10 ^ p10

is all the elements in f10 union p10 but not in f10 intersection p10. In mathematical terms, it gives the symmectric difference.

Sets also support checking of subsets.

b = set([1, 2])
b < f10

gives a True since b is a proper subset of f10.

Similarly,

f10 < f10

gives a False since f10 is not a proper subset.

Where as,

f10 <= f10

gives True since every set is a subset of itself.

Sets can be iterated upon just like lists and tuples.

for i in f10:
    print i,

prints the elements of f10.

The length and containership check on sets is similar as in lists and tuples.

len(f10)

shows 5. And

1 in f10
4 in f10

prints True and False respectively

The order in which elements are organised in a set is not to be relied upon. There is no ordering of elements of a set. Sets do not support indexing and hence slicing and striding do not make sense, either.

Here’s an example that shows the use of sets.

Given a list of marks, marks = [20, 23, 22, 23, 20, 21, 23] list all the duplicates

Duplicates marks are the marks left out when we remove each element of the list exactly one time.

marks = [20, 23, 22, 23, 20, 21, 23]
marks_set = set(marks)
for mark in marks_set:
    marks.remove(mark)

# we are now left with only duplicates in the list marks
duplicates = set(marks)

This brings us to the end of our discussion on sets.

Exercises

  1. Round a float to the nearest integer using int().

  2. What does this do? round(amount * 10)/10.0. How to round it to the nearest 5 paise?

  3. Print out the fibonacci sequence less than 30

  4. Write a program that prints the numbers from 1 to 100. But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. For numbers which are multiples of both three and five print “FizzBuzz”. This is famously known as the FizzBuzz test.

  5. Write a program that displays all three digit numbers that are equal to the sum of the cubes of their digits. That is, print numbers abc that have the property abc=a3+b3+c3 These are called Armstrong numbers.

  6. Collatz sequence

    1. Start with an arbitrary (positive) integer.
    2. If the number is even, divide by 2; if the number is odd multiply by 3 and add 1.
    3. Repeat the procedure with the new number.
    4. There is a cycle of 4, 2, 1 at which the procedure loops.

    Write a program that accepts the starting value and prints out the Collatz sequence.

  7. Kaprekar’s constant

    1. Take a four digit number–with at least two digits different.
    2. Arrange the digits in ascending and descending order, giving A and D respectively.
    3. Leave leading zeros in A!
    4. Subtract A from D.
    5. With the result, repeat from step 2.

    Write a program to accept a 4-digit number and display the progression to Kaprekar’s constant.

  8. Write a function to return the gcd of two numbers.

  9. Write a program to find Primitive Pythagorean Triads A pythagorean triad (a,b,c) has the property a2+b2=c2. By primitive we mean triads that do not ‘depend’ on others. For example, (4,3,5) is a variant of (3,4,5) and hence is not primitive. And (10,24,26) is easily derived from (5,12,13) and should not be displayed by our program. Write a program to print primitive pythagorean triads. The program should generate all triads with a, b values in the range 0—100

  10. Write a program that generates a list of all four digit numbers that have all their digits even and are perfect squares. For example, the output should include 6400 but not 8100 (one digit is odd) or 4248 (not a perfect square).

  11. The aliquot of a number is defined as: the sum of the proper of the number.

    For example, the aliquot(12) = 1 + 2 + 3 + 4 + 6 = 16.

    Write a function that returns the aliquot number of a given number.

  12. A pair of numbers (a, b) is said to be amicable if the aliquot number of a is b and the aliquot number of b is a.

    Example: 220, 284

    Write a program that prints all five digit amicable pairs.

  13. Given an empty chessboard and one Bishop placed in any square, say (r, c), generate the list of all squares the Bishop could move to.

  14. Write a program to display the following pyramid. The number of lines in the pyramid should not be hard-coded. It should be obtained from the user. The pyramid should appear as close to the centre of the screen as possible.

       *
      ***
     *****
    *******
  15. Write a program to display the following pyramid. The number of lines in the pyramid should not be hard-coded. It should be obtained from the user. The pyramid should appear as close to the centre of the screen as possible.

       *
      * *
     * * *
    * * * *
  16. Write a program to display the following pyramid. The number of lines has to be a parameter obtained from the user. The pyramid must appear aligned to the left edge of the screen.

    1
    2 2
    3 3 3
    4 4 4 4
  17. Write a program to display the following pyramid. The number of lines has to be a parameter obtained from the user. The pyramid must appear aligned to the left edge of the screen.

    1
    2   4
    3   6   9
    4   8  12  16
    5  10  15  20  25
  18. Write a program to display the following output. The last number where the program will stop printing has to be a parameter obtained from the user. The pyramid must appear aligned to the left edge of the screen. Note that depending on the last number, the base of the pyramid may be smaller than the line above it.

     1
     2   3
     4   5   6
     7   8   9  10
    11  12
  19. Given a string like, “1, 3-7, 12, 15, 18-21”, produce the list [1,3,4,5,6,7,12,15,18,19,20,21]

  20. You are given date strings of the form “29, Jul 2009”, or “4 January 2008”. In other words a number a string and another number, with a comma sometimes separating the items.Write a function that takes such a string and returns a tuple (yyyy, mm, dd) where all three elements are ints.

  21. Count word frequencies in a file.

  22. Given a dictionary of the names of students and their marks, identify how many duplicate marks are there? and what are these?

  23. Given a string of the form “4-7, 9, 12, 15” find the numbers missing in this list for a given range.