summaryrefslogtreecommitdiff
path: root/basic_python
diff options
context:
space:
mode:
Diffstat (limited to 'basic_python')
-rw-r--r--basic_python/exercises.rst110
-rw-r--r--basic_python/func.rst753
-rw-r--r--basic_python/handOut.rst6
-rw-r--r--basic_python/interim_assessment.rst3
-rw-r--r--basic_python/intro.rst942
-rw-r--r--basic_python/io_files_parsing.rst386
-rw-r--r--basic_python/list_tuples.rst526
-rw-r--r--basic_python/module_plan.rst83
-rw-r--r--basic_python/oop.rst114
-rw-r--r--basic_python/python.tex54
-rw-r--r--basic_python/slides/func.tex262
-rw-r--r--basic_python/slides/intro.tex477
-rw-r--r--basic_python/slides/io_files_parsing.tex239
-rw-r--r--basic_python/slides/strings_loops_lists.tex456
-rw-r--r--basic_python/slides/tmp.tex1
-rw-r--r--basic_python/slides/tuples_dicts_sets.tex256
-rw-r--r--basic_python/strings_dicts.rst475
-rw-r--r--basic_python/strings_loops_lists.rst768
-rw-r--r--basic_python/tuples_dicts_sets.rst426
19 files changed, 4346 insertions, 1991 deletions
diff --git a/basic_python/exercises.rst b/basic_python/exercises.rst
new file mode 100644
index 0000000..83b1315
--- /dev/null
+++ b/basic_python/exercises.rst
@@ -0,0 +1,110 @@
+Exercises
+=========
+
+1. Round a float to the nearest integer using ``int()``.
+
+#. What does this do? round(amount * 10)/10.0. How to round it to the nearest
+ 5 paise?
+
+#. Print out the fibonacci sequence less than 30
+
+#. 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 :math:`$abc$`
+ that have the property :math:`$abc = a^3 + b^3 + c^3$` These are called
+ :math:`$Armstrong$` numbers.
+
+#. Collatz sequence
+
+ #. Start with an arbitrary (positive) integer.
+ #. If the number is even, divide by 2; if the number is odd multiply by 3
+ and add 1.
+ #. Repeat the procedure with the new number.
+ #. 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.
+
+
+#. Kaprekar’s constant
+
+ #. Take a four digit number–with at least two digits different.
+ #. Arrange the digits in ascending and descending order, giving A and D
+ respectively.
+ #. Leave leading zeros in A!
+ #. Subtract A from D.
+ #. With the result, repeat from step 2.
+
+ Write a program to accept a 4-digit number and display the progression to
+ Kaprekar’s constant.
+
+#. Write a program that prints the following pyramid on the screen.
+
+ ::
+
+ 1
+ 2 2
+ 3 3 3
+ 4 4 4 4
+
+
+ The number of lines must be obtained from the user as input. When can your
+ code fail?
+
+#. Write a function to return the gcd of two numbers.
+
+#. Write a program to find Primitive Pythagorean Triads A pythagorean triad
+ :math:`$(a,b,c)$` has the property :math:`$a^2 + b^2 = c^2$`. 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
+
+#. 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).
+
+
+#. 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.
+
+#. 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.
+
+#. 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.
+
+#. 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]``
+
+#. 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.
+
+#. Count word frequencies in a file.
+
+#. Given a dictionary of the names of students and their marks, identify how
+ many duplicate marks are there? and what are these?
+
+#. Given a string of the form "4-7, 9, 12, 15" find the numbers missing in
+ this list for a given range.
+
+
+..
+ Local Variables:
+ mode: rst
+ indent-tabs-mode: nil
+ sentence-end-double-space: nil
+ fill-column: 77
+ End:
+
diff --git a/basic_python/func.rst b/basic_python/func.rst
index df3452a..bd9074b 100644
--- a/basic_python/func.rst
+++ b/basic_python/func.rst
@@ -1,339 +1,420 @@
-Functional Approach
-===================
+Functions
+=========
-*Functions* allow us to enclose a set of statements and call the function again
-and again instead of repeating the group of statements everytime. Functions also
-allow us to isolate a piece of code from all the other code and provides the
-convenience of not polluting the global variables.
-
-*Function* in python is defined with the keyword **def** followed by the name
-of the function, in turn followed by a pair of parenthesis which encloses the
-list of parameters to the function. The definition line ends with a ':'. The
-definition line is followed by the body of the function intended by one block.
-The *Function* must return a value::
-
- def factorial(n):
- fact = 1
- for i in range(2, n):
- fact *= i
-
- return fact
-
-The code snippet above defines a function with the name factorial, takes the
-number for which the factorial must be computed, computes the factorial and
-returns the value.
-
-A *Function* once defined can be used or called anywhere else in the program. We
-call a fucntion with its name followed by a pair of parenthesis which encloses
-the arguments to the function.
-
-The value that function returns can be assigned to a variable. Let's call the
-above function and store the factorial in a variable::
-
- fact5 = factorial(5)
-
-The value of fact5 will now be 120, which is the factorial of 5. Note that we
-passed 5 as the argument to the function.
-
-It may be necessary to document what the function does, for each of the function
-to help the person who reads our code to understand it better. In order to do
-this Python allows the first line of the function body to be a string. This
-string is called as *Documentation String* or *docstring*. *docstrings* prove
-to be very handy since there are number of tools which can pull out all the
-docstrings from Python functions and generate the documentation automatically
-from it. *docstrings* for functions can be written as follows::
-
- def factorial(n):
- 'Returns the factorial for the number n.'
- fact = 1
- for i in range(2, n):
- fact *= i
-
- return fact
-
-An important point to note at this point is that, a function can return any
-Python value or a Python object, which also includes a *Tuple*. A *Tuple* is
-just a collection of values and those values themselves can be of any other
-valid Python datatypes, including *Lists*, *Tuples*, *Dictionaries* among other
-things. So effectively, if a function can return a tuple, it can return any
-number of values through a tuple
-
-Let us write a small function to swap two values::
-
- def swap(a, b):
- return b, a
-
- c, d = swap(a, b)
-
-Function scope
----------------
-The variables used inside the function are confined to the function's scope
-and doesn't pollute the variables of the same name outside the scope of the
-function. Also the arguments passed to the function are passed by-value if
-it is of basic Python data type::
-
- def cant_change(n):
- n = 10
-
- n = 5
- cant_change(n)
-
-Upon running this code, what do you think would have happened to value of n
-which was assigned 5 before the function call? If you have already tried out
-that snippet on the interpreter you already know that the value of n is not
-changed. This is true of any immutable types of Python like *Numbers*, *Strings*
-and *Tuples*. But when you pass mutable objects like *Lists* and *Dictionaries*
-the values are manipulated even outside the function::
-
- >>> def can_change(n):
- ... n[1] = James
- ...
-
- >>> name = ['Mr.', 'Steve', 'Gosling']
- >>> can_change(name)
- >>> name
- ['Mr.', 'James', 'Gosling']
-
-If nothing is returned by the function explicitly, Python takes care to return
-None when the funnction is called.
-
-Default Arguments
------------------
-
-There may be situations where we need to allow the functions to take the
-arguments optionally. Python allows us to define function this way by providing
-a facility called *Default Arguments*. For example, we need to write a function
-that returns a list of fibonacci numbers. Since our function cannot generate an
-infinite list of fibonacci numbers, we need to specify the number of elements
-that the fibonacci sequence must contain. Suppose, additionally, we want to the
-function to return 10 numbers in the sequence if no option is specified we can
-define the function as follows::
-
- def fib(n=10):
- fib_list = [0, 1]
- for i in range(n - 2):
- next = fib_list[-2] + fib_list[-1]
- fib_list.append(next)
- return fib_list
-
-When we call this function, we can optionally specify the value for the
-parameter n, during the call as an argument. Calling with no argument and
-argument with n=5 returns the following fibonacci sequences::
-
- fib()
- [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
- fib(5)
- [0, 1, 1, 2, 3]
-
-Keyword Arguments
------------------
-
-When a function takes a large number of arguments, it may be difficult to
-remember the order of the parameters in the function definition or it may
-be necessary to pass values to only certain parameters since others take
-the default value. In either of these cases, Python provides the facility
-of passing arguments by specifying the name of the parameter as defined in
-the function definition. This is known as *Keyword Arguments*.
-
-In a function call, *Keyword arguments* can be used for each argument, in the
-following fashion::
-
- argument_name=argument_value
- Also denoted as: keyword=argument
-
- def wish(name='World', greetings='Hello'):
- print "%s, %s!" % (greetings, name)
-
-This function can be called in one of the following ways. It is important to
-note that no restriction is imposed in the order in which *Keyword arguments*
-can be specified. Also note, that we have combined *Keyword arguments* with
-*Default arguments* in this example, however it is not necessary::
-
- wish(name='Guido', greetings='Hey')
- wish(greetings='Hey', name='Guido')
-
-Calling functions by specifying arguments in the order of parameters specified
-in the function definition is called as *Positional arguments*, as opposed to
-*Keyword arguments*. It is possible to use both *Positional arguments* and
-*Keyword arguments* in a single function call. But Python doesn't allow us to
-bungle up both of them. The arguments to the function, in the call, must always
-start with *Positional arguments* which is in turn followed by *Keyword
-arguments*::
-
- def my_func(x, y, z, u, v, w):
- # initialize variables.
- ...
- # do some stuff
- ...
- # return the value
-
-It is valid to call the above functions in the following ways::
-
- my_func(10, 20, 30, u=1.0, v=2.0, w=3.0)
- my_func(10, 20, 30, 1.0, 2.0, w=3.0)
- my_func(10, 20, z=30, u=1.0, v=2.0, w=3.0)
- my_func(x=10, y=20, z=30, u=1.0, v=2.0, w=3.0)
-
-Following lists some of the invalid calls::
-
- my_func(10, 20, z=30, 1.0, 2.0, 3.0)
- my_func(x=10, 20, z=30, 1.0, 2.0, 3.0)
- my_func(x=10, y=20, z=30, u=1.0, v=2.0, 3.0)
-
-Parameter Packing and Unpacking
--------------------------------
-
-The positional arguments passed to a function can be collected in a tuple
-parameter and keyword arguments can be collected in a dictionary. Since keyword
-arguments must always be the last set of arguments passed to a function, the
-keyword dictionary parameter must be the last parameter. The function definition
-must include a list explicit parameters, followed by tuple paramter collecting
-parameter, whose name is preceded by a *****, for collecting positional
-parameters, in turn followed by the dictionary collecting parameter, whose name
-is preceded by a ****** ::
-
- def print_report(title, *args, **name):
- """Structure of *args*
- (age, email-id)
- Structure of *name*
- {
- 'first': First Name
- 'middle': Middle Name
- 'last': Last Name
- }
- """
-
- print "Title: %s" % (title)
- print "Full name: %(first)s %(middle)s %(last)s" % name
- print "Age: %d\nEmail-ID: %s" % args
-
-The above function can be called as. Note, the order of keyword parameters can
-be interchanged::
-
- >>> print_report('Employee Report', 29, 'johny@example.com', first='Johny',
- last='Charles', middle='Douglas')
- Title: Employee Report
- Full name: Johny Douglas Charles
- Age: 29
- Email-ID: johny@example.com
-
-The reverse of this can also be achieved by using a very identical syntax while
-calling the function. A tuple or a dictionary can be passed as arguments in
-place of a list of *Positional arguments* or *Keyword arguments* respectively
-using ***** or ****** ::
-
- def print_report(title, age, email, first, middle, last):
- print "Title: %s" % (title)
- print "Full name: %s %s %s" % (first, middle, last)
- print "Age: %d\nEmail-ID: %s" % (age, email)
-
- >>> args = (29, 'johny@example.com')
- >>> name = {
- 'first': 'Johny',
- 'middle': 'Charles',
- 'last': 'Douglas'
- }
- >>> print_report('Employee Report', *args, **name)
- Title: Employee Report
- Full name: Johny Charles Douglas
- Age: 29
- Email-ID: johny@example.com
-
-Nested Functions and Scopes
+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
---------------------------
-Python allows nesting one function inside another. This style of programming
-turns out to be extremely flexible and powerful features when we use *Python
-decorators*. We will not talk about decorators is beyond the scope of this
-course. If you are interested in knowing more about *decorator programming* in
-Python you are suggested to read:
-
-| http://avinashv.net/2008/04/python-decorators-syntactic-sugar/
-| http://personalpages.tds.net/~kent37/kk/00001.html
-
-However, the following is an example for nested functions in Python::
-
- def outer():
- print "Outer..."
- def inner():
- print "Inner..."
- print "Outer..."
- inner()
-
- >>> outer()
-
-map, reduce and filter functions
---------------------------------
-
-Python provides several built-in functions for convenience. The **map()**,
-**reduce()** and **filter()** functions prove to be very useful with sequences like
-*Lists*.
-
-The **map** (*function*, *sequence*) function takes two arguments: *function*
-and a *sequence* argument. The *function* argument must be the name of the
-function which in turn takes a single argument, the individual element of the
-*sequence*. The **map** function calls *function(item)*, for each item in the
-sequence and returns a list of values, where each value is the value returned
-by each call to *function(item)*. **map()** function allows to pass more than
-one sequence. In this case, the first argument, *function* must take as many
-arguments as the number of sequences passed. This function is called with each
-corresponding element in the each of the sequences, or **None** if one of the
-sequence is exhausted::
-
- def square(x):
- return x*x
-
- >>> map(square, [1, 2, 3, 4])
- [1, 4, 9, 16]
-
- def mul(x, y):
- return x*y
-
- >>> map(mul, [1, 2, 3, 4], [6, 7, 8, 9])
-
-The **filter** (*function*, *sequence*) function takes two arguments, similar to
-the **map()** function. The **filter** function calls *function(item)*, for each
-item in the sequence and returns all the elements in the sequence for which
-*function(item)* returned True::
-
- def even(x):
- if x % 2:
- return True
- else:
- return False
-
- >>> filter(even, range(1, 10))
- [1, 3, 5, 7, 9]
-
-The **reduce** (*function*, *sequence*) function takes two arguments, similar to
-**map** function, however multiple sequences are not allowed. The **reduce**
-function calls *function* with first two consecutive elements in the sequence,
-obtains the result, calls *function* with the result and the subsequent element
-in the sequence and so on until the end of the list and returns the final result::
-
- def mul(x, y):
- return x*y
-
- >>> reduce(mul, [1, 2, 3, 4])
- 24
-
-List Comprehensions
-~~~~~~~~~~~~~~~~~~~
-
-List Comprehension is a convenvience utility provided by Python. It is a
-syntatic sugar to create *Lists*. Using *List Comprehensions* one can create
-*Lists* from other type of sequential data structures or other *Lists* itself.
-The syntax of *List Comprehensions* consists of a square brackets to indicate
-the result is a *List* within which we include at least one **for** clause and
-multiple **if** clauses. It will be more clear with an example::
-
- >>> num = [1, 2, 3]
- >>> sq = [x*x for x in num]
- >>> sq
- [1, 4, 9]
- >>> all_num = [1, 2, 3, 4, 5, 6, 7, 8, 9]
- >>> even = [x for x in all_num if x%2 == 0]
-
-The syntax used here is very clear from the way it is written. It can be
-translated into english as, "for each element x in the list all_num,
-if remainder of x divided by 2 is 0, add x to the list."
+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 <http://docs.python.org/library/functions.html>`_.
+
+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.
+
+..
+ Local Variables:
+ mode: rst
+ indent-tabs-mode: nil
+ sentence-end-double-space: nil
+ fill-column: 77
+ End:
+
+
diff --git a/basic_python/handOut.rst b/basic_python/handOut.rst
new file mode 100644
index 0000000..870c26e
--- /dev/null
+++ b/basic_python/handOut.rst
@@ -0,0 +1,6 @@
+.. include :: intro.rst
+.. include :: strings_loops_lists.rst
+.. include :: io_files_parsing.rst
+.. include :: func.rst
+.. include :: tuples_dicts_sets.rst
+
diff --git a/basic_python/interim_assessment.rst b/basic_python/interim_assessment.rst
deleted file mode 100644
index 6afc401..0000000
--- a/basic_python/interim_assessment.rst
+++ /dev/null
@@ -1,3 +0,0 @@
-Interim Assessment
-==================
-
diff --git a/basic_python/intro.rst b/basic_python/intro.rst
index c5298ee..3953db0 100644
--- a/basic_python/intro.rst
+++ b/basic_python/intro.rst
@@ -1,716 +1,584 @@
-============
-Basic Python
-============
-
-This document is intended to be handed out at the end of the workshop. It has
-been designed for Engineering students who are Python beginners and have basic
-programming skills. The focus is on basic numerics and plotting using Python.
-
-The system requirements:
- * Python - version 2.5.x or newer.
- * IPython
- * Text editor - scite, vim, emacs or whatever you are comfortable with.
-
Introduction
============
-The Python programming language was created by a dutch named Guido van Rossum.
-The idea of Python was conceived in December 1989. The name Python has nothing
-to do with the reptilian, but its been named after the 70s comedy series
-"Monty Python's Flying Circus", since it happens to be Guido's favourite
-TV series.
+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.
-Current stable version of Python is 2.6.x, although Python 3.0 is also the stable
-version, it is not backwards compatible with the previous versions and is hence
-not entirely popular at the moment. This material will focus on the 2.6.x series.
-
-Python is licensed under the Python Software Foundation License (PSF License)
-which is GPL compatible Free Software license (excepting license version 1.6 and 2.0)
-It is a no strings attached license, which means the source code is free to modify
-and redistribute.
+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.
-The Python docs define Python as "Python is an interpreted, object-oriented,
-high-level programming language with dynamic semantics." A more detailed summary
-can be found at http://www.python.org/doc/essays/blurb.html. Python is a language that
-has been designed to help the programmer concentrate on solving the problem at hand
-and not worry about the programming language idiosyncrasies.
+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.
-Python is a highly cross platform compatible language on account of it being an
-interpreted language. It is highly scalable and hence has been adapted to run on
-the Nokia 60 series phones. Python has been designed to be readable and easy to use
+Why Python?
+-----------
-**Resources available for reference**
+* 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.
-* Web: http://www.python.org
-* Doc: http://www.python.org/doc
-* Free Tutorials:
- * Official Python Tutorial: http://docs.python.org/tut/tut.html
- * Byte of Python: http://www.byteofpython.info/
- * Dive into Python: http://diveintopython.org/
+* It is interactive and the interactive environment offers a very fast
+ edit-test-debug cycle.
-**Advantages of Python - Why Python??**
+* 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.
-* Python has been designed for readability and ease of use. Its been designed in
- such a fashion that it imposes readability on the programmer. Python does away
- with the braces and the semicolons and instead implements code blocks based on
- indentation, thus enhancing readability.
+* It handles memory management and takes the burden, of allocating and
+ de-allocating memory to variables off the programmer.
-* Python is a high level, interpreted, modular and object oriented language.
- Python performs memory management on its own, thus the programmer need not bother
- about allocating and deallocating memory to variables. Python provides extensibility
- by providing modules which can be easily imported similar to headers in C and
- packages in Java. Python is object oriented and hence provides all the object oriented
- characteristics such as inheritance, encapsulation and polymorphism.
+* It is a Batteries included language. It comes with a huge standard library
+ that allows us to do a wide range of tasks.
-* Python offers a highly powerful interactive programming interface in the form
- of the 'Interactive Interpreter' which will be discussed in more detail in the
- following sections.
+* It is object-oriented.
-* Python provides a rich standard library and an extensive set of modules. The
- power of Python modules can be seen in this slightly exaggerated cartoon
- http://xkcd.com/353/
+* It interfaces with other programming languages such as C, C++ and FORTRAN.
+ This allows us to use legacy code available in these languages.
-* Python interfaces well with most other programming languages such as C, C++
- and FORTRAN.
+* 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.
-Although, Python has one setback. Python is not fast as some of the compiled
-languages like C or C++. Yet, the amount of flexibility and power more than make
-up for this setback.
+The Interpreter
+===============
-The Python 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.
-The Interactive Interpreter
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+::
-Typing *python* at the shell prompt on any standard Unix/Gnu-Linux system and
-hitting the enter key fires up the Python 'Interactive Interpreter'. The Python
-interpreter is one of the most integral features of Python. The prompt obtained
-when the interactive interpreter is similar to what is shown below. The exact
-appearance might differ based on the version of Python being used. The ``>>>``
-thing shown is the python prompt. When something is typed at the prompt and the
-enter key is hit, the python interpreter interprets the command entered and
-performs the appropriate action. All the examples presented in this document are
-to be tried hands on, on the interactive interpreter.
+ 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
- Python 2.5.2 (r252:60911, Oct 5 2008, 19:24:49)
- [GCC 4.3.2] on linux2
- Type "help", "copyright", "credits" or "license" for more information.
- >>>
+``>>>`` is called the prompt and it implies that the interpreter is ready and
+waiting for your command!
-Lets try with an example, type ``print 'Hello, World!'`` at the prompt and hit
-the enter key.
+Let's write our first line of Python code, the ubiquitous ``Hello World``.
::
>>> print 'Hello, World!'
Hello, World!
-This example was quite straight forward, and thus we have written our first
-line of Python code. Now let us try typing something arbitrary at the prompt.
-For example:
+Typing ``print 'Hello World'`` and hitting enter, printed out the words
+*Hello World*.
-::
-
- >>> arbit word
- File "<stdin>", line 1
- arbit word
- ^
- SyntaxError: invalid syntax
- >>>
-
-The interpreter gave an error message saying that 'arbit word' was invalid
-syntax which is valid. The interpreter is an amazing tool when learning to
-program in Python. The interpreter provides a help function that provides the
-necessary documentation regarding all Python syntax, constructs, modules and
-objects. Typing *help()* at the prompt gives the following output:
+Let us now exit the interpreter. Hitting ``Ctrl-D``, exits the python
+interpreter.
-::
-
- >>> help()
-
- Welcome to Python 2.5! This is the online help utility.
-
- If this is your first time using Python, you should definitely check out
- the tutorial on the Internet at http://www.python.org/doc/tut/.
-
- Enter the name of any module, keyword, or topic to get help on writing
- Python programs and using Python modules. To quit this help utility and
- return to the interpreter, just type "quit".
-
- To get a list of available modules, keywords, or topics, type "modules",
- "keywords", or "topics". Each module also comes with a one-line summary
- of what it does; to list the modules whose summaries contain a given word
- such as "spam", type "modules spam".
-
- help>
+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
+----------------------------------------------------
-As mentioned in the output, entering the name of any module, keyword or topic
-will provide the documentation and help regarding the same through the online
-help utility. Pressing *Ctrl+d* exits the help prompt and returns to the
-python prompt.
+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.
-Let us now try a few examples at the python interpreter.
+invoking IPython
+~~~~~~~~~~~~~~~~
-Eg 1:
-::
-
- >>> print 'Hello, python!'
- Hello, python!
- >>>
-
-Eg 2:
-::
-
- >>> print 4321*567890
- 2453852690
- >>>
-
-Eg 3:
-::
-
- >>> 4321*567890
- 2453852690L
- >>>
+First let us see how to invoke the ``ipython`` interpreter.
+We type
::
-
- Note: Notice the 'L' at the end of the output. The 'L' signifies that the
- output of the operation is of type *long*. It was absent in the previous
- example because we used the print statement. This is because *print* formats
- the output before displaying.
-
-Eg 4:
-::
-
- >>> big = 12345678901234567890 ** 3
- >>> print big
- 1881676372353657772490265749424677022198701224860897069000
- >>>
-::
-
- This example is to show that unlike in C or C++ there is no limit on the
- value of an integer.
+ ipython
+
+at the terminal prompt to invoke the ipython interpreter.
-Try this on the interactive interpreter:
-``import this``
+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.
-*Hint: The output gives an idea of Power of Python*
+``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.
-*ipython* - An enhanced interactive Python interpreter
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If you get an error saying something like ``ipython is not installed``,
+install it and continue with the course.
-The power and the importance of the interactive interpreter was the highlight
-of the previous section. This section provides insight into the enhanced
-interpreter with more advanced set of features called **ipython**. Entering
-*ipython* at the shell prompt fires up the interactive interpreter.
+Let's try out the same ``Hello World`` in ``ipython``.
::
-
- $ ipython
- Python 2.5.2 (r252:60911, Oct 5 2008, 19:24:49)
- Type "copyright", "credits" or "license" for more information.
-
- IPython 0.8.4 -- An enhanced Interactive Python.
- ? -> Introduction and overview of IPython's features.
- %quickref -> Quick reference.
- help -> Python's own help system.
- object? -> Details about 'object'. ?object also works, ?? prints more.
-
- In [1]:
-
-This is the output obtained upon firing ipython. The exact appearance may
-change based on the Python version installed. The following are some of the
-various features provided by **ipython**:
-
- Suggestions - ipython provides suggestions of the possible methods and
- operations available for the given python object.
+
+ 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
-Eg 5:
-
::
-
- In [4]: a = 6
-
- In [5]: a.
- a.__abs__ a.__divmod__ a.__index__ a.__neg__ a.__rand__ a.__rmod__ a.__rxor__
- a.__add__ a.__doc__ a.__init__ a.__new__ a.__rdiv__ a.__rmul__ a.__setattr__
- a.__and__ a.__float__ a.__int__ a.__nonzero__ a.__rdivmod__ a.__ror__ a.__str__
- a.__class__ a.__floordiv__ a.__invert__ a.__oct__ a.__reduce__ a.__rpow__ a.__sub__
- a.__cmp__ a.__getattribute__ a.__long__ a.__or__ a.__reduce_ex__ a.__rrshift__ a.__truediv__
- a.__coerce__ a.__getnewargs__ a.__lshift__ a.__pos__ a.__repr__ a.__rshift__ a.__xor__
- a.__delattr__ a.__hash__ a.__mod__ a.__pow__ a.__rfloordiv__ a.__rsub__
- a.__div__ a.__hex__ a.__mul__ a.__radd__ a.__rlshift__ a.__rtruediv__
-
-In this example, we initialized 'a' (a variable - a concept that will be
-discussed in the subsequent sections.) to 6. In the next line when the *tab* key
-is pressed after typing '*a.*' ipython displays the set of all possible methods
-that are applicable on the object 'a' (an integer in this context). Ipython
-provides many such datatype specific features which will be presented in the
-further sections as and when the datatypes are introduced.
-
-Editing and running a python file
-=================================
-
-The previous sections focused on the use of the interpreter to run python code.
-While the interpeter is an excellent tool to test simple solutions and
-experiment with small code snippets, its main disadvantage is that everything
-written in the interpreter is lost once its quit. Most of the times a program is
-used by people other than the author. So the programs have to be available in
-some form suitable for distribution, and hence they are written in files. This
-section will focus on editing and running python files. Start by opening a text
-editor ( it is recommended you choose one from the list at the top of this page ).
-In the editor type down python code and save the file with an extension **.py**
-(python files have an extension of .py). Once done with the editing, save the
-file and exit the editor.
-
-Let us look at a simple example of calculating the gcd of 2 numbers using Python:
-
-**Creating the first python script(file)**
-::
-
- $ emacs gcd.py
- def gcd(x,y):
- if x % y == 0:
- return y
- return gcd(y, x%y)
-
- print gcd(72, 92)
-To run the script, open the shell prompt, navigate to the directory that
-contains the python file and run ``python <filename.py>`` at the prompt ( in this
-case filename is gcd.py )
+ 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.
-**Running the python script**
::
-
- $ python gcd.py
- 4
- $
-Another method to run a python script would be to include the line
+ 5 - 3
+ 7 - 4
+ 6 * 5
-``#! /usr/bin/python``
+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.
-at the beginning of the python file and then make the file executable by
+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``.
-$ chmod a+x *filename.py*
+Tab-completion
+~~~~~~~~~~~~~~
-Once this is done, the script can be run as a standalone program as follows:
+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.
-$ ./*filename.py*
+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.
-Basic Datatypes and operators in Python
-=======================================
+Now, let's see what these functions are used for. We will use the help
+features of ipython to find this out.
-Python provides the following set of basic datatypes.
+Help using ?
+~~~~~~~~~~~~
- * Numbers: int, float, long, complex
- * Strings
- * Boolean
+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.
-Numbers
-~~~~~~~
+As the documentation says, ``abs`` accepts a number as an input and returns
+it's absolute value.
-Numbers were introduced in the examples presented in the interactive interpreter
-section. Numbers include types as mentioned earlier viz., int (integers), float
-(floating point numbers), long (large integers), complex (complex numbers with
-real and imaginary parts). Python is not a strongly typed language, which means
-the type of a variable need not mentioned during its initialization. Let us look
-at a few examples.
+We say,
-Eg 6:
::
-
- >>> a = 1 #here a is an integer variable
-Eg 7:
-::
+ abs(-19)
+
+ abs(19)
- >>> lng = 122333444455555666666777777788888888999999999 #here lng is a variable of type long
- >>> lng
- 122333444455555666666777777788888888999999999L #notice the trailing 'L'
- >>> print lng
- 122333444455555666666777777788888888999999999 #notice the absence of the trailing 'L'
- >>> lng+1
- 122333444455555666666777777788888889000000000L
+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.
-Long numbers are the same as integers in almost all aspects. They can be used in
-operations just like integers and along with integers without any distinction.
-The only distinction comes during type checking (which is not a healthy practice).
-Long numbers are tucked with a trailing 'L' just to signify that they are long.
-Notice that in the example just lng at the prompt displays the value of the variable
-with the 'L' whereas ``print lng`` displays without the 'L'. This is because print
-formats the output before printing. Also in the example, notice that adding an
-integer to a long does not give any errors and the result is as expected. So for
-all practical purposes longs can be treated as ints.
+Let us look at the documentation of the ``round`` function.
-Eg 8:
::
- >>> fl = 3.14159 #fl is a float variable
- >>> e = 1.234e-4 #e is also a float variable, specified in the exponential form
- >>> a = 1
- >>> b = 2
- >>> a/b #integer division
- 0
- >>> a/fl #floating point division
- 0.31831015504887655
- >>> e/fl
- 3.9279473133031364e-05
+ 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.
-Floating point numbers, simply called floats are real numbers with a decimal point.
-The example above shows the initialization of a float variable. Shown also in this
-example is the difference between integer division and floating point division.
-'a' and 'b' here are integer variables and hence the division gives 0 as the quotient.
-When either of the operands is a float, the operation is a floating point division,
-and the result is also a float as illustrated.
+The function ``round``, rounds a number to a given precision.
-Eg 9:
::
- >>> cplx = 3 + 4j #cplx is a complex variable
- >>> cplx
- (3+4j)
- >>> print cplx.real #prints the real part of the complex number
- 3.0
- >>> print cplx.imag #prints the imaginary part of the complex number
- 4.0
- >>> print cplx*fl #multiplies the real and imag parts of the complex number with the multiplier
- (9.42477+12.56636j)
- >>> abs(cplx) #returns the absolute value of the complex number
- 5.0
+ round(2.48)
+ round(2.48, 1)
+ round(2.48, 2)
-Python provides a datatype for complex numbers. Complex numbers are initialized
-as shown in the example above. The *real* and *imag* operators return the real and
-imaginary parts of the complex number as shown. The *abs()* returns the absolute
-value of the complex number.
+ round(2.484)
+ round(2.484, 1)
+ round(2.484, 2)
-Variables
-~~~~~~~~~
+We get 2.0, 2.5 and 2.48, which are what we expect.
-Variables are just names that represent a value. Variables have already been
-introduced in the various examples from the previous sections. Certain rules about
-using variables:
+Interrupting
+~~~~~~~~~~~~
- * Variables have to be initialized or assigned a value before being used.
- * Variable names can consist of letters, digits and underscores(_).
- * Variable names cannot begin with digits, but can contain digits in them.
+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.
-In reference to the previous section examples, 'a', 'b', 'lng', 'fl', 'e' and 'cplx'
-are all variables of various datatypes.
+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,
::
- Note: Python is not a strongly typed language and hence an integer variable can at a
- later stage be used as a float variable as well.
+ 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
-~~~~~~~
+ * Strings
+ * Lists
+ * Tuples
-Strings are one of the essential data structures of any programming language.
-The ``print "Hello, World!"`` program was introduced in the earlier section, and
-the *"Hello, World!"* in the print statement is a string. A string is basically
-a set of characters. Strings can be represented in various ways shown below:
+
+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``
::
- s = 'this is a string' # a string variable can be represented using single quotes
- s = 'This one has "quotes" inside!' # The string can have quotes inside it as shown
- s = "I have 'single-quotes' inside!"
- l = "A string spanning many lines\
- one more line\
- yet another" # a string can span more than a single line.
- t = """A triple quoted string does # another way of representing multiline strings.
- not need to be escaped at the end and
- "can have nested quotes" etc."""
+ a = 13
+ a
-Try the following on the interpreter:
-``s = 'this is a string with 'quotes' of similar kind'``
-**Exercise: How to use single quotes within single quotes in a string as shown
-in the above example without getting an error?**
+Now, we have our first ``int`` variable ``a``.
-String operations
------------------
+To verify this, we say
+
+::
-A few basic string operations are presented here.
+ type(a)
+ <type 'int'>
-**String concatenation**
-String concatenation is done by simple addition of two strings.
+``int`` data-type can hold integers of any size lets see this by an example.
::
- >>> x = 'Hello'
- >>> y = ' Python'
- >>> print x+y
- Hello Python
+ b = 99999999999999999999
+ b
-*Try this yourself:*
+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
::
-
- >>> somenum = 13
- >>> print x+somenum
-The problem with the above example is that here a string variable and an integer
-variable are trying to be concantenated. To obtain the desired result from the
-above example the str(), repr() and the `` can be used.
+ p = 3.141592
+ p
-**str()** simply converts a value to a string in a reasonable form.
-**repr()** creates a string that is a representation of the value.
+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.
-The difference can be seen in the example shown below:
+Finally, let us look at the ``complex`` data-type.
::
-
- >>> str(1000000000000000000000000000000000000000000000000L)
- '1000000000000000000000000000000000000000000000000'
- >>> repr(1000000000000000000000000000000000000000000000000L)
- '1000000000000000000000000000000000000000000000000L'
-It can be observed that the 'L' in the long value shown was omitted by str(),
-whereas repr() converted that into a string too. An alternative way of using
-repr(value) is ```value```.
+ 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
-A few more examples:
::
-
- >>> x = "Let's go \nto Pycon"
- >>> print x
- Let's go
- to Pycon
-In the above example, notice that the '\n'(newline) character is formatted and
-the string is printed on two lines. The strings discussed until now were normal
-strings. Other than these there are two other types of strings namely, raw strings
-and unicode strings.
+ c.real
+ c.imag
-**Raw strings** are strings which are unformatted, that is the backslashes(\) are
-not parsed and are left as it is in the string. Raw strings are represented with
-an 'r' at the start of a string.
-Let us look at an example
+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.
::
-
- >>> x = r"Let's go \nto Pycon"
- >>> print x
- Let's go \nto Pycon
-Note: The '\n' is not being parsed into a new line and is left as it is.
+ type(c.real)
+ type(c.imag)
-*Try this yourself:*
+We can get the absolute value of c, by
::
-
- >>> x = r"Let's go to Pycon\"
+
+ abs(c)
-**Unicode strings** are strings where the characters are Unicode characters as
-opposed to ASCII characters. Unicode strings are represented with a 'u' at the
-start of the string.
-Let us look at an example:
+Let's now look at some operators common operations on these data-types.
::
-
- >>> x = u"Let's go to Pycon!"
- >>> print x
- Let's go to Pycon!
-Boolean
-~~~~~~~
+ 23 + 74
+ 23 - 56
+ 45 * 76
+
+ 8 / 3
+ 8.0 / 3
-Python also provides special Boolean datatype. A boolean variable can assume a
-value of either *True* or *False* (Note the capitalizations).
+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.
-Let us look at examples:
+``%`` is used for the modulo operation.
::
- >>> t = True
- >>> f = not t
- >>> print f
- False
- >>> f or t
- True
- >>> f and t
- False
+ 87 % 6
-The **while** loop
-==================
+and ``**`` is for exponentiation.
+
+::
+ 7 ** 8
-The Python **while** loop is similar to the C/C++ while loop. The syntax is as
-follows:
+All of the above operations can be performed with variables, as well.
::
- statement 0
- while condition:
- statement 1 #while block
- statement 2 #while block
- statement 3 #outside the while block.
+ a = 23
+ b = 74
+ a * b
-Let us look at an example:
+ 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.
::
- >>> x = 1
- >>> while x <= 5:
- ... print x
- ... x += 1
- ...
- 1
- 2
- 3
- 4
- 5
+ c /= 3
-The **if** conditional
-======================
+is the same as
-The Python **if** block provides the conditional execution of statements.
-If the condition evaluates as true the block of statements defined under the if
-block are executed.
+::
+
+ c = c / 3
-If the first block is not executed on account of the condition not being satisfied,
-the set of statements in the **else** block are executed.
+Booleans
+--------
-The **elif** block provides the functionality of evaluation of multiple conditions
-as shown in the example.
+Now let us look at the Boolean data-type.
-The syntax is as follows:
+::
+
+ 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.
::
- if condition :
- statement_1
- statement_2
+ (f and t) or t
- elif condition:
- statement_3
- statement_4
- else:
- statement_5
- statement_6
+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.
-Let us look at an example:
+The following expression, for instance is different from the one above.
::
- >>> n = raw_input("Input a number:")
- >>> if n < 0:
- print n," is negative"
- elif n > 0:
- print n," is positive"
- else:
- print n, " is 0"
-
-**raw_input()**
-===============
+ f and (t or t)
-In the previous example we saw the call to the raw_input() subroutine.
-The **raw_input()** method is used to take user inputs through the console.
-Unlike **input()** which assumes the data entered by the user as a standard python
-expression, **raw_input()** treats all the input data as raw data and converts
-everything into a string. To illustrate this let us look at an example.
+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
::
- >>> input("Enter a number thats a palindrome:")
- Enter a number thats a palindrome:121
- 121
+ greet_str = "hello"
+
+``greet_str`` is now a string variable with the value ``hello``
- >>> input("Enter your name:")
- Enter your name:PythonFreak
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- File "<string>", line 1, in <module>
- NameError: name 'PythonFreak' is not defined
+Anything within quotes is a string.
-As shown above the **input()** assumes that the data entered is a valid Python
-expression. In the first call it prompts for an integer input and when entered
-it accepts the integer as an integer, whereas in the second call, when the string
-is entered without the quotes, **input()** assumes that the entered data is a valid
-Python expression and hence it raises and exception saying PythonFreak is not
-defined.
+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 ('[')
::
- >>> input("Enter your name:")
- Enter your name:'PythonFreak'
- 'PythonFreak'
- >>>
+ num_tuple = (1, 2, 3, 4, 5, 6, 7, 8)
+
+Operations on sequences
+~~~~~~~~~~~~~~~~~~~~~~~
-Here the name is accepted because its entered as a string (within quotes). But
-its unreasonable to go on using quotes each time a string is entered. Hence the
-alternative is to use **raw_input()**.
+Due to their sequential nature, there are certain kind of operations, which
+can be performed on all of them.
-Let us now look at how **raw_input()** operates with an example.
+Firstly, accessing elements. Elements in sequences can be accessed using
+indexes.
::
- >>> raw_input("Enter your name:")
- Enter your name:PythonFreak
- 'PythonFreak'
+ num_list[2]
+ num_tuple[2]
+ greet_str[2]
-Observe that the **raw_input()** is converting it into a string all by itself.
+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.
::
- >>> pal = raw_input("Enter a number thats a palindrome:")
- Enter a number thats a palindrome:121
- '121'
+ num_list + [3, 4, 5, 6]
+ greet_str + " world!"
+
+
+Thirdly, you can get the length of a sequence, by using the ``len`` function.
+
+::
-Observe that **raw_input()** is converting the integer 121 also to a string as
-'121'. Let us look at another example:
+ len(num_list)
+ len(greet_str)
+
+
+Fourthly, we can check the containership of an element using the ``in``
+keyword
::
-
- >>> pal = raw_input("Enter a number thats a palindrome:")
- Enter a number thats a palindrome:121
- >>> pal + 2
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- TypeError: cannot concatenate 'str' and 'int' objects
- >>> pal
- '121'
-Observe here that the variable *pal* is a string and hence integer operations
-cannot be performed on it. Hence the exception is raised.
+ 3 in num_list
+ 'h' in greet_str
+ 'w' in greet_str
+ 2 in num_tuple
-**int()** method
-================
+We see that it gives True and False accordingly.
-Generally for computing purposes, the data used is not strings or raw data but
-on integers, floats and similar mathematical data structures. The data obtained
-from **raw_input()** is raw data in the form of strings. In order to obtain integers
-from strings we use the method **int()**.
+Next, we can find the maximum and minimum elements from a sequence.
-Let us look at an example.
+::
+
+ 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.
::
- >>> intpal = int(pal)
- >>> intpal
- 121
+ num_list[1:5]
-In the previous example it was observed that *pal* was a string variable. Here
-using the **int()** method the string *pal* was converted to an integer variable.
+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.
-*Try This Yourself:*
+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.
- >>> stringvar = raw_input("Enter a name:")
- Enter a name:Guido Van Rossum
- >>> stringvar
- 'Guido Van Rossum'
- >>> numvar = int(stringvar)
+..
+ Local Variables:
+ mode: rst
+ indent-tabs-mode: nil
+ sentence-end-double-space: nil
+ fill-column: 77
+ End:
diff --git a/basic_python/io_files_parsing.rst b/basic_python/io_files_parsing.rst
new file mode 100644
index 0000000..6bbc2e4
--- /dev/null
+++ b/basic_python/io_files_parsing.rst
@@ -0,0 +1,386 @@
+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
+
+..
+ Local Variables:
+ mode: rst
+ indent-tabs-mode: nil
+ sentence-end-double-space: nil
+ fill-column: 77
+ End:
+
+
diff --git a/basic_python/list_tuples.rst b/basic_python/list_tuples.rst
deleted file mode 100644
index 58e263c..0000000
--- a/basic_python/list_tuples.rst
+++ /dev/null
@@ -1,526 +0,0 @@
-Lists and Tuples
-================
-
-Lists
------
-
-Python provides an intuitive way to represent a group items, called *Lists*. The
-items of a *List* are called its elements. Unlike C/C++, elements can be of any
-type. A *List* is represented as a list of comma-sepated elements with square
-brackets around them::
-
- >>> a = [10, 'Python programming', 20.3523, 23, 3534534L]
- >>> a
- [10, 'Python programming', 20.3523, 23, 3534534L]
-
-
-Common List Operations
-~~~~~~~~~~~~~~~~~~~~~~
-
-The following are some of the most commonly used operations on *Lists*.
-
-
-~~~~~~~~
-Indexing
-~~~~~~~~
-
-Individual elements of a *List* can be accessed using an index to the element.
-The indices start at 0. One can also access the elements of the *List* in reverse
-using negative indices.::
-
- >>> a[1]
- 'Python programming'
- >>> a[-1]
- 3534534L
-
-It is important to note here that the last element of the *List* has an index of
--1.
-
-~~~~~~~~~~~~~
-Concatenating
-~~~~~~~~~~~~~
-
-Two or more *Lists* can be concatenated using the + operator::
-
- >>> a + ['foo', 12, 23.3432, 54]
- [10, 'Python programming', 20.3523, 'foo', 12, 23.3432, 54]
- >>> [54, 75, 23] + ['write', 67, 'read']
- [54, 75, 23, 'write', 67, 'read']
-
-
-~~~~~~~
-Slicing
-~~~~~~~
-
-A *List* can be sliced off to contain a subset of elements of the *List*. Slicing
-can be done by using two indices separated by a colon, where the first index is
-inclusive and the second index is exclusive. The resulting slice is also a *List*.::
-
- >>> num = [1, 2, 3, 4, 5, 6, 7, 8, 9]
- >>> num[3:6]
- [4, 5, 6]
- >>> num[0:1]
- [1]
- >>> num[7:10]
- [7, 8, 9]
-
-The last example showed how to access last 3 elements of the *List*. There is a
-small catch here. The second index 10 actually refers to the 11th element of the
-*List* which is still valid, even though it doesn't exist because the second
-index is exclusive and tells the Python interpreter to get the last element of
-the *List*. But this can also be done in a much easier way using negative indices::
-
- >>> num[-3:-1]
- [7, 8, 9]
-
-Excluding the first index implies that the slice must start at the beginning of
-the *List*, while excluding the second index includes all the elements till the
-end of the *List*. A third parameter to a slice, which is implicitly taken as 1
-is the step of the slice. It is specified as a value which follows a colon after
-the second index::
-
- >>> num[:4]
- [1, 2, 3, 4]
- >>> num[7:]
- [8, 9]
- >>> num[-3:]
- [7, 8, 9]
- >>> num[:]
- [1, 2, 3, 4, 5, 6, 7, 8, 9]
- >>> num[4:9:3]
- [5, 8]
- >>> num[3::2]
- [4, 6, 8]
- >>> num[::4]
- [1, 5, 9]
-
-
-~~~~~~~~~~~~~~
-Multiplication
-~~~~~~~~~~~~~~
-
-
-A *List* can be multiplied with an integer to repeat itself::
-
- >>> [20] * 5
- [20, 20, 20, 20, 20]
- >>> [42, 'Python', 54] * 3
- [42, 'Python', 54, 42, 'Python', 54, 42, 'Python', 54]
-
-
-~~~~~~~~~~
-Membership
-~~~~~~~~~~
-
-**in** operator is used to find whether an element is part of the *List*. It
-returns **True** if the element is present in the *List* or **False** if it is not
-present. Since this operator returns a Boolean value it is called a Boolean
-operator::
-
- >>> names = ['Guido', 'Alex', 'Tim']
- >>> 'Tim' in names
- True
- >>> 'Adam' in names
- False
-
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Length, Maximum and Minimum
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Length of a *List* can be found out using the len function. The max function
-returns the element with the largest value and the min function returns the
-element with the smallest value::
-
- >>> num = [4, 1, 32, 12, 67, 34, 65]
- >>> len(num)
- 7
- >>> max(num)
- 67
- >>> min(num)
- 1
-
-
-~~~~~~~~~~~~~~~~~
-Changing Elements
-~~~~~~~~~~~~~~~~~
-
-Unlike Strings *Lists* are mutable, i.e. elements of a *List* can be manipulated::
-
- >>> a = [1, 3, 5, 7]
- >>> a[2] = 9
- >>> a
- [1, 3, 9, 7]
-
-
-~~~~~~~~~~~~~~~~~
-Deleting Elements
-~~~~~~~~~~~~~~~~~
-
-An element or a slice of a *List* can be deleted by using the **del** statement::
-
- >>> a = [1, 3, 5, 7, 9, 11]
- >>> del a[-2:]
- >>> a
- [1, 3, 5, 7]
- >>> del a[1]
- >>> a
- [1, 5, 7]
-
-
-~~~~~~~~~~~~~~~~
-Assign to Slices
-~~~~~~~~~~~~~~~~
-
-In the same way, values can be assigned to individual elements of the *List*,
-a *List* of elements can be assigned to a slice::
-
- >>> a = [2, 3, 4, 5]
- >>> a[:2] = [0, 1]
- [0, 1, 4, 5]
- >>> a[2:2] = [2, 3]
- >>> a
- [0, 1, 2, 3, 4, 5]
- >>> a[2:4] = []
- >>> a
- [0, 1, 4, 5]
-
-The last two examples should be particularly noted carefully. The last but one
-example insert elements or a list of elements into a *List* and the last example
-deletes a list of elements from the *List*.
-
-
-None, Empty Lists, and Initialization
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-An *Empty List* is a *List* with no elements and is simply represented as
-[]. A *None List* is one with all elements in it being **None**. It serves
-the purpose having a container list of some fixed number of elements with
-no value::
-
- >>> a = []
- >>> a
- []
- >>> n = [None] * 10
- >>> n
- [None, None, None, None, None, None, None, None, None, None]
-
-
-Nested Lists
-~~~~~~~~~~~~
-
-As mentioned earlier, a List can contain elements of any data type. This also
-implies a *List* can have a *Lists* themselves as its elements. These are
-called as *Nested Lists*. There is no limit on the depth of the *Nested Lists*::
-
- >>> a = [1, [1, 2, 3], 3, [1, [1, 2, 3]], 7]
-
-
-List Methods
-~~~~~~~~~~~~
-
-A method is a function that is coupled to an object. More about objects
-and its methods are discussed in Advanced Python module. In general, a
-method is called like::
-
- object.method(arguments)
-
-For now, it is enough to know that a list of elements is an object and
-so *List* methods can be called upon them. Also some of the methods change
-the *List* in-place, meaning it modifies the existing list instead of creating
-a new one, while other methods don't. It must be noted as we run through
-the *List* methods.
-
-Some of the most commonly used *List* methods are as follows:
-
-
-~~~~~~
-append
-~~~~~~
-
-The *append* method is used to append an object at the end of the list::
-
- >>> prime = [2, 3, 5]
- >>> prime.append(7)
- >>> prime
- [2, 3, 5, 7]
-
-It is important to note that append changes the *List* in-place.
-
-
-~~~~~
-count
-~~~~~
-
-The *count* method returns the number of occurences of a particular element
-in a list::
-
- >>> [1, 4, 4, 9, 9, 9].count(9)
- 3
- >>> tlst = ['Python', 'is', 'a', 'beautiful', 'language']
- >>> tlst.count('Python')
- 1
-
-
-~~~~~~
-extend
-~~~~~~
-
-The *extend* method extends the list on which it is called by the list supplied
-as argument to it::
-
- >>> a = [1, 2, 3]
- >>> b = [4, 5, 6]
- >>> a.extend(b)
- [1, 2, 3, 4, 5, 6]
-
-This is an in-place method. This method is equivalent to using the + operator, but
-using the + operator returns a new list.
-
-
-~~~~~
-index
-~~~~~
-
-The *index* method returns the index position of the element in the list
-specified as argument::
-
- >>> a = [1, 2, 3, ,4, 5]
- >>> a.index(4)
- 3
-
-
-~~~~~~
-insert
-~~~~~~
-
-The *insert* method is used to insert an element specified as the second
-argument to the list at the position specified by the first argument::
-
- >>> a = ['Python', 'is', 'cool']
- >>> a.insert(2, 'so')
- >>> a
- ['Python', 'is', 'so', 'cool']
-
-The *insert* method changes the *List* in-place.
-
-
-~~~
-pop
-~~~
-
-The *pop* method removes an element from the list. The index position
-of the element to be removed can be specified as an argument to the
-*pop* method, if not it removes the last element by default::
-
- >>> a = [1, 2, 3, 4, 5]
- >>> a.pop()
- >>> a
- 5
- >>> a.pop(2)
- >>> a
- 3
-
-The *pop* method changes the *List* in-place.
-
-
-~~~~~~
-remove
-~~~~~~
-
-The *remove* method removes the first occurence of an element supplied as a
-parameter::
-
- >>> a = [1, 2, 3, 4, 2, 5, 2]
- >>> a.remove(2)
- >>> a
- [1, 3, 4, 2, 5, 2]
-
-
-~~~~~~~
-reverse
-~~~~~~~
-
-The *reverse* method reverses elements in the list. It is important to note
-here that *reverse* method changes the list in-place and doesn't return any
-thing::
-
- >>> a = ['guido', 'alex', 'tim']
- >>> a.reverse()
- >>> a
- ['tim', 'alex', 'guido']
-
-
-~~~~
-sort
-~~~~
-
-The *sort* method is used to sort the elements of the list. The *sort* method
-also sorts in-place and does not return anything::
-
- >>> a = [5, 1, 3, 7, 4]
- >>> a.sort()
- >>> a
- [1, 3, 4, 5, 7]
-
-In addition to the sort method on a *List* object we can also use the built-in
-**sorted** function. This function takes the *List* as a parameter and returns
-a sorted copy of the list. However the original list is left intact::
-
- >>> a = [5, 1, 3, 7, 4]
- >>> b = sorted(a)
- >>> b
- [1, 3, 4, 5, 7]
- >>> a
- [5, 1, 3, 7, 4]
-
-
-Tuples
-------
-
-*Tuples* are sequences just like *Lists*, but they are immutable. In other
-words *Tuples* provides a way to represent a group of items, where the group
-of items cannot be changed in any way. The syntax of a *Tuple* is also very
-similar to *List*. A *Tuple* is represented with the list of items, called
-elements of the *Tuple* separated by comma, with the entire list being enclosed
-in parenthesis. It is not compulsory to use parenthesis around a *Tuple* but
-it may be necessary in some of the cases::
-
- >>> a = 1, 2, 3
- >>> a
- (1, 2, 3)
- >>> b = 1,
- >>> b
- (1,)
-
-It is interesting to note the second example. Just a value followed by a comma
-automatically makes that an element of a *Tuple* with only one element. It is
-also important to note that, irrespective of input having a parenthesis, the
-output always has a parenthesis.
-
-The first example is also known as *Tuple packing*, because values are being
-packed into a tuple. It is also possible to do *Tuple unpacking* which is more
-interesting. It is better to understand that by example. Say we have a
-co-ordinate pair from which we need to separate x and y co-ordinates::
-
- >>> a = (1, 2)
- >>> x, y = a
- >>> x
- 1
- >>> y
- 2
-
-*Tuple unpacking* also has several other use-cases of which the most interesting
-one is to swap the values of two variables. Using programming languages like C
-would require anywhere around 10 lines of code and an extra temporary variable
-to do this (including all the #include stuff). Python does it in the most
-intuitive way in just one line. Say we want to swap the co-ordinates in the
-above example::
-
- >>> x, y = y, x
- >>> x
- 2
- >>> y
- 1
-
-Common Tuple Operations
-~~~~~~~~~~~~~~~~~~~~~~~
-
-There is no need to introduce all the *Tuple* operations again, since *Tuples*
-support the following operations that *List* supports in exactly the same way:
-
- * Indexing
- * Concatenating
- * Slicing
- * Membership
- * Multiplication
- * Length, Maximum, Minimum
-
-The following examples illustrate the above operations::
-
- >>> a = (1, 2, 3, 4, 5, 6)
- >>> a[5]
- 6
- >>> b = (7, 8, 9)
- >>> a + b
- (1, 2, 3, 4, 5, 6, 7, 8, 9)
- >>> a[3:5]
- (4, 5)
- >>> 5 in a
- True
- >>> c = (1,)
- >>> c * 5
- (1, 1, 1, 1, 1)
- >>> len(a)
- 6
- >>> max(a)
- 6
- >>> min(a)
- 1
-
-However the following *List* operations are not supported by *Tuples* because
-*Tuples* cannot be changed once they are created:
-
- * Changing elements
- * Deleting elements
- * Assigning to slices
-
-Similarity to *Lists* leads to the questions like, why not *Lists* only? Why do
-we even want *Tuples*? Can we do the same with *Lists*? And the answer is **Yes**
-we can do it, but *Tuples* are helpful at times, like we can return Tuples from
-functions. They are also returned by some built-in functions and methods. And
-also there are some use cases like co-ordinate among other things. So *Tuples*
-are helpful.
-
-Additional Syntax
------------------
-
-The following additional syntax are introduced to make it easier to operate on
-*Lists*.
-
-range()
-~~~~~~~
-
-The *range* function takes at least one argument and 2 additional optional
-arguments. If two or more arguments are specified, the range function returns
-a list of natural numbers starting from the first argument passed to it to the
-second argument. The third argument, if specified is used as a step. Suppose
-only one argument is specified, then *range* function returns a list of natural
-numbers starting from 0 upto the argument specified::
-
- >>> range(5, 10, 2)
- [5, 7, 9]
- >>> range(2, 15)
- [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
- >>> range(12)
- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
-
-for
-~~~
-
-The **for** keyword is used as a part of the looping construct. Unlike for loops
-in other languages, Python's for is used to iterate through the elements of
-sequences like *Lists*, *Tuples*, *Dictionaries*, etc. The syntax of the for loop
-consists of **for**, followed by a variable to hold the individual or the current
-element of the list during iteration and **in**, followed by the sequence and a
-semicolon(':') The next line which is part of the **for** loop, i.e the statements
-that are part of the loop should start with a new intend::
-
- >>> names = ['Guido', 'Alex', 'Tim']
- >>> for name in names:
- ... print "Name =", name
- ...
- Name = Guido
- Name = Alex
- Name = Tim
-
-
-Conclusion
-----------
-
-This section on *Lists* and *Tuples* introduces almost all the necessary
-machinary required to work on *Lists* and *Tuples*. Topics like how to
-use these data structures in bigger more useful programs will be introduced
-in the subsequent chapters.
-
-
diff --git a/basic_python/module_plan.rst b/basic_python/module_plan.rst
new file mode 100644
index 0000000..e4d1cbd
--- /dev/null
+++ b/basic_python/module_plan.rst
@@ -0,0 +1,83 @@
+Basic Python
+============
+
+Module Objectives
+-----------------
+
+After successfully completing this module a participant will be able to:
+
+* Write Python scripts to perform simple string processing or
+ mathematical tasks {Ap}
+* Read and understand simple procedural Python programs {Ap}
+
++---------+------------------------------+----------+
+| Session | Topic | Duration |
++---------+------------------------------+----------+
+| 1 | Introduction to Python | 5 min |
+| | | |
+| | Python Interpreter | 20 min |
+| | - getting started | |
+| | - IPython introduction | |
+| | | |
+| | Basic Data-types | 25 min |
+| | - Numbers | |
+| | - Booleans | |
+| | - Sequences | |
+| | | |
++---------+------------------------------+----------+
+| 2 | Strings | 20 min |
+| | - Creation | |
+| | - Operations | |
+| | - Accessing elements | |
+| | - immutability | |
+| | - methods | |
+| | | |
+| | Conditionals | 10 min |
+| | - if, if-else, if-elif-else | |
+| | - Ternary operator | |
+| | - pass | |
+| | | |
+| | Loops | 10 min |
+| | - while | |
+| | - for | |
+| | | |
+| | Lists | 20 min |
+| | - Creation | |
+| | - Operations | |
+| | - Accessing elements | |
+| | - adding & removing | |
+| | - sorting | |
++---------+------------------------------+----------+
+| 3 | I/O | 10 min |
+| | - print x & print x, | |
+| | - string formatting | |
+| | - raw_input | |
+| | | |
+| | Files | 20 min |
+| | - opening | |
+| | - reading | |
+| | - tokenization | |
+| | | |
+| | Functions | 30 min |
+| | - definition | |
+| | - doc-strings | |
+| | - code reading | |
+| | - default arguments | |
+| | - keyword arguments | |
+| | - variable scope | |
++---------+------------------------------+----------+
+| 4 | Tuples | 10 min |
+| | - packing, unpacking | |
+| | - swapping | |
+| | | |
+| | Dictionaries | 15 min |
+| | - creating | |
+| | - Accessing elements | |
+| | - Adding & removing elements | |
+| | - containership | |
+| | - keys and values | |
+| | | |
+| | Sets | 10 min |
+| | - creating | |
+| | - operations | |
++---------+------------------------------+----------+
diff --git a/basic_python/oop.rst b/basic_python/oop.rst
deleted file mode 100644
index 4241d48..0000000
--- a/basic_python/oop.rst
+++ /dev/null
@@ -1,114 +0,0 @@
-Classes and Objects
-===================
-
-In the previous sections we learnt about functions which provide certain level
-of abstraction to our code by holding the code which performs one or more
-specific functionality. We were able to use this function as many times as we
-wanted. In addition to functions, Python also higher level of abstractions
-through *Classes* and *Objects*. *Objects* can be loosely defined as a
-collection of a set of data items and a set of methods. The data items can be
-any valid Python variable or any Python object. Functions enclosed within a class
-are called as *methods*. If you are thinking if methods are functions why is there
-a distinction between the two? The answer to this will be given as we walk through
-the concepts of *Classes* and *Objects*. *Classes* contain the definition for the
-*Objects*. *Objects* are instances of *Classes*.
-
-A class is defined using the keyword **class** followed by the class name, in
-turn followed by a semicolon. The statements that a *Class* encloses are written
-in a new block, i.e on the next indentation level::
-
- class Employee:
- def setName(self, name):
- self.name = name
-
- def getName(self):
- return self.name
-
-In the above example, we defined a class with the name Employee. We also defined
-two methods, setName and getName for this class. It is important to note the
-differences between the normal Python functions and class methods defined above.
-Each method of the class must take the same instance of the class(object) from
-which it was called as the first argument. It is conventionally given the name,
-*self*. Note that *self* is only a convention. You can use any other name, but
-the first argument to the method will always be the same object of the class
-from which the method was called. The data members that belong to the class are
-called as *class attributes*. *Class attributes* are preceded by the object of
-the class and a dot. In the above example, *name* is a class attribute since it
-is preceded by the *self* object. *Class attributes* can be accessed from
-anywhere within the class.
-
-We can create objects of a class outside the class definition by using the same
-syntax we use to call a function with no parameters. We can assign this object
-to a variable::
-
- emp = Employee()
-
-In the above example, we create an object named *emp* of the class *Employee*.
-All the attributes and methods of the class can be accessed by the object of the
-class using the standard notation *object.attribute* or *object.method()*.
-Although the first parameter of a class method is the self object, it must not
-be passed as an argument when calling the method. The *self* object is implicitly
-passed to the method by the Python interpreter. All other arguments passing rules
-like default arguments, keyword arguments, argument packing and unpacking follow
-the same rules as those for ordinary Python functions::
-
- >>> emp.setName('John')
- >>> name = emp.getName()
- >>> print name
- John
- >>> print emp.name
- John
-
-If we at all try to access a class attribute before assigning a value to it, i.e
-before creating it, Python raises the same error as it would raise for the
-accessing undefined variable::
-
- >>> emp = Employee()
- >>> emp.name
- Traceback (most recent call last):
- File "class.py", line 10, in <module>
- print e.name
- AttributeError: Employee instance has no attribute 'name'
-
-It is also possible to assign values to the attributes using the above notation::
-
- >>> emp = Employee()
- >>> emp.name = 'John'
- >>> print emp.name
- John
-
-Magic methods
--------------
-
-Python reserves a number of names starting and ending with **__**. Note that it
-is a double underscore. We must not invent names of this kind in our programs.
-These methods are generally referred to as *Magic methods* or sometimes called
-as *Special Methods*. Each *Magic method* performs a specific function. One such
-magic method we will discuss now is **__init__** method. If you are from C++
-background, the **__init__** method is analogous to the class constructor. This
-method is called a constructor because, it is implicitly called everytime a new
-instance of the class is created. So effectively **__init__** method constructs
-the object from the class and sets up some initial values for the object. Other
-than the above special properties, the **__init__** method is similar to any other
-class method. The argument passing rules are same for **__init__** method. Although,
-since **__init__** is called when the object is created we need to pass the
-arguments to the class name we call while creating the object. It passes the
-arguments to the **__init__** method::
-
- class Employee:
- def __init__(self, name):
- self.name = name
-
- def getName(self):
- return self.name
-
- >>> emp = Employee('John')
- >>> print emp.getName()
- John
-
-
-Writing Object Oriented Code
-----------------------------
-
-Object oriented code mainly encompasses three components: Encapsulation, Inheritence and Polymorphism.
-Lets briefly look at each of them with examples.
diff --git a/basic_python/python.tex b/basic_python/python.tex
new file mode 100644
index 0000000..01963e1
--- /dev/null
+++ b/basic_python/python.tex
@@ -0,0 +1,54 @@
+\documentclass[12pt,presentation]{beamer}
+\usepackage[utf8]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage{fixltx2e}
+\usepackage{graphicx}
+\usepackage{longtable}
+\usepackage{float}
+\usepackage{wrapfig}
+\usepackage{soul}
+\usepackage{textcomp}
+\usepackage{marvosym}
+\usepackage{wasysym}
+\usepackage{latexsym}
+\usepackage{amssymb}
+\usepackage{hyperref}
+\tolerance=1000
+\usepackage[english]{babel} \usepackage{ae,aecompl}
+\usepackage{mathpazo,courier,euler} \usepackage[scaled=.95]{helvet}
+\usepackage{listings}
+\lstset{language=Python, basicstyle=\ttfamily\bfseries,
+commentstyle=\color{red}\itshape, stringstyle=\color{green},
+showstringspaces=false, keywordstyle=\color{blue}\bfseries}
+\providecommand{\alert}[1]{\textbf{#1}}
+
+\title{SEES: Basic Python}
+\author{FOSSEE}
+
+\usetheme{Warsaw}\usecolortheme{default}\useoutertheme{infolines}\setbeamercovered{transparent}
+
+\AtBeginSection[]
+{
+ \begin{frame}<beamer>
+ \frametitle{Outline}
+ \tableofcontents[currentsection]
+ \end{frame}
+}
+
+\begin{document}
+
+\maketitle
+
+\begin{frame}
+\frametitle{Outline}
+\setcounter{tocdepth}{3}
+\tableofcontents
+\end{frame}
+
+\include{slides/intro}
+\include{slides/strings_loops_lists}
+\include{slides/io_files_parsing}
+\include{slides/func}
+\include{slides/tuples_dicts_sets}
+
+\end{document}
diff --git a/basic_python/slides/func.tex b/basic_python/slides/func.tex
new file mode 100644
index 0000000..eefd0d5
--- /dev/null
+++ b/basic_python/slides/func.tex
@@ -0,0 +1,262 @@
+\section{Functions}
+
+\begin{frame}[fragile]
+ \frametitle{Abstracting}
+ \begin{itemize}
+ \item Reduce duplication of code
+ \item Fewer lines of code and hence lesser scope for bugs
+ \item Re-usability of code, that's already been written
+ \item Use functions written by others, without exactly knowing how
+ they do, what they are doing
+ \item \alert{Enter Functions!}
+ \end{itemize}
+\end{frame}
+
+
+\begin{frame}[fragile]
+ \frametitle{Defining functions}
+ \begin{itemize}
+ \item Consider the function \texttt{f(x) = x\textasciicircum{}2}
+ \item Let's write a Python function, equivalent to this
+ \end{itemize}
+ \begin{lstlisting}
+ def f(x):
+ return x*x
+
+ f(1)
+ f(2)
+ \end{lstlisting}
+ \begin{itemize}
+ \item \texttt{def} is a keyword
+ \item \texttt{f} is the name of the function
+ \item \texttt{x} the parameter of the function
+ \item \texttt{return} is a keyword; specifies what should be
+ returned
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Defining functions \ldots}
+ \begin{lstlisting}
+ def greet():
+ print "Hello World!"
+
+ greet()
+ \end{lstlisting}
+ \begin{itemize}
+ \item \texttt{greet} is a function that takes no arguments
+ \item Also, it is not returning anything explicitly
+ \item But implicitly, Python returns \texttt{None}
+ \end{itemize}
+ \begin{lstlisting}
+ def avg(a, b):
+ return (a + b)/2
+
+ avg(12, 10)
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Doc-strings}
+ \begin{itemize}
+ \item It's highly recommended that all functions have documentation
+ \item We write a doc-string along with the function definition
+ \end{itemize}
+ \begin{lstlisting}
+ def avg(a, b):
+ """ avg takes two numbers as input
+ and returns their average"""
+
+ return (a + b)/2
+
+ avg?
+ greet?
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Returning multiple values}
+ \begin{itemize}
+ \item Return area and perimeter of circle, given radius
+ \item Function needs to return two values
+ \end{itemize}
+ \begin{lstlisting}
+ def circle(r):
+ """returns area and perimeter of a
+ circle given, the radius r"""
+
+ pi = 3.14
+ area = pi * r * r
+ perimeter = 2 * pi * r
+ return area, perimeter
+
+ circle(4)
+ a, p = circle(6)
+ print a
+ print p
+ \end{lstlisting}
+ \begin{itemize}
+ \item Any number of values can be returned
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{What? -- 1}
+ \begin{lstlisting}
+ def what( n ):
+ if n < 0: n = -n
+ while n > 0:
+ if n % 2 == 1:
+ return False
+ n /= 10
+ return True
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{What? -- 2}
+ \begin{lstlisting}
+ def what( n ):
+ i = 1
+ while i * i < n:
+ i += 1
+ return i * i == n, i
+ \end{lstlisting}
+\end{frame}
+
+\subsection*{Default \& Keyword Arguments}
+
+\begin{frame}[fragile]
+ \frametitle{Default arguments}
+ \begin{lstlisting}
+ round(2.484)
+ round(2.484, 2)
+
+ s.split() # split on spaces
+ s.split(';') # split on ';'
+
+ range(10) # returns numbers from 0 to 9
+ range(1, 10) # returns numbers from 1 to 9
+ range(1, 10, 2) # returns odd numbers from 1 to 9
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Default arguments \ldots}
+ \begin{lstlisting}
+ def welcome(greet, name="World"):
+ print greet, name
+
+ welcome("Hi", "Guido")
+ welcome("Hello")
+ \end{lstlisting}
+ \begin{itemize}
+ \item Arguments with default values, should be placed at the end
+ \item The following definition is \alert{WRONG}
+ \end{itemize}
+ \begin{lstlisting}
+ def welcome(name="World", greet):
+ print greet, name
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Keyword Arguments}
+ \begin{lstlisting}
+ def welcome(greet, name="World"):
+ print greet, name
+
+ welcome("Hello", "James")
+
+ welcome("Hi", name="Guido")
+
+ welcome(name="Guido", greet="Hey")
+
+ welcome(name="Guido", "Hey")
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Built-in functions}
+ \begin{itemize}
+ \item Variety of built-in functions are available
+ \item \texttt{abs, any, all, len, max, min}
+ \item \texttt{pow, range, sum, type}
+ \item Refer here:
+ \url{http://docs.python.org/library/functions.html}
+ \end{itemize}
+\end{frame}
+
+\subsection*{Variable Scope}
+
+\begin{frame}[fragile]
+ \frametitle{Arguments are local}
+ \begin{lstlisting}
+ def change(q):
+ q = 10
+ print q
+
+ change(1)
+ print q
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Variables inside function are local}
+ \begin{lstlisting}
+ n = 5
+ def change():
+ n = 10
+ print n
+ change()
+ print n
+ \end{lstlisting}
+ \begin{itemize}
+ \item Use the \texttt{global} statement to assign to global variables
+ \end{itemize}
+ \begin{lstlisting}
+ def change():
+ global n
+ n = 10
+ print n
+ change()
+ print n
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Mutable variables}
+ \begin{itemize}
+ \item Behavior is different when assigning to a list element/slice
+ \item Python looks up for the name, from innermost scope outwards,
+ until the name is found
+ \end{itemize}
+ \begin{lstlisting}
+ name = ['Mr.', 'Steve', 'Gosling']
+ def change_name():
+ name[0] = 'Dr.'
+ change_name()
+ print name
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Passing Arguments \ldots}
+ \begin{lstlisting}
+ n = 5
+ def change(n):
+ n = 10
+ print "n = %s inside change " %n
+ change(n)
+ print n
+ \end{lstlisting}
+
+ \begin{lstlisting}
+ name = ['Mr.', 'Steve', 'Gosling']
+ def change_name(n):
+ n[0] = 'Dr.'
+ print "n = %s inside change_name" %n
+ change_name(n)
+ print name
+ \end{lstlisting}
+\end{frame}
diff --git a/basic_python/slides/intro.tex b/basic_python/slides/intro.tex
new file mode 100644
index 0000000..34c20dd
--- /dev/null
+++ b/basic_python/slides/intro.tex
@@ -0,0 +1,477 @@
+\section{The Language}
+\begin{frame}[fragile]
+ \frametitle{Python!}
+ \begin{itemize}
+ \item Programming Language
+ \item Powerful, High-level, Interpreted, Multi-Platform
+ \item Elegant and highly readable syntax
+ \item Efficient high-level data structures
+ \end{itemize}
+ \begin{itemize}
+ \item Easy to learn
+ \item Allows to concentrate on the problem instead of the language
+ \item Increased Productivity
+ \end{itemize}
+ \begin{itemize}
+ \item Guido van Rossum -- BDFL
+ \item Conceived in December 1989
+ \item Named after ``Monty Python's Flying Circus'', a 70s comedy
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Why Python?}
+ \begin{itemize}
+ \item Extremely readable; Forces programmers to write readable code.
+ \item Interactive; Offers a very fast edit-test-debug cycle.
+ \item Doesn't get in your way; High-level data structures let you
+ focus on the problem
+ \item Handles memory management
+ \item Batteries included; Huge standard library for wide range of
+ tasks.
+ \item Object-oriented.
+ \item C, C++ and FORTRAN interfacing allows use of legacy code
+ \item Your time is more valuable than machine time!
+ \end{itemize}
+\end{frame}
+
+\section{The Interpreter}
+\begin{frame}[fragile]
+ \frametitle{Python interpreter}
+ \begin{itemize}
+ \item Let's get our hands dirty!
+ \item Start Python from your shell
+ \end{itemize}
+ \lstset{language=sh}
+ \begin{lstlisting}
+ $ python
+ \end{lstlisting} %$
+ \begin{lstlisting}
+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.
+>>>
+ \end{lstlisting}
+ \begin{itemize}
+ \item First line shows Python version (2.7.1)
+ \item \verb+>>>+ the interpreter's prompt
+ \item The interpreter is ready and waiting for your command!
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Hello World!}
+ \begin{itemize}
+ \item Type\texttt{print `Hello World'} and hitting enter
+ \end{itemize}
+ \begin{lstlisting}
+ >>> print 'Hello, World!'
+ Hello, World!
+ \end{lstlisting}
+ \begin{itemize}
+ \item The interpreter prints out the words \emph{Hello World}
+ \end{itemize}
+ \begin{itemize}
+ \item Hit \texttt{Ctrl-D} to exit the interpreter
+ \item We shall look at IPython, an enhanced interpreter
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Versions}
+ Before moving on \ldots
+ \begin{itemize}
+ \item Currently has two stable branches or versions, 2.x and 3.x
+ \item 3.x is not backward compatible
+ \item 3.x is deemed to be the future of Python
+ \item But, we shall stick to 2.x for this course
+ \item The ecosystem around Python 2.x hasn't yet moved to 3.x
+ \end{itemize}
+\end{frame}
+
+\subsection*{IPython}
+
+\begin{frame}[fragile]
+ \frametitle{Invoking IPython}
+ \begin{itemize}
+ \item An enhanced Python interpreter
+ \item Tab-completion, Easier access to help, Better history
+ \end{itemize}
+ \lstset{language=sh}
+ \begin{lstlisting}
+ $ ipython
+ \end{lstlisting} %$
+ \alert{If \texttt{ipython is not installed}, you need to install it!}
+ \begin{itemize}
+ \item The prompt is \texttt{In [1]:} instead of \verb+>>>+
+ \item \texttt{In} stands for input, 1 indicates the command number
+ \item Try \texttt{Hello World}
+ \end{itemize}
+ \begin{lstlisting}
+ In []: print 'Hello, World!'
+ Out[]: Hello, World!
+ \end{lstlisting}
+ {\tiny the numbers have been omitted to avoid confusion}
+ \begin{itemize}
+ \item Hit \texttt{Ctrl-D} to exit \texttt{ipython}; Say \texttt{y}
+ when prompted.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Getting comfortable}
+ \begin{itemize}
+ \item Let's try some simple math to get comfortable
+ \end{itemize}
+ \begin{lstlisting}
+ In []: 1 + 2
+ In []: 5 - 3
+ In []: 7 - 4
+ In []: 6 * 5
+ \end{lstlisting}
+ \begin{itemize}
+ \item We get back the expected output
+ \item Output is displayed with an \texttt{Out[]}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{History \& Arrow Keys}
+ \begin{itemize}
+ \item Change the \texttt{print 1+2}
+ \item Use <UP-Arrow> to go back to \texttt{1+2} command
+ \item Use <LEFT-Arrow> to get to start of line; type \texttt{print }
+ \item Hit <RETURN>
+ \end{itemize}
+ \begin{lstlisting}
+ In []: print 1 + 2
+ \end{lstlisting}
+ \begin{itemize}
+ \item Now, change the previous command to \texttt{print 10*2}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Tab-Completion}
+ \begin{itemize}
+ \item We want to use \texttt{round} function
+ \item Type \texttt{ro}, and hit <TAB>
+ \end{itemize}
+ \begin{lstlisting}
+ In []: ro<TAB>
+ \end{lstlisting}
+ \begin{itemize}
+ \item Type \texttt{r}, and hit <TAB>
+ \item All possibilities are listed out, when ambiguous
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{?} for Help}
+ \begin{itemize}
+ \item To get help for \texttt{abs} function
+ \end{itemize}
+ \begin{lstlisting}
+ In []: abs?
+ In []: abs(19)
+ In []: abs(-10.5)
+ \end{lstlisting}
+ \begin{itemize}
+ \item Look at documentation for \texttt{round}
+ \item Optional arguments are denoted with square brackets
+ \texttt{[]}
+ \end{itemize}
+ \begin{lstlisting}
+ In []: round(2.484)
+ In []: round(2.484, 1)
+ In []: round(2.484, 2)
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{?} for Help}
+ \begin{itemize}
+ \item To get help for \texttt{abs} function
+ \end{itemize}
+ \begin{lstlisting}
+ In []: abs?
+ In []: abs(19)
+ In []: abs(-10.5)
+ \end{lstlisting}
+ \begin{itemize}
+ \item Look at documentation for \texttt{round}
+ \item Optional arguments are denoted with square brackets
+ \texttt{[]}
+ \end{itemize}
+ \begin{lstlisting}
+ In []: round(2.484)
+ In []: round(2.484, 1)
+ In []: round(2.484, 2)
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Interrupting}
+ \begin{lstlisting}
+ In []: round(2.484
+ ...:
+ \end{lstlisting}
+ \begin{itemize}
+ \item The \ldots prompt is the continuation prompt
+ \item It comes up, since we haven't completed previous command
+ \item Either complete by typing the missing \texttt{)}
+ \item OR hit \texttt{Ctrl-C} to interrupt the command
+ \end{itemize}
+ \begin{lstlisting}
+ In []: round(2.484
+ ...: ^C
+ \end{lstlisting}
+\end{frame}
+
+\section{Basic Datatypes and Operators}
+
+\begin{frame}[fragile]
+ \frametitle{Basic Datatypes}
+ \begin{itemize}
+ \item Numbers
+ \begin{itemize}
+ \item int
+ \item float
+ \item complex
+ \end{itemize}
+ \item Boolean
+ \item Sequence
+ \begin{itemize}
+ \item Strings
+ \item Lists
+ \item Tuples
+ \end{itemize}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{int}}
+ \begin{lstlisting}
+ In []: a = 13
+ In []: a
+ \end{lstlisting}
+ \begin{itemize}
+ \item \texttt{a} is a variable of the \texttt{int} type
+ \item Use the \texttt{type} command to verify
+ \end{itemize}
+ \begin{lstlisting}
+ In []: type(a)
+ \end{lstlisting}
+ \begin{itemize}
+ \item Integers can be arbitrarily long
+ \end{itemize}
+ \begin{lstlisting}
+ In []: b = 9999999999999999999999999999
+ In []: b
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{float}}
+ \begin{lstlisting}
+ In []: p = 3.141592
+ In []: p
+ \end{lstlisting}
+ \begin{itemize}
+ \item Decimal numbers are represented using the \texttt{float} type
+ \item Notice the loss of precision
+ \item Floats have a fixed precision
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{complex}}
+ \begin{lstlisting}
+ In []: c = 3+4j
+ \end{lstlisting}
+ \begin{itemize}
+ \item A complex number with real part 3, imaginary part 4
+ \end{itemize}
+ \begin{lstlisting}
+ In []: c.real
+ In []: c.imag
+ In []: abs(c)
+ \end{lstlisting}
+ \begin{itemize}
+ \item It's a combination of two floats
+ \item \texttt{abs} gives the absolute value
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Operations on numbers}
+ \begin{lstlisting}
+ In []: 23 + 74
+ In []: 23 - 56
+ In []: 45 * 76
+
+ In []: 8 / 3
+ In []: 8.0 / 3
+ In []: float(8) / 3
+ \end{lstlisting}
+ \begin{itemize}
+ \item The first division is an integer division
+ \item To avoid integer division, at least one number should be float
+ \item \texttt{float} function is changing int to float
+ \end{itemize}
+ \begin{lstlisting}
+ In []: 87 % 6
+ In []: 7 ** 8
+ \end{lstlisting}
+ \begin{itemize}
+ \item \texttt{\%} is used for modulo operation
+ \item \texttt{**} is used for exponentiation
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Variables \& assignment}
+ \begin{itemize}
+ \item All the operations could be done on variables
+ \end{itemize}
+ \begin{lstlisting}
+ In []: a = 23
+ In []: b = 74
+ In []: a * b
+
+ In []: c = 8
+ In []: d = 8.0
+ In []: f = c / 3
+ \end{lstlisting}
+ \begin{itemize}
+ \item Last two commands show assignment
+ \end{itemize}
+ \begin{lstlisting}
+ In []: c = c / 3
+ \end{lstlisting}
+ An operation like the one above, may equivalently be written as
+ \begin{lstlisting}
+ In []: c /= 3
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Booleans \& Operations}
+ \begin{itemize}
+ \item All the operations could be done on variables
+ \end{itemize}
+ \begin{lstlisting}
+ In []: t = True
+ In []: t
+ In []: f = not t
+ In []: f
+ In []: f or t
+ In []: f and t
+ \end{lstlisting}
+ \begin{itemize}
+ \item Multiple operation in a single command
+ \item We use parenthesis for explicitly stating what we mean
+ \item No discussion of operator precedence
+ \end{itemize}
+ \begin{lstlisting}
+ In []: (f and t) or t
+ In []: f and (t or t)
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Sequences}
+ \begin{itemize}
+ \item Hold a bunch of elements in a sequence
+ \item Elements are accessed based on position in the sequence
+ \item The sequence data-types
+ \begin{itemize}
+ \item str
+ \item list
+ \item tuple
+ \end{itemize}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Strings, Lists \& Tuples}
+ \begin{itemize}
+ \item Anything withing quotes is a string
+ \end{itemize}
+ \begin{lstlisting}
+ In []: greet_str = "hello"
+ \end{lstlisting}
+ \begin{itemize}
+ \item Items enclosed in \texttt{[ ]} and separated by \texttt{,}s
+ constitute a list
+ \end{itemize}
+ \begin{lstlisting}
+ In []: num_list = [1, 2, 3, 4, 5, 6, 7, 8]
+ \end{lstlisting}
+ \begin{itemize}
+ \item Items of a tuple are enclosed by \texttt{( )} instead of
+ \texttt{[ ]}
+ \end{itemize}
+ \begin{lstlisting}
+ In []: num_tuple = num_tuple = (1, 2, 3, 4, 5, 6, 7, 8)
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Operations on Sequences}
+ \begin{itemize}
+ \item Accessing elements
+ \end{itemize}
+ \begin{lstlisting}
+ In []: num_list[2]
+ In []: num_tuple[2]
+ In []: greet_str[2]
+ \end{lstlisting}
+ \begin{itemize}
+ \item Add two sequences of same type
+ \end{itemize}
+ \begin{lstlisting}
+ In []: num_list + [3, 4, 5, 6]
+ In []: greet_str + " world!"
+ \end{lstlisting}
+ \begin{itemize}
+ \item Get the length of a sequence
+ \end{itemize}
+ \begin{lstlisting}
+ In []: len(num_list)
+ In []: len(greet_str)
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Operations on Sequences \ldots}
+ \begin{itemize}
+ \item Check for container-ship of elements
+ \end{itemize}
+ \begin{lstlisting}
+ In []: 3 in num_list
+ In []: 'h' in greet_str
+ In []: 'w' in greet_str
+ In []: 2 in num_tuple
+ \end{lstlisting}
+ \begin{itemize}
+ \item Finding maximum and minimum
+ \end{itemize}
+ \begin{lstlisting}
+ In []: max(num_list)
+ In []: min(greet_str)
+ \end{lstlisting}
+ \begin{itemize}
+ \item Slice a sequence
+ \end{itemize}
+ \begin{lstlisting}
+ In []: num_list[1:5]
+ \end{lstlisting}
+ \begin{itemize}
+ \item Stride over a sequence
+ \end{itemize}
+ \begin{lstlisting}
+ In []: num_list[1:8:2]
+ \end{lstlisting}
+\end{frame}
+
diff --git a/basic_python/slides/io_files_parsing.tex b/basic_python/slides/io_files_parsing.tex
new file mode 100644
index 0000000..0fa030a
--- /dev/null
+++ b/basic_python/slides/io_files_parsing.tex
@@ -0,0 +1,239 @@
+\section{I/O}
+
+\begin{frame}[fragile]
+ \frametitle{Printing}
+ \begin{lstlisting}
+ a = "This is a string"
+ a
+ print a
+ \end{lstlisting}
+ \begin{itemize}
+ \item Both \texttt{a}, and \texttt{print a} are showing the value
+ \item What is the difference?
+ \item Typing \texttt{a} shows the value; \texttt{print a} prints it
+ \item Typing \texttt{a} shows the value only in interpreter
+ \item In a script, it has no effect.
+ \end{itemize}
+ \begin{lstlisting}
+ b = "A line \n New line"
+ b
+ print b
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{String formatting}
+ \begin{lstlisting}
+ x = 1.5
+ y = 2
+ z = "zed"
+ print "x is %2.1f y is %d z is %s" %(x, y, z)
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{print x} \& \texttt{print x,}}
+ \begin{itemize}
+ \item Open an editor
+ \item Type the following code
+ \item Save as \texttt{print\_example.py}
+ \end{itemize}
+ \begin{lstlisting}
+ print "Hello"
+ print "World"
+
+ print "Hello",
+ print "World"
+ \end{lstlisting}
+ \begin{itemize}
+ \item Run the script using \texttt{\% run print\_example.py}
+ \item \texttt{print x} adds a newline whereas \texttt{print x,} adds
+ a space
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{raw\_input}}
+ \begin{lstlisting}
+ ip = raw_input()
+ \end{lstlisting}
+ \begin{itemize}
+ \item The cursor is blinking; waiting for input
+ \item Type \texttt{an input} and hit <ENTER>
+ \end{itemize}
+ \begin{lstlisting}
+ print ip
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{raw\_input} \ldots}
+ \begin{lstlisting}
+ c = raw_input()
+ 5.6
+ c
+ type(c)
+ \end{lstlisting}
+ \begin{itemize}
+ \item \alert{\texttt{raw\_input} always takes a string}
+ \end{itemize}
+ \begin{lstlisting}
+ name = raw_input("Please enter your name: ")
+ George
+ \end{lstlisting}
+ \begin{itemize}
+ \item \texttt{raw\_input} can display a prompt string for the user
+ \end{itemize}
+\end{frame}
+
+\section{Files}
+
+\begin{frame}[fragile]
+ \frametitle{Opening files}
+ \begin{lstlisting}
+ pwd # present working directory
+ cd /home/fossee # go to location of the file
+ \end{lstlisting}
+ {\tiny The file is in our present working directory}
+ \begin{lstlisting}
+ f = open('pendulum.txt')
+ f
+ \end{lstlisting}
+ \begin{itemize}
+ \item \texttt{f} is a file object
+ \item Shows the mode in which the file is open (read mode)
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Reading the whole file}
+ \begin{lstlisting}
+ pend = f.read()
+ print pend
+ \end{lstlisting}
+ \begin{itemize}
+ \item We have read the whole file into the variable \texttt{pend}
+ \end{itemize}
+ \begin{lstlisting}
+ type(pend)
+ pend_list = pend.splitlines()
+ pend_list
+ \end{lstlisting}
+ \begin{itemize}
+ \item \texttt{pend} is a string variable
+ \item We can split it at the newline characters into a list of
+ strings
+ \item Close the file, when done; Also, if you want to read again
+ \end{itemize}
+ \begin{lstlisting}
+ f.close()
+ f
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Reading line-by-line}
+ \begin{lstlisting}
+ for line in open('pendulum.txt'):
+ print line
+ \end{lstlisting}
+ \begin{itemize}
+ \item The file object is an ``iterable''
+ \item We iterate over it and print each line
+ \item Instead of printing, collect lines in a list
+ \end{itemize}
+ \begin{lstlisting}
+ line_list = [ ]
+ for line in open('pendulum.txt'):
+ line_list.append(line)
+ \end{lstlisting}
+\end{frame}
+
+
+\begin{frame}[fragile]
+ \frametitle{File parsing -- Problem}
+ \begin{lstlisting}
+ A;010002;ANAND R;058;037;42;35;40;212;P;;
+ \end{lstlisting}
+ \begin{itemize}
+ \item File with records like the one above is given
+ \item Each record has fields separated by ;
+ \item region code; roll number; name;
+ \item marks --- $1^{st}$ L; $2^{nd}$ L; math; science; social; total
+ \item pass/fail indicated by P/F; W if withheld and else empty
+ \end{itemize}
+
+ \begin{itemize}
+ \item We wish to calculate mean of math marks in region B
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Tokenization}
+ \begin{lstlisting}
+ line = "parse this string"
+ line.split()
+ \end{lstlisting}
+ \begin{itemize}
+ \item Original string is split on white-space (if no argument)
+ \item Returns a list of strings
+ \item It can be given an argument to split on that argrument
+ \end{itemize}
+ \begin{lstlisting}
+ record = "A;015163;JOSEPH RAJ S;083;042;47;AA;72;244;;;"
+ record.split(';')
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Tokenization \ldots}
+ \begin{itemize}
+ \item Since we split on commas, fields may have extra spaces at ends
+ \item We can strip out the spaces at the ends
+ \end{itemize}
+ \begin{lstlisting}
+ word = " B "
+ word.strip()
+ \end{lstlisting}
+ \begin{itemize}
+ \item \texttt{strip} is returning a new string
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{str} to \texttt{float}}
+ \begin{itemize}
+ \item After tokenizing, the marks we have are strings
+ \item We need numbers to perform math operations
+ \end{itemize}
+ \begin{lstlisting}
+ mark_str = "1.25"
+ mark = int(mark_str)
+ type(mark_str)
+ type(mark)
+ \end{lstlisting}
+ \begin{itemize}
+ \item \texttt{strip} is returning a new string
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{File parsing -- Solution}
+ \begin{lstlisting}
+ math_B = [] # empty list to store 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)
+
+ math_B_mean = sum(math_B) / len(math_B)
+ math_B_mean
+ \end{lstlisting}
+\end{frame}
diff --git a/basic_python/slides/strings_loops_lists.tex b/basic_python/slides/strings_loops_lists.tex
new file mode 100644
index 0000000..244fd95
--- /dev/null
+++ b/basic_python/slides/strings_loops_lists.tex
@@ -0,0 +1,456 @@
+\section{Strings}
+
+\begin{frame}[fragile]
+ \frametitle{What are Strings?}
+ \begin{itemize}
+ \item Anything quoted is a string
+ \item Single quotes, double quotes or triple single/double quotes
+ \item Any length --- single character, null string, \ldots
+ \end{itemize}
+ \begin{lstlisting}
+ 'This is a string'
+ "This is a string too'
+ '''This is a string as well'''
+ """This is also a string"""
+ '' # empty string
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Why so many?}
+ \begin{itemize}
+ \item Reduce the need for escaping
+ \end{itemize}
+ \begin{lstlisting}
+ "Python's strings are powerful!"
+ 'He said, "I love Python!"'
+ \end{lstlisting}
+ \begin{itemize}
+ \item Triple quoted strings can be multi-line
+ \item Used for doc-strings
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Assignment \& Operations}
+ \begin{lstlisting}
+ a = 'Hello'
+ b = 'World'
+ c = a + ', ' + b + '!'
+ \end{lstlisting}
+ \begin{itemize}
+ \item Strings can be multiplied with numbers
+ \end{itemize}
+ \begin{lstlisting}
+ a = 'Hello'
+ a * 5
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Accessing Elements}
+ \begin{lstlisting}
+ print a[0], a[4], a[-1], a[-4]
+ \end{lstlisting}
+ \begin{itemize}
+ \item Can we change the elements?
+ \end{itemize}
+ \begin{lstlisting}
+ a[0] = 'H'
+ \end{lstlisting}
+ \begin{itemize}
+ \item Strings are immutable!
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Problem - Day of the Week?}
+ \begin{itemize}
+ \item Strings have methods to manipulate them
+ \end{itemize}
+ \begin{block}{Problem}
+ Given a list, \texttt{week}, containing names of the days of the
+ week and a string \texttt{s}, check if the string is a day of the
+ week. We should be able to check for any of the forms like,
+ \emph{sat, saturday, Sat, Saturday, SAT, SATURDAY}
+ \end{block}
+ \begin{itemize}
+ \item Get the first 3 characters of the string
+ \item Convert it all to lower case
+ \item Check for existence in the list, \texttt{week}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Slicing}
+ \begin{lstlisting}
+ q = "Hello World"
+ q[0:3]
+ q[:3]
+ q[3:]
+ q[:]
+ q[-1:1]
+ q[1:-1]
+ \end{lstlisting}
+ \begin{itemize}
+ \item One or both of the limits, is optional
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Striding}
+ \begin{lstlisting}
+ q[0:5:1]
+ q[0:5:2]
+ q[0:5:3]
+ q[0::2]
+ q[2::2]
+ q[::2]
+ q[5:0:-1]
+ q[::-1]
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{String Methods}
+ \begin{lstlisting}
+ s.lower()
+ s.upper()
+ s.<TAB>
+ \end{lstlisting}
+ \begin{itemize}
+ \item \alert{Strings are immutable!}
+ \item A new string is being returned
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Solution - Day of the Week?}
+ \begin{lstlisting}
+ s.lower()[:3] in week
+ \end{lstlisting}
+ OR
+ \begin{lstlisting}
+ s[:3].lower() in week
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{join} a list of strings}
+ \begin{itemize}
+ \item Given a list of strings
+ \item We wish to join them into a single string
+ \item Possibly, each string separated by a common token
+ \end{itemize}
+ \begin{lstlisting}
+ email_list = ["info@fossee.in",
+ "enquiries@fossee.in",
+ "help@fossee.in"]
+ \end{lstlisting}
+ \begin{lstlisting}
+ '; '.join(email_list)
+ ', '.join(email_list)
+ \end{lstlisting}
+\end{frame}
+
+\section{Conditionals}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{if-else} block}
+ \begin{lstlisting}
+ a = 5
+ if a % 2 == 0:
+ print "Even"
+ else:
+ print "Odd"
+ \end{lstlisting}
+ \begin{itemize}
+ \item A code block -- \texttt{:} and indentation
+ \item Exactly one block gets executed in the \texttt{if-else}
+ \end{itemize}
+\end{frame}
+
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{if-elif-else}}
+ \begin{lstlisting}
+ if a > 0:
+ print "positive"
+ elif a < 0:
+ print "negative"
+ else:
+ print "zero"
+ \end{lstlisting}
+ \begin{itemize}
+ \item Only one block gets executed, depending on \texttt{a}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{else} is optional}
+ \begin{lstlisting}
+ if user == 'admin':
+ admin_Operations()
+ elif user == 'moderator':
+ moderator_operations()
+ elif user == 'client':
+ customer_operations()
+ \end{lstlisting}
+ \begin{itemize}
+ \item Note that there is no \texttt{else} block
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Ternary operator}
+ \begin{itemize}
+ \item \texttt{score\_str} is either \texttt{'AA'} or a string of one
+ of the numbers in the range 0 to 100.
+ \item We wish to convert the string to a number using \texttt{int}
+ \item Convert it to 0, when it is \texttt{'AA'}
+ \item \texttt{if-else} construct or the ternary operator
+ \end{itemize}
+ \begin{lstlisting}
+ if score_str != 'AA':
+ score = int(score_str)
+ else:
+ score = 0
+ \end{lstlisting}
+ \begin{lstlisting}
+ score = int(score_str) if score_str != 'AA' else 0
+ \end{lstlisting}
+\end{frame}
+
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{pass}}
+ \begin{itemize}
+ \item \texttt{pass} is a syntactic filler
+ \item When a certain block has no statements, a \texttt{pass} is
+ thrown in
+ \item Mostly, when you want to get back to that part, later.
+ \end{itemize}
+\end{frame}
+
+\section{Loops}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{while}}
+ \begin{itemize}
+ \item Print squares of all odd numbers less than 10 using
+ \texttt{while}
+ \end{itemize}
+ \begin{lstlisting}
+ i = 1
+
+ while i<10:
+ print i*i
+ i += 2
+ \end{lstlisting}
+ \begin{itemize}
+ \item The loops runs as long as the condition is \texttt{True}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{for}}
+ \begin{itemize}
+ \item Print squares of all odd numbers less than 10 using
+ \texttt{for}
+ \end{itemize}
+ \begin{lstlisting}
+ for n in [1, 2, 3]:
+ print n
+ \end{lstlisting}
+ \begin{itemize}
+ \item \texttt{for} iterates over each element of a sequence
+ \end{itemize}
+ \begin{lstlisting}
+ for n in [1, 3, 5, 7, 9]:
+ print n*n
+
+ for n in range(1, 10, 2):
+ print n*n
+ \end{lstlisting}
+ \begin{itemize}
+ \item \alert{range([start,] stop[, step])}
+ \item Returns a list; Stop value is not included.
+ \end{itemize}
+\end{frame}
+
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{break}}
+ \begin{itemize}
+ \item breaks out of the innermost loop.
+ \item Squares of odd numbers below 10 using \texttt{while} \&
+ \texttt{break}
+ \end{itemize}
+ \begin{lstlisting}
+ i = 1
+
+ while True:
+ print i*i
+ i += 2
+ if i<10:
+ break
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{continue}}
+ \begin{itemize}
+ \item Skips execution of rest of the loop on current iteration
+ \item Jumps to the end of this iteration
+ \item Squares of all odd numbers below 10, not multiples of 3
+ \end{itemize}
+ \begin{lstlisting}
+ for n in range(1, 10, 2):
+ if n%3 == 0:
+ continue
+ print n*n
+ \end{lstlisting}
+\end{frame}
+
+
+\section{Lists}
+
+\begin{frame}[fragile]
+ \frametitle{Creating Lists}
+ \begin{lstlisting}
+ empty = []
+
+ p = ['spam', 'eggs', 100, 1.234]
+ q = [[4, 2, 3, 4], 'and', 1, 2, 3, 4]
+ \end{lstlisting}
+ \begin{itemize}
+ \item Lists can be empty, with no elements in them
+ \item Lists can be heterogeneous -- every element of different kind
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Accessing Elements}
+ \begin{lstlisting}
+ print p[0], p[1], p[3]
+
+ print p[-1], p[-2], p[-4]
+ print p[10]
+ \end{lstlisting}
+ \begin{itemize}
+ \item Indexing starts from 0
+ \item Indexes can be negative
+ \item Indexes should be in the valid range
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Accessing Elements \& length}
+ \begin{lstlisting}
+ print p[0], p[1], p[3]
+
+ print p[-1], p[-2], p[-4]
+ print len(p)
+ print p[10]
+ \end{lstlisting}
+ \begin{itemize}
+ \item Indexing starts from 0
+ \item Indexes can be negative
+ \item Indexes should be within the \texttt{range(0, len(p))}
+ \end{itemize}
+\end{frame}
+
+
+\begin{frame}[fragile]
+ \frametitle{Adding \& Removing Elements}
+ \begin{itemize}
+ \item The append method adds elements to the end of the list
+ \end{itemize}
+ \begin{lstlisting}
+ p.append('onemore')
+ p
+ p.append([1, 6])
+ p
+ \end{lstlisting}
+ \begin{itemize}
+ \item Elements can be removed based on their index OR
+ \item based on the value of the element
+ \end{itemize}
+ \begin{lstlisting}
+ del p[1]
+ p.remove(100)
+ \end{lstlisting}
+ \begin{itemize}
+ \item \alert{When removing by value, first element is removed}
+ \end{itemize}
+\end{frame}
+
+
+\begin{frame}[fragile]
+ \frametitle{Concatenating lists}
+ \begin{lstlisting}
+ a = [1, 2, 3, 4]
+ b = [4, 5, 6, 7]
+ a + b
+ print a+b, a, b
+ \end{lstlisting}
+ \begin{itemize}
+ \item A new list is returned; None of the original lists change
+ \end{itemize}
+ \begin{lstlisting}
+ c = a + b
+ c
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Slicing \& Striding}
+ \begin{lstlisting}
+ primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
+ primes[4:8]
+ primes[:4]
+
+ num = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
+ num[1:10:2]
+ num[:10]
+ num[10:]
+ num[::2]
+ num[::-1]
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Sorting}
+ \begin{lstlisting}
+ a = [5, 1, 6, 7, 7, 10]
+ a.sort()
+ a
+ \end{lstlisting}
+ \begin{itemize}
+ \item \texttt{sort} method sorts the list in-place
+ \item Use \texttt{sorted} if you require a new list
+ \end{itemize}
+ \begin{lstlisting}
+ a = [5, 1, 6, 7, 7, 10]
+ sorted(a)
+ a
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Reversing}
+ \begin{lstlisting}
+ a = [5, 1, 6, 7, 7, 10]
+ a.reverse()
+ a
+ \end{lstlisting}
+ \begin{itemize}
+ \item \texttt{reverse} method reverses the list in-place
+ \item Use \texttt{[::-1]} if you require a new list
+ \end{itemize}
+ \begin{lstlisting}
+ a = [5, 1, 6, 7, 7, 10]
+ a[::-1]
+ a
+ \end{lstlisting}
+\end{frame}
diff --git a/basic_python/slides/tmp.tex b/basic_python/slides/tmp.tex
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/basic_python/slides/tmp.tex
@@ -0,0 +1 @@
+
diff --git a/basic_python/slides/tuples_dicts_sets.tex b/basic_python/slides/tuples_dicts_sets.tex
new file mode 100644
index 0000000..29dadba
--- /dev/null
+++ b/basic_python/slides/tuples_dicts_sets.tex
@@ -0,0 +1,256 @@
+\section{Tuples}
+
+\begin{frame}[fragile]
+ \frametitle{Tuples -- Initialization}
+ \begin{lstlisting}
+ t = (1, 2.5, "hello", -4, "world", 1.24, 5)
+ t
+ \end{lstlisting}
+ \begin{itemize}
+ \item It is not always necessary to use parenthesis
+ \end{itemize}
+ \begin{lstlisting}
+ a = 1, 2, 3
+ b = 1,
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Indexing}
+ \begin{lstlisting}
+ t[3]
+ t[1:5:2]
+ t[2] = "Hello"
+ \end{lstlisting}
+ \begin{itemize}
+ \item \alert{Tuples are immutable!}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Swapping values}
+ \begin{lstlisting}
+ a = 5
+ b = 7
+
+ temp = a
+ a = b
+ b = temp
+ \end{lstlisting}
+ \begin{itemize}
+ \item Here's the Pythonic way of doing it
+ \end{itemize}
+ \begin{lstlisting}
+ a, b = b, a
+ \end{lstlisting}
+ \begin{itemize}
+ \item The variables can be of different data-types
+ \end{itemize}
+ \begin{lstlisting}
+ a = 2.5
+ b = "hello"
+ a, b = b, a
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Tuple packing \& unpacking}
+ \begin{lstlisting}
+ 5,
+
+ 5, "hello", 2.5
+ \end{lstlisting}
+ \begin{itemize}
+ \item Tuple packing and unpacking, when swapping
+ \end{itemize}
+ \begin{lstlisting}
+ a, b = b, a
+ \end{lstlisting}
+\end{frame}
+
+\section{Dictionaries}
+
+\begin{frame}[fragile]
+ \frametitle{Creating Dictionaries}
+ \begin{lstlisting}
+ mt_dict = {}
+
+ extensions = {'jpg' : 'JPEG Image',
+ 'py' : 'Python script',
+ 'html' : 'Html document',
+ 'pdf' : 'Portable Document Format'}
+
+ extensions
+ \end{lstlisting}
+ \begin{itemize}
+ \item Key-Value pairs
+ \item \alert{ No ordering of keys! }
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Accessing Elements}
+ \begin{lstlisting}
+ print extensions['jpg']
+ \end{lstlisting}
+ \begin{itemize}
+ \item Values can be accessed using keys
+ \end{itemize}
+ \begin{lstlisting}
+ print extensions['zip']
+ \end{lstlisting}
+ \begin{itemize}
+ \item Values of non-existent keys cannot, obviously, be accessed
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Adding \& Removing Elements}
+ \begin{itemize}
+ \item Adding a new key-value pair
+ \end{itemize}
+ \begin{lstlisting}
+ extensions['cpp'] = 'C++ code'
+ extensions
+ \end{lstlisting}
+ \begin{itemize}
+ \item Deleting a key-value pair
+ \end{itemize}
+ \begin{lstlisting}
+ del extension['pdf']
+ extensions
+ \end{lstlisting}
+ \begin{itemize}
+ \item Assigning to existing key, modifies the value
+ \end{itemize}
+ \begin{lstlisting}
+ extensions['cpp'] = 'C++ source code'
+ extensions
+ \end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Containership}
+ \begin{lstlisting}
+ 'py' in extensions
+ 'odt' in extensions
+ \end{lstlisting}
+ \begin{itemize}
+ \item Allow checking for container-ship of keys; NOT values
+ \item Use the \texttt{in} keyword to check for container-ship
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Lists of Keys and Values}
+ \begin{lstlisting}
+ extensions.keys()
+ extensions.values()
+ \end{lstlisting}
+ \begin{itemize}
+ \item Note that the order of the keys and values match
+ \item That can be relied upon and used
+ \end{itemize}
+ \begin{lstlisting}
+ for each in extensions.keys():
+ print each, "-->", extensions[each]
+ \end{lstlisting}
+\end{frame}
+
+\section{Sets}
+
+\begin{frame}[fragile]
+ \frametitle{Creating Sets}
+ \begin{lstlisting}
+ a_list = [1, 2, 1, 4, 5, 6, 2]
+ a = set(a_list)
+ a
+ \end{lstlisting}
+ \begin{itemize}
+ \item Conceptually identical to the sets in mathematics
+ \item Duplicate elements not allowed
+ \item No ordering of elements exists
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Operations on Sets}
+ \begin{lstlisting}
+ f10 = set([1, 2, 3, 5, 8])
+ p10 = set([2, 3, 5, 7])
+ \end{lstlisting}
+ \begin{itemize}
+ \item Mathematical operations performed on sets, can be performed
+ \end{itemize}
+ \begin{itemize}
+ \item Union
+ \begin{lstlisting}
+ f10 | p10
+ \end{lstlisting}
+ \item Intersection
+ \begin{lstlisting}
+ f10 & p10
+ \end{lstlisting}
+ \item Difference
+ \begin{lstlisting}
+ f10 - p10
+ \end{lstlisting}
+ \item Symmetric Difference
+ \begin{lstlisting}
+ f10 ^ p10
+ \end{lstlisting}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Sub-sets}
+ \begin{itemize}
+ \item Proper Subset
+ \begin{lstlisting}
+ b = set([1, 2])
+ b < f10
+ \end{lstlisting}
+ \item Subsets
+ \begin{lstlisting}
+ f10 <= f10
+ \end{lstlisting}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Elements of sets}
+ \begin{itemize}
+ \item Containership
+ \begin{lstlisting}
+ 1 in f10
+ 4 in f10
+ \end{lstlisting}
+ \item Iterating over elements
+ \begin{lstlisting}
+ for i in f10:
+ print i,
+ \end{lstlisting}
+ \item Subsets
+ \begin{lstlisting}
+ f10 <= f10
+ \end{lstlisting}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Sets -- Example}
+ \begin{block}{}
+ Given a list of marks, \texttt{[20, 23, 22, 23, 20, 21, 23]} list
+ all the duplicates
+ \end{block}
+ \begin{lstlisting}
+ marks = [20, 23, 22, 23, 20, 21, 23]
+ marks_set = set(marks)
+ for mark in marks_set:
+ marks.remove(mark)
+
+ # left with only duplicates
+ duplicates = set(marks)
+ \end{lstlisting}
+\end{frame}
+
diff --git a/basic_python/strings_dicts.rst b/basic_python/strings_dicts.rst
deleted file mode 100644
index b508a3d..0000000
--- a/basic_python/strings_dicts.rst
+++ /dev/null
@@ -1,475 +0,0 @@
-=======
-Strings
-=======
-
-Strings were briefly introduced previously in the introduction document. In this
-section strings will be presented in greater detail. All the standard operations
-that can be performed on sequences such as indexing, slicing, multiplication, length
-minimum and maximum can be performed on string variables as well. One thing to
-be noted is that strings are immutable, which means that string variables are
-unchangeable. Hence, all item and slice assignments on strings are illegal.
-Let us look at a few example.
-
-::
-
- >>> name = 'PythonFreak'
- >>> print name[3]
- h
- >>> print name[-1]
- k
- >>> print name[6:]
- Freak
- >>> name[6:0] = 'Maniac'
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- TypeError: 'str' object does not support item assignment
-
-This is quite expected, since string objects are immutable as already mentioned.
-The error message is clear in mentioning that 'str' object does not support item
-assignment.
-
-String Formatting
-=================
-
-String formatting can be performed using the string formatting operator represented
-as the percent (%) sign. The string placed before the % sign is formatted with
-the value placed to the right of it. Let us look at a simple example.
-
-::
-
- >>> format = 'Hello %s, from PythonFreak'
- >>> str1 = 'world!'
- >>> print format % str1
- Hello world!, from PythonFreak
-
-The %s parts of the format string are called the coversion specifiers. The coversion
-specifiers mark the places where the formatting has to be performed in a string.
-In the example the %s is replaced by the value of str1. More than one value can
-also be formatted at a time by specifying the values to be formatted using tuples
-and dictionaries (explained in later sections). Let us look at an example.
-
-::
-
- >>> format = 'Hello %s, from %s'
- >>> values = ('world!', 'PythonFreak')
- >>> print format % values
- Hello world!, from PythonFreak
-
-In this example it can be observed that the format string contains two conversion
-specifiers and they are formatted using the tuple of values as shown.
-
-The s in %s specifies that the value to be replaced is of type string. Values of
-other types can be specified as well such as integers and floats. Integers are
-specified as %d and floats as %f. The precision with which the integer or the
-float values are to be represented can also be specified using a **.** (**dot**)
-followed by the precision value.
-
-String Methods
-==============
-
-Similar to list methods, strings also have a rich set of methods to perform various
-operations on strings. Some of the most important and popular ones are presented
-in this section.
-
-**find**
-~~~~~~~~
-
-The **find** method is used to search for a substring within a given string. It
-returns the left most index of the first occurence of the substring. If the
-substring is not found in the string then it returns -1. Let us look at a few
-examples.
-
-::
-
- >>> longstring = 'Hello world!, from PythonFreak'
- >>> longstring.find('Python')
- 19
- >>> longstring.find('Perl')
- -1
-
-**join**
-~~~~~~~~
-
-The **join** method is used to join the elements of a sequence. The sequence
-elements that are to be join ed should all be strings. Let us look at a few
-examples.
-
-::
-
- >>> seq = ['With', 'great', 'power', 'comes', 'great', 'responsibility']
- >>> sep = ' '
- >>> sep.join(seq)
- 'With great power comes great responsibility'
- >>> sep = ',!'
- >>> sep.join(seq)
- 'With,!great,!power,!comes,!great,!responsibility'
-
-*Try this yourself*
-
-::
-
- >>> seq = [12,34,56,78]
- >>> sep.join(seq)
-
-**lower**
-~~~~~~~~~
-
-The **lower** method, as the name indicates, converts the entire text of a string
-to lower case. It is specially useful in cases where the programmers deal with case
-insensitive data. Let us look at a few examples.
-
-::
-
- >>> sometext = 'Hello world!, from PythonFreak'
- >>> sometext.lower()
- 'hello world!, from pythonfreak'
-
-**replace**
-~~~~~~~~~~~
-
-The **replace** method replaces a substring with another substring within
-a given string and returns the new string. Let us look at an example.
-
-::
-
- >>> sometext = 'Concise, precise and criticise is some of the words that end with ise'
- >>> sometext.replace('is', 'are')
- 'Concaree, precaree and criticaree are some of the words that end with aree'
-
-Observe here that all the occurences of the substring *is* have been replaced,
-even the *is* in *concise*, *precise* and *criticise* have been replaced.
-
-**split**
-~~~~~~~~~
-
-The **split** is one of the very important string methods. split is the opposite of the
-**join** method. It is used to split a string based on the argument passed as the
-delimiter. It returns a list of strings. By default when no argument is passed it
-splits with *space* (' ') as the delimiter. Let us look at an example.
-
-::
-
- >>> grocerylist = 'butter, cucumber, beer(a grocery item??), wheatbread'
- >>> grocerylist.split(',')
- ['butter', ' cucumber', ' beer(a grocery item??)', ' wheatbread']
- >>> grocerylist.split()
- ['butter,', 'cucumber,', 'beer(a', 'grocery', 'item??),', 'wheatbread']
-
-Observe here that in the second case when the delimiter argument was not set
-**split** was done with *space* as the delimiter.
-
-**strip**
-~~~~~~~~~
-
-The **strip** method is used to remove or **strip** off any whitespaces that exist
-to the left and right of a string, but not the whitespaces within a string. Let
-us look at an example.
-
-::
-
- >>> spacedtext = " Where's the text?? "
- >>> spacedtext.strip()
- "Where's the text??"
-
-Observe that the whitespaces between the words have not been removed.
-
-::
-
- Note: Very important thing to note is that all the methods shown above do not
- transform the source string. The source string still remains the same.
- Remember that **strings are immutable**.
-
-Introduction to the standard library
-====================================
-
-Python is often referred to as a "Batteries included!" language, mainly because
-of the Python Standard Library. The Python Standard Library provides an extensive
-set of features some of which are available directly for use while some require to
-import a few **modules**. The Standard Library provides various built-in functions
-like:
-
- * **abs()**
- * **dict()**
- * **enumerate()**
-
-The built-in constants like **True** and **False** are provided by the Standard Library.
-More information about the Python Standard Library is available http://docs.python.org/library/
-
-
-I/O: Reading and Writing Files
-==============================
-
-Files are very important aspects when it comes to computing and programming.
-Up until now the focus has been on small programs that interacted with users
-through **input()** and **raw_input()**. Generally, for computational purposes
-it becomes necessary to handle files, which are usually large in size as well.
-This section focuses on basics of file handling.
-
-Opening Files
-~~~~~~~~~~~~~
-
-Files can be opened using the **open()** method. **open()** accepts 3 arguments
-out of which 2 are optional. Let us look at the syntax of **open()**:
-
-*f = open( filename, mode, buffering)*
-
-The *filename* is a compulsory argument while the *mode* and *buffering* are
-optional. The *filename* should be a string and it should be the complete path
-to the file to be opened (The path can be absolute or relative). Let us look at
-an example.
-
-::
-
- >>> f = open ('basic_python/interim_assessment.rst')
-
-The *mode* argument specifies the mode in which the file has to be opened.
-The following are the valid mode arguments:
-
-**r** - Read mode
-**w** - Write mode
-**a** - Append mode
-**b** - Binary mode
-**+** - Read/Write mode
-
-The read mode opens the file as a read-only document. The write mode opens the
-file in the Write only mode. In the write mode, if the file existed prior to the
-opening, the previous contents of the file are erased. The append mode opens the
-file in the write mode but the previous contents of the file are not erased and
-the current data is appended onto the file.
-The binary and the read/write modes are special in the sense that they are added
-onto other modes. The read/write mode opens the file in the reading and writing
-mode combined. The binary mode can be used to open a files that do not contain
-text. Binary files such as images should be opened in the binary mode. Let us look
-at a few examples.
-
-::
-
- >>> f = open ('basic_python/interim_assessment.rst', 'r')
- >>> f = open ('armstrong.py', 'r+')
-
-The third argument to the **open()** method is the *buffering* argument. This takes
-a boolean value, *True* or *1* indicates that buffering has to be enabled on the file,
-that is the file is loaded on to the main memory and the changes made to the file are
-not immediately written to the disk. If the *buffering* argument is *0* or *False* the
-changes are directly written on to the disk immediately.
-
-Reading and Writing files
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-**write()**
------------
-
-**write()**, evidently, is used to write data onto a file. It takes the data to
-be written as the argument. The data can be a string, an integer, a float or any
-other datatype. In order to be able to write data onto a file, the file has to
-be opened in one of **w**, **a** or **+** modes.
-
-**read()**
-----------
-
-**read()** is used to read data from a file. It takes the number of bytes of data
-to be read as the argument. If nothing is specified by default it reads the entire
-contents from the current position to the end of file.
-
-Let us look at a few examples:
-
-::
-
- >>> f = open ('randomtextfile', 'w')
- >>> f.write('Hello all, this is PythonFreak. This is a random text file.')
- >>> f = open ('../randomtextfile', 'r')
- >>> f = open ('../randomtextfile', 'r')
- >>> f.read(5)
- 'Hello'
- >>> f.read()
- ' all, this is PythonFreak. This is a random text file.'
- >>> f.close()
-
-**readline()**
---------------
-
-**readline()** is used to read a file line by line. **readline()** reads a line
-of a file at a time. When an argument is passed to **readline()** it reads that
-many bytes from the current line.
-
-One other method to read a file line by line is using the **read()** and the
-**for** construct. Let us look at this block of code as an example.
-
-::
-
- >>> f = open('../randomtextfile', 'r')
- >>> for line in f:
- ... print line
- ...
- Hello all!
-
- This is PythonFreak on the second line.
-
- This is a random text file on line 3
-
-**close()**
------------
-
-One must always close all the files that have been opened. Although, files opened
-will be closed automatically when the program ends. When files opened in read mode
-are not closed it might lead to uselessly locked sometimes. In case of files
-opened in the write mode it is more important to close the files. This is because,
-Python maybe using the file in the buffering mode and when the file is not closed
-the buffer maybe lost completely and the changes made to the file are lost forever.
-
-
-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.
-Let us look at an example of how to define dictionaries.
-
-::
-
- >>> dct = { 'Sachin': 'Tendulkar', 'Rahul': 'Dravid', 'Anil': 'Kumble'}
-
-The dictionary consists of pairs of strings, which are called *keys* and their
-corresponding *values* separated by *:* and each of these *key-value* pairs are
-comma(',') separated and the entire structure wrapped in a pair curly braces *{}*.
-
-::
-
- Note: The data inside a dictionary is not ordered. The order in which you enter
- the key-value pairs is not the order in which they are stored in the dictionary.
- Python has an internal storage mechanism for that which is out of the purview
- of this document.
-
-**dict()**
-~~~~~~~~~~
-
-The **dict()** function is used to create dictionaries from other mappings or other
-dictionaries. Let us look at an example.
-
-::
-
- >>> diction = dict(mat = 133, avg = 52.53)
-
-**String Formatting with Dictionaries:**
-
-String formatting was discussed in the previous section and it was mentioned that
-dictionaries can also be used for formatting more than one value. This section
-focuses on the formatting of strings using dictionaries. String formatting using
-dictionaries is more appealing than doing the same with tuples. Here the *keyword*
-can be used as a place holder and the *value* corresponding to it is replaced in
-the formatted string. Let us look at an example.
-
-::
-
- >>> player = { 'Name':'Rahul Dravid', 'Matches':133, 'Avg':52.53, '100s':26 }
- >>> strng = '%(Name)s has played %(Matches)d with an average of %(Avg).2f and has %(100s)d hundreds to his name.'
- >>> print strng % player
- Rahul Dravid has played 133 with an average of 52.53 and has 26 hundreds to his name.
-
-Dictionary Methods
-~~~~~~~~~~~~~~~~~~
-
-**clear()**
------------
-
-The **clear()** method removes all the existing *key-value* pairs from a dictionary.
-It returns *None* or rather does not return anything. It is a method that changes
-the object. It has to be noted here that dictionaries are not immutable. Let us
-look at an example.
-
-::
-
- >>> dct
- {'Anil': 'Kumble', 'Sachin': 'Tendulkar', 'Rahul': 'Dravid'}
- >>> dct.clear()
- >>> dct
- {}
-
-**copy()**
-----------
-
-The **copy()** returns a copy of a given dictionary. Let us look at an example.
-
-::
-
- >>> dct = {'Anil': 'Kumble', 'Sachin': 'Tendulkar', 'Rahul': 'Dravid'}
- >>> dctcopy = dct.copy()
- >>> dctcopy
- {'Anil': 'Kumble', 'Sachin': 'Tendulkar', 'Rahul': 'Dravid'}
-
-
-**get()**
----------
-
-**get()** returns the *value* for the *key* passed as the argument and if the
-*key* does not exist in the dictionary, it returns *None*. Let us look at an
-example.
-
-::
-
- >>> print dctcopy.get('Saurav')
- None
- >>> print dctcopy.get('Anil')
- Kumble
-
-**has_key()**
--------------
-
-This method returns *True* if the given *key* is in the dictionary, else it returns
-*False*.
-
-::
-
- >>> dctcopy.has_key('Saurav')
- False
- >>> dctcopy.has_key('Sachin')
- True
-
-**pop()**
----------
-
-This method is used to retrieve the *value* of a given *key* and subsequently
-remove the *key-value* pair from the dictionary. Let us look at an example.
-
-::
-
- >>> print dctcopy.pop('Sachin')
- Tendulkar
- >>> dctcopy
- {'Anil': 'Kumble', 'Rahul': 'Dravid'}
-
-**popitem()**
--------------
-
-This method randomly pops a *key-value* pair from a dictionary and returns it.
-The *key-value* pair returned is removed from the dictionary. Let us look at an
-example.
-
-::
-
- >>> print dctcopy.popitem()
- ('Anil', 'Kumble')
- >>> dctcopy
- {'Rahul': 'Dravid'}
-
- Note that the item chosen is completely random since dictionaries are unordered
- as mentioned earlier.
-
-**update()**
-------------
-
-The **update()** method updates the contents of one dictionary with the contents
-of another dictionary. For items with existing *keys* their *values* are updated,
-and the rest of the items are added. Let us look at an example.
-
-::
-
- >>> dctcopy.update(dct)
- >>> dct
- {'Anil': 'Kumble', 'Sachin': 'Tendulkar', 'Rahul': 'Dravid'}
- >>> dctcopy
- {'Anil': 'Kumble', 'Sachin': 'Tendulkar', 'Rahul': 'Dravid'}
-
diff --git a/basic_python/strings_loops_lists.rst b/basic_python/strings_loops_lists.rst
new file mode 100644
index 0000000..b894f5b
--- /dev/null
+++ b/basic_python/strings_loops_lists.rst
@@ -0,0 +1,768 @@
+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.
+
+..
+ Local Variables:
+ mode: rst
+ indent-tabs-mode: nil
+ sentence-end-double-space: nil
+ fill-column: 77
+ End:
+
+
diff --git a/basic_python/tuples_dicts_sets.rst b/basic_python/tuples_dicts_sets.rst
new file mode 100644
index 0000000..ff722fd
--- /dev/null
+++ b/basic_python/tuples_dicts_sets.rst
@@ -0,0 +1,426 @@
+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.
+..
+ Local Variables:
+ mode: rst
+ indent-tabs-mode: nil
+ sentence-end-double-space: nil
+ fill-column: 77
+ End:
+
+