diff options
Diffstat (limited to 'basic_python')
-rw-r--r-- | basic_python/exercises.rst | 110 | ||||
-rw-r--r-- | basic_python/func.rst | 753 | ||||
-rw-r--r-- | basic_python/handOut.rst | 6 | ||||
-rw-r--r-- | basic_python/interim_assessment.rst | 3 | ||||
-rw-r--r-- | basic_python/intro.rst | 942 | ||||
-rw-r--r-- | basic_python/io_files_parsing.rst | 386 | ||||
-rw-r--r-- | basic_python/list_tuples.rst | 526 | ||||
-rw-r--r-- | basic_python/module_plan.rst | 83 | ||||
-rw-r--r-- | basic_python/oop.rst | 114 | ||||
-rw-r--r-- | basic_python/python.tex | 54 | ||||
-rw-r--r-- | basic_python/slides/func.tex | 262 | ||||
-rw-r--r-- | basic_python/slides/intro.tex | 477 | ||||
-rw-r--r-- | basic_python/slides/io_files_parsing.tex | 239 | ||||
-rw-r--r-- | basic_python/slides/strings_loops_lists.tex | 456 | ||||
-rw-r--r-- | basic_python/slides/tmp.tex | 1 | ||||
-rw-r--r-- | basic_python/slides/tuples_dicts_sets.tex | 256 | ||||
-rw-r--r-- | basic_python/strings_dicts.rst | 475 | ||||
-rw-r--r-- | basic_python/strings_loops_lists.rst | 768 | ||||
-rw-r--r-- | basic_python/tuples_dicts_sets.rst | 426 |
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: + + |