Ver código fonte

Adding AsciiDoc version

Swaroop C H 11 anos atrás
pai
commit
d5ab6c074d
100 arquivos alterados com 5400 adições e 4 exclusões
  1. 5 4
      .gitignore
  2. 3 0
      LICENSE.txt
  3. 46 0
      about.asciidoc
  4. 498 0
      basics.asciidoc
  5. 66 0
      byte_of_python.asciidoc
  6. 77 0
      commands.bash
  7. 272 0
      control_flow.asciidoc
  8. 392 0
      data_structures.asciidoc
  9. 13 0
      dedication.asciidoc
  10. 181 0
      exceptions.asciidoc
  11. 216 0
      first_steps.asciidoc
  12. 74 0
      floss.asciidoc
  13. 374 0
      frontpage.asciidoc
  14. 358 0
      functions.asciidoc
  15. 96 0
      installation.asciidoc
  16. 142 0
      intro.asciidoc
  17. 180 0
      io.asciidoc
  18. BIN
      light_table_screenshot.png
  19. 315 0
      modules.asciidoc
  20. 232 0
      more.asciidoc
  21. 329 0
      oop.asciidoc
  22. 278 0
      op_exp.asciidoc
  23. 88 0
      preface.asciidoc
  24. 276 0
      problem_solving.asciidoc
  25. 1 0
      programs/abc.txt
  26. 41 0
      programs/backup_ver1.py
  27. 9 0
      programs/backup_ver1.txt
  28. 51 0
      programs/backup_ver2.py
  29. 10 0
      programs/backup_ver2.txt
  30. 58 0
      programs/backup_ver3.py
  31. 5 0
      programs/backup_ver3.txt
  32. 58 0
      programs/backup_ver4.py
  33. 10 0
      programs/backup_ver4.txt
  34. 6 0
      programs/break.py
  35. 11 0
      programs/break.txt
  36. 9 0
      programs/continue.py
  37. 8 0
      programs/continue.txt
  38. 23 0
      programs/ds_reference.py
  39. 7 0
      programs/ds_reference.txt
  40. 23 0
      programs/ds_seq.py
  41. 16 0
      programs/ds_seq.txt
  42. 15 0
      programs/ds_str_methods.py
  43. 5 0
      programs/ds_str_methods.txt
  44. 23 0
      programs/ds_using_dict.py
  45. 10 0
      programs/ds_using_dict.txt
  46. 22 0
      programs/ds_using_list.py
  47. 10 0
      programs/ds_using_list.txt
  48. 14 0
      programs/ds_using_tuple.py
  49. 7 0
      programs/ds_using_tuple.txt
  50. 24 0
      programs/exceptions_finally.py
  51. 5 0
      programs/exceptions_finally.txt
  52. 8 0
      programs/exceptions_handle.py
  53. 11 0
      programs/exceptions_handle.txt
  54. 20 0
      programs/exceptions_raise.py
  55. 7 0
      programs/exceptions_raise.txt
  56. 3 0
      programs/exceptions_using_with.py
  57. 4 0
      programs/for.py
  58. 6 0
      programs/for.txt
  59. 7 0
      programs/function1.py
  60. 3 0
      programs/function1.txt
  61. 5 0
      programs/function_default.py
  62. 3 0
      programs/function_default.txt
  63. 15 0
      programs/function_docstring.py
  64. 5 0
      programs/function_docstring.txt
  65. 11 0
      programs/function_global.py
  66. 4 0
      programs/function_global.txt
  67. 6 0
      programs/function_keyword.py
  68. 4 0
      programs/function_keyword.txt
  69. 9 0
      programs/function_local.py
  70. 4 0
      programs/function_local.txt
  71. 16 0
      programs/function_param.py
  72. 3 0
      programs/function_param.txt
  73. 9 0
      programs/function_return.py
  74. 2 0
      programs/function_return.txt
  75. 9 0
      programs/function_varargs.py
  76. 2 0
      programs/function_varargs.txt
  77. 19 0
      programs/if.py
  78. 15 0
      programs/if.txt
  79. 11 0
      programs/io_input.py
  80. 11 0
      programs/io_input.txt
  81. 21 0
      programs/io_pickle.py
  82. 2 0
      programs/io_pickle.txt
  83. 9 0
      programs/io_unicode.py
  84. 28 0
      programs/io_using_file.py
  85. 5 0
      programs/io_using_file.txt
  86. 4 0
      programs/module_using_name.py
  87. 7 0
      programs/module_using_name.txt
  88. 7 0
      programs/module_using_sys.py
  89. 12 0
      programs/module_using_sys.txt
  90. 43 0
      programs/more_decorator.py
  91. 12 0
      programs/more_decorator.txt
  92. 4 0
      programs/more_lambda.py
  93. 2 0
      programs/more_lambda.txt
  94. 3 0
      programs/more_list_comprehension.py
  95. 2 0
      programs/more_list_comprehension.txt
  96. 4 0
      programs/mymodule.py
  97. 4 0
      programs/mymodule_demo.py
  98. 3 0
      programs/mymodule_demo.txt
  99. 4 0
      programs/mymodule_demo2.py
  100. 0 0
      programs/oop_init.py

+ 5 - 4
.gitignore

@@ -1,5 +1,6 @@
 *.pyc
-*.*DS_Store
-.*.sw*
-.ropeproject
-oauth.json
+byte_of_python.html
+byte_of_python.xml
+byte_of_python.pdf
+byte_of_python.epub
+byte_of_python.mobi

+ 3 - 0
LICENSE.txt

@@ -0,0 +1,3 @@
+This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
+
+See http://creativecommons.org/licenses/by-sa/4.0/ for the full text of the License.

+ 46 - 0
about.asciidoc

@@ -0,0 +1,46 @@
+[[colophon]]
+[colophon]
+== Appendix: Colophon
+
+Almost all of the software that I have used in the creation of this book are <<floss,FLOSS>>.
+
+=== Birth of the Book
+
+In the first draft of this book, I had used Red Hat 9.0 Linux as the foundation of my setup and in
+the sixth draft, I used Fedora Core 3 Linux as the basis of my setup.
+
+Initially, I was using KWord to write the book (as explained in the <<history_lesson,history
+lesson>> in the preface).
+
+=== Teenage Years
+
+Later, I switched to DocBook XML using Kate but I found it too tedious. So, I switched to
+OpenOffice which was just excellent with the level of control it provided for formatting as well as
+the PDF generation, but it produced very sloppy HTML from the document.
+
+Finally, I discovered XEmacs and I rewrote the book from scratch in DocBook XML (again) after I
+decided that this format was the long term solution.
+
+In the sixth draft, I decided to use Quanta+ to do all the editing. The standard XSL stylesheets
+that came with Fedora Core 3 Linux were being used. However, I had written a CSS document to give
+color and style to the HTML pages. I had also written a crude lexical analyzer, in Python of
+course, which automatically provides syntax highlighting to all the program listings.
+
+For the seventh draft, I'm using http://www.mediawiki.org[MediaWiki] as the basis of my setup. I
+used to edit everything online and the readers can directly read/edit/discuss within the wiki
+website, but I ended up spending more time fighting spam than writing.
+
+For the eight draft, I used http://www.swaroopch.com/notes/vim[Vim],
+http://johnmacfarlane.net/pandoc/README.html[Pandoc], and Mac OS X.
+
+=== Now
+
+For the ninth draft, I switched to http://asciidoctor.org/docs/what-is-asciidoc/[AsciiDoc format]
+and used http://www.masteringemacs.org/articles/2013/03/11/whats-new-emacs-24-3/[Emacs 24.3],
+https://github.com/chriskempson/tomorrow-theme[tomorrow theme],
+https://www.mozilla.org/en-US/styleguide/products/firefox-os/typeface/#download-primary[Fira Mono
+font] and https://github.com/sensorflo/adoc-mode/wiki[adoc-mode] to write.
+
+=== About the Author
+
+See http://swaroopch.com/about/

+ 498 - 0
basics.asciidoc

@@ -0,0 +1,498 @@
+[[basics]]
+== Basics
+
+Just printing +hello world+ is not enough, is it? You want to do more than that - you want to take
+some input, manipulate it and get something out of it. We can achieve this in Python using
+constants and variables, and we'll learn some other concepts as well in this chapter.
+
+=== Comments
+
+_Comments_ are any text to the right of the `#` symbol and is mainly useful as notes for the reader
+of the program.
+
+For example:
+
+[source,python]
+--------------------------------------------------
+print 'hello world' # Note that print is a statement
+--------------------------------------------------
+
+or:
+
+[source,python]
+--------------------------------------------------
+# Note that print is a statement
+print 'hello world'
+--------------------------------------------------
+
+Use as many useful comments as you can in your program to:
+
+- explain assumptions
+- explain important decisions
+- explain important details
+- explain problems you're trying to solve
+- explain problems you're trying to overcome in your program, etc.
+
+http://www.codinghorror.com/blog/2006/12/code-tells-you-how-comments-tell-you-why.html[*Code tells
+you how, comments should tell you why*].
+
+This is useful for readers of your program so that they can easily understand what the program is
+doing. Remember, that person can be yourself after six months!
+
+=== Literal Constants
+
+An example of a literal constant is a number like `5`, `1.23`, or a string like `'This is a
+string'` or `"It's a string!"`.
+
+It is called a literal because it is _literal_ - you use its value literally. The number `2` always
+represents itself and nothing else - it is a _constant_ because its value cannot be changed. Hence,
+all these are referred to as literal constants.
+
+=== Numbers
+
+Numbers are mainly of two types - integers and floats.
+
+An examples of an integer is `2` which is just a whole number.
+
+Examples of floating point numbers (or _floats_ for short) are `3.23` and `52.3E-4`. The +E+
+notation indicates powers of 10. In this case, `52.3E-4` means +52.3 * 10^-4^+.
+
+.Note for Experienced Programmers
+[NOTE]
+There is no separate +long+ type. The +int+ type can be an integer of any size.
+
+=== Strings
+
+A string is a _sequence_ of _characters_. Strings are basically just a bunch of words.
+
+You will be using strings in almost every Python program that you write, so pay attention to the
+following part.
+
+==== Single Quote
+
+You can specify strings using single quotes such as `'Quote me on this'`.
+
+All white space i.e. spaces and tabs, within the quotes, are preserved as-is.
+
+==== Double Quotes
+
+Strings in double quotes work exactly the same way as strings in single quotes. An example is
+`"What's your name?"`.
+
+[[triple_quotes]]
+==== Triple Quotes
+
+You can specify multi-line strings using triple quotes - (`"""` or `'''`). You can use single
+quotes and double quotes freely within the triple quotes. An example is:
+
+[source,python]
+--------------------------------------------------
+'''This is a multi-line string. This is the first line.
+This is the second line.
+"What's your name?," I asked.
+He said "Bond, James Bond."
+'''
+--------------------------------------------------
+
+==== Strings Are Immutable
+
+This means that once you have created a string, you cannot change it. Although this might seem like
+a bad thing, it really isn't. We will see why this is not a limitation in the various programs that
+we see later on.
+
+.Note for C/C++ Programmers
+[NOTE]
+There is no separate +char+ data type in Python. There is no real need for it and I am sure you
+won't miss it.
+
+.Note for Perl/PHP Programmers
+[NOTE]
+Remember that single-quoted strings and double-quoted strings are the same - they do not differ in
+any way.
+
+==== The format method
+
+Sometimes we may want to construct strings from other information. This is where the +format()+
+method is useful.
+
+Save the following lines as a file +str_format.py+:
+
+[source,python]
+--------------------------------------------------
+age = 20
+name = 'Swaroop'
+
+print '{0} was {1} years old when he wrote this book'.format(name, age)
+print 'Why is {0} playing with that python?'.format(name)
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+$ python str_format.py
+Swaroop was 20 years old when he wrote this book
+Why is Swaroop playing with that python?
+--------------------------------------------------
+
+.How It Works
+
+A string can use certain specifications and subsequently, the +format+ method can be called to
+substitute those specifications with corresponding arguments to the +format+ method.
+
+Observe the first usage where we use +{0}+ and this corresponds to the variable +name+ which is the
+first argument to the format method. Similarly, the second specification is +{1}+ corresponding to
++age+ which is the second argument to the format method. Note that Python starts counting from 0
+which means that first position is at index 0, second position is at index 1, and so on.
+
+Notice that we could have achieved the same using string concatenation:
+
+[source,python]
+--------------------------------------------------
+name + ' is ' + str(age) + ' years old'
+--------------------------------------------------
+
+but that is much uglier and error-prone. Second, the conversion to string would be done
+automatically by the +format+ method instead of the explicit conversion to strings needed in this
+case. Third, when using the +format+ method, we can change the message without having to deal with
+the variables used and vice-versa.
+
+Also note that the numbers are optional, so you could have also written as:
+
+[source,python]
+--------------------------------------------------
+age = 20
+name = 'Swaroop'
+
+print '{} was {} years old when he wrote this book'.format(name, age)
+print 'Why is {} playing with that python?'.format(name)
+--------------------------------------------------
+
+which will give the same exact output as the previous program.
+
+What Python does in the +format+ method is that it substitutes each argument value into the place
+of the specification. There can be more detailed specifications such as:
+
+[source,python]
+--------------------------------------------------
+# decimal (.) precision of 3 for float '0.333'
+print '{0:.3f}'.format(1.0/3)
+# fill with underscores (_) with the text centered
+# (^) to 11 width '___hello___'
+print '{0:_^11}'.format('hello')
+# keyword-based 'Swaroop wrote A Byte of Python'
+print '{name} wrote {book}'.format(name='Swaroop',
+                                   book='A Byte of Python')
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+0.333
+___hello___
+Swaroop wrote A Byte of Python
+--------------------------------------------------
+
+Since we are discussing formatting, note that +print+ always ends with an invisible "new line"
+character (+\n+) so that repeated calls to +print+ will all print on a separate line each. To
+prevent this newline character from being printed, you can end the statement with a comma:
+
+[source,python]
+--------------------------------------------------
+print "a",
+print "b",
+--------------------------------------------------
+
+Output is:
+
+--------------------------------------------------
+a b
+--------------------------------------------------
+
+==== Escape Sequences
+
+Suppose, you want to have a string which contains a single quote (`'`), how will you specify this
+string? For example, the string is `"What's your name?"`. You cannot specify `'What's your name?'`
+because Python will be confused as to where the string starts and ends. So, you will have to
+specify that this single quote does not indicate the end of the string. This can be done with the
+help of what is called an _escape sequence_. You specify the single quote as `\'` : notice the
+backslash. Now, you can specify the string as `'What\'s your name?'`.
+
+Another way of specifying this specific string would be `"What's your name?"` i.e. using double
+quotes. Similarly, you have to use an escape sequence for using a double quote itself in a double
+quoted string. Also, you have to indicate the backslash itself using the escape sequence `\\`.
+
+What if you wanted to specify a two-line string? One way is to use a triple-quoted string as shown
+<<triple_quotes,previously>> or you can use an escape sequence for the newline character - +\n+ to
+indicate the start of a new line. An example is:
+
+[source,python]
+--------------------------------------------------
+'This is the first line\nThis is the second line'
+--------------------------------------------------
+
+Another useful escape sequence to know is the tab: +\t+. There are many more escape sequences but I
+have mentioned only the most useful ones here.
+
+One thing to note is that in a string, a single backslash at the end of the line indicates that the
+string is continued in the next line, but no newline is added. For example:
+
+[source,python]
+--------------------------------------------------
+"This is the first sentence. \
+This is the second sentence."
+--------------------------------------------------
+
+is equivalent to
+
+[source,python]
+--------------------------------------------------
+"This is the first sentence. This is the second sentence."
+--------------------------------------------------
+
+==== Raw String
+
+If you need to specify some strings where no special processing such as escape sequences are
+handled, then what you need is to specify a _raw_ string by prefixing +r+ or +R+ to the string. An
+example is:
+
+[source,python]
+--------------------------------------------------
+r"Newlines are indicated by \n"
+--------------------------------------------------
+
+.Note for Regular Expression Users
+[NOTE]
+Always use raw strings when dealing with regular expressions. Otherwise, a lot of backwhacking may
+be required. For example, backreferences can be referred to as `'\\1'` or `r'\1'`.
+
+=== Variable
+
+Using just literal constants can soon become boring - we need some way of storing any information
+and manipulate them as well. This is where _variables_ come into the picture. Variables are exactly
+what the name implies - their value can vary, i.e., you can store anything using a
+variable. Variables are just parts of your computer's memory where you store some
+information. Unlike literal constants, you need some method of accessing these variables and hence
+you give them names.
+
+=== Identifier Naming
+
+Variables are examples of identifiers. _Identifiers_ are names given to identify _something_. There
+are some rules you have to follow for naming identifiers:
+
+- The first character of the identifier must be a letter of the alphabet (uppercase ASCII or
+  lowercase ASCII or Unicode character) or an underscore (`_`).
+- The rest of the identifier name can consist of letters (uppercase ASCII or lowercase ASCII or
+  Unicode character), underscores (`_`) or digits (0-9).
+- Identifier names are case-sensitive. For example, `myname` and `myName` are _not_ the same. Note
+  the lowercase `n` in the former and the uppercase `N` in the latter.
+- Examples of _valid_ identifier names are `i`, `__my_name`, `name_23`. Examples of _invalid_
+  identifier names are `2things`, `this is spaced out`, `my-name` and `>a1b2_c3`.
+
+=== Data Types
+
+Variables can hold values of different types called _data types_. The basic types are numbers and
+strings, which we have already discussed. In later chapters, we will see how to create our own
+types using <<oop,classes>>.
+
+=== Object
+
+Remember, Python refers to anything used in a program as an _object_.  This is meant in the generic
+sense. Instead of saying "the _something_"', we say "the _object_".
+
+.Note for Object Oriented Programming users
+[NOTE]
+Python is strongly object-oriented in the sense that everything is an object including numbers,
+strings and functions.
+
+We will now see how to use variables along with literal constants. Save the following example and
+run the program.
+
+=== How to write Python programs
+
+Henceforth, the standard procedure to save and run a Python program is as follows:
+
+. Open your editor of choice, such as Light Table.
+. Type the program code given in the example.
+. Save it as a file with the filename mentioned.
+. Run the interpreter with the command +python program.py+ to run the program.
+
+=== Example: Using Variables And Literal Constants
+
+Type and run the following program:
+
+[source,python]
+--------------------------------------------------
+# Filename : var.py
+i = 5
+print i
+i = i + 1
+print i
+
+s = '''This is a multi-line string.
+This is the second line.'''
+print s
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+5
+6
+This is a multi-line string.
+This is the second line.
+--------------------------------------------------
+
+.How It Works
+
+Here's how this program works. First, we assign the literal constant value +5+ to the variable +i+
+using the assignment operator (`=`). This line is called a statement because it states that
+something should be done and in this case, we connect the variable name +i+ to the value +5+. Next,
+we print the value of +i+ using the +print+ statement which, unsurprisingly, just prints the value
+of the variable to the screen.
+
+Then we add +1+ to the value stored in +i+ and store it back. We then print it and expectedly, we
+get the value +6+.
+
+Similarly, we assign the literal string to the variable +s+ and then print it.
+
+.Note for static language programmers
+[NOTE]
+Variables are used by just assigning them a value. No declaration or data type definition is
+needed/used.
+
+=== Logical And Physical Line
+
+A physical line is what you _see_ when you write the program. A logical line is what _Python sees_
+as a single statement. Python implicitly assumes that each _physical line_ corresponds to a
+_logical line_.
+
+An example of a logical line is a statement like `print 'hello world'` - if this was on a line by
+itself (as you see it in an editor), then this also corresponds to a physical line.
+
+Implicitly, Python encourages the use of a single statement per line which makes code more
+readable.
+
+If you want to specify more than one logical line on a single physical line, then you have to
+explicitly specify this using a semicolon (`;`) which indicates the end of a logical
+line/statement. For example:
+
+[source,python]
+--------------------------------------------------
+i = 5
+print i
+--------------------------------------------------
+
+is effectively same as
+
+[source,python]
+--------------------------------------------------
+i = 5;
+print i;
+--------------------------------------------------
+
+which is also same as
+
+[source,python]
+--------------------------------------------------
+i = 5; print i;
+--------------------------------------------------
+
+and same as
+
+[source,python]
+--------------------------------------------------
+i = 5; print i
+--------------------------------------------------
+
+However, I *strongly recommend* that you stick to *writing a maximum of a single logical line on
+each single physical line*. The idea is that you should never use the semicolon. In fact, I have
+_never_ used or even seen a semicolon in a Python program.
+
+There is one kind of situation where this concept is really useful: if you have a long line of
+code, you can break it into multiple physical lines by using the backslash. This is referred to as
+_explicit line joining_:
+
+[source,python]
+--------------------------------------------------
+s = 'This is a string. \
+This continues the string.'
+print s
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+This is a string. This continues the string.
+--------------------------------------------------
+
+Similarly,
+
+[source,python]
+--------------------------------------------------
+print \
+i
+--------------------------------------------------
+
+is the same as
+
+[source,python]
+--------------------------------------------------
+print i
+--------------------------------------------------
+
+Sometimes, there is an implicit assumption where you don't need to use a backslash. This is the
+case where the logical line has a starting parentheses, starting square brackets or a starting
+curly braces but not an ending one. This is called *implicit line joining*. You can see this in
+action when we write programs using <<lists,lists>> in later chapters.
+
+[[indentation]]
+=== Indentation
+
+Whitespace is important in Python. Actually, *whitespace at the beginning of the line is
+important*. This is called _indentation_. Leading whitespace (spaces and tabs) at the beginning of
+the logical line is used to determine the indentation level of the logical line, which in turn is
+used to determine the grouping of statements.
+
+This means that statements which go together _must_ have the same indentation. Each such set of
+statements is called a *block*. We will see examples of how blocks are important in later chapters.
+
+One thing you should remember is that wrong indentation can give rise to errors. For example:
+
+[source,python]
+--------------------------------------------------
+i = 5
+# Error below! Notice a single space at the start of the line
+ print 'Value is ', i
+print 'I repeat, the value is ', i
+--------------------------------------------------
+
+When you run this, you get the following error:
+
+--------------------------------------------------
+  File "whitespace.py", line 5
+    print 'Value is ', i
+    ^
+IndentationError: unexpected indent
+--------------------------------------------------
+
+Notice that there is a single space at the beginning of the second line. The error indicated by
+Python tells us that the syntax of the program is invalid i.e. the program was not properly
+written. What this means to you is that _you cannot arbitrarily start new blocks of statements_
+(except for the default main block which you have been using all along, of course). Cases where you
+can use new blocks will be detailed in later chapters such as the <<control_flow,Control Flow>>.
+
+.How to indent
+Use four spaces for indentation. This is the official Python language recommendation. Good editors
+will automatically do this for you. Make sure you use a consistent number of spaces for
+indentation, otherwise your program will show errors.
+
+.Note to static language programmers
+[NOTE]
+Python will always use indentation for blocks and will never use braces. Run `from __future__
+import braces` to learn more.
+
+=== Summary
+
+Now that we have gone through many nitty-gritty details, we can move on to more interesting stuff
+such as control flow statements. Be sure to become comfortable with what you have read in this
+chapter.

+ 66 - 0
byte_of_python.asciidoc

@@ -0,0 +1,66 @@
+= A Byte of Python
+:Author: Swaroop C H
+:Email: swaroop@swaroopch.com
+:Revision: 3.0
+:doctype: book
+:lang: en
+:homepage: http://swaroopch.com/notes/python
+:buy: http://swaroopch.com/buybook
+:contact: http://swaroopch.com/contact
+:toc:
+:toclevels: 1
+:sectlinks:
+:experimental:
+// http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/#ui-macros
+
+"A Byte of Python" is a free book on programming using the Python language. It serves as a tutorial
+or guide to the Python language for a beginner audience. If all you know about computers is how to
+save text files, then this is the book for you.
+
+include::frontpage.asciidoc[]
+
+include::dedication.asciidoc[]
+
+include::preface.asciidoc[]
+
+include::intro.asciidoc[]
+
+include::installation.asciidoc[]
+
+include::first_steps.asciidoc[]
+
+include::basics.asciidoc[]
+
+include::op_exp.asciidoc[]
+
+include::control_flow.asciidoc[]
+
+include::functions.asciidoc[]
+
+include::modules.asciidoc[]
+
+include::data_structures.asciidoc[]
+
+include::problem_solving.asciidoc[]
+
+include::oop.asciidoc[]
+
+include::io.asciidoc[]
+
+include::exceptions.asciidoc[]
+
+include::stdlib.asciidoc[]
+
+include::more.asciidoc[]
+
+include::what_next.asciidoc[]
+
+include::floss.asciidoc[]
+
+include::about.asciidoc[]
+
+include::revision_history.asciidoc[]
+
+include::translations.asciidoc[]
+
+include::translation_howto.asciidoc[]

+ 77 - 0
commands.bash

@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+
+## References:
+## http://asciidoctor.org/docs/asciidoc-writers-guide/
+
+SLUG="byte_of_python"
+FOPUB="$HOME/code/asciidoctor/asciidoctor-fopub/fopub"
+
+function doctor() {
+    backend=$1
+    shift
+
+    asciidoctor -n -a 'source-highlighter=pygments' -b $backend ${SLUG}.asciidoc
+}
+
+function make_html () {
+    doctor html5
+    ls -lh "$PWD/$SLUG.html"
+}
+
+function make_pdf () {
+    doctor docbook
+    $FOPUB ${SLUG}.xml
+    # OR
+    # a2x -f pdf --fop ${SLUG}.asciidoc
+    ls -lh "$PWD/$SLUG.pdf"
+}
+
+# TODO Syntax highlighting in output
+#   - http://docbook.sourceforge.net/release/xsl/current/doc/fo/highlight.source.html
+#      - ~/code/asciidoctor/asciidoctor-fopub/src/dist/docbook-xsl/xslthl-config.xml
+#   - http://www.vogella.com/tutorials/DocBook/article.html#advanced_syntaxhighlighting
+function make_epub () {
+    doctor docbook
+    dbtoepub ${SLUG}.xml
+    # OR
+    # a2x -f epub ${SLUG}.xml
+    epubcheck "$PWD/$SLUG.epub"
+    ls -lh "$PWD/$SLUG.epub"
+}
+
+function make_mobi () {
+    doctor html5
+    kindlegen -verbose ${SLUG}.html -o ${SLUG}.mobi
+    ls -lh "$PWD/$SLUG.mobi"
+}
+
+# TODO https://github.com/schacon/git-scribe/blob/master/lib/git-scribe/generate.rb#L107
+# TODO Instead, create an official backend for asciidoctor to create a website?
+#
+function make_website () {
+    echo "TODO"
+}
+
+function install_deps_osx () {
+    # http://brew.sh
+    brew update
+    brew install docbook docbook-xsl fop epubcheck git
+    brew tap homebrew/binary
+    brew install kindlegen
+    # brew install asciidoc
+
+    # http://asciidoctor.org/docs/install-asciidoctor-macosx/
+    sudo gem update --system
+    sudo gem install asciidoctor -N
+
+    # https://groups.google.com/forum/#!topic/asciidoc/FC-eOwU8rYg
+    echo >> ~/.bash_profile
+    echo 'export XML_CATALOG_FILES="/usr/local/etc/xml/catalog"' >> ~/.bash_profile
+
+    # https://github.com/asciidoctor/asciidoctor-fopub/blob/master/README.adoc
+    mkdir -p $HOME/code/asciidoctor/
+    cd $HOME/code/asciidoctor/
+    git clone https://github.com/asciidoctor/asciidoctor-fopub
+
+    # If emacs, install package: https://github.com/sensorflo/adoc-mode/wiki
+}

+ 272 - 0
control_flow.asciidoc

@@ -0,0 +1,272 @@
+[[control_flow]]
+== Control Flow
+
+In the programs we have seen till now, there has always been a series of statements faithfully
+executed by Python in exact top-down order. What if you wanted to change the flow of how it works?
+For example, you want the program to take some decisions and do different things depending on
+different situations, such as printing 'Good Morning' or 'Good Evening' depending on the time of
+the day?
+
+As you might have guessed, this is achieved using control flow statements. There are three control
+flow statements in Python - +if+, +for+ and +while+.
+
+=== The +if+ statement
+
+The +if+ statement is used to check a condition: *if* the condition is true, we run a block of
+statements (called the _if-block_), *else* we process another block of statements (called the
+_else-block_). The *else* clause is optional.
+
+Example (save as +if.py+):
+
+[source,python]
+--------------------------------------------------
+include::programs/if.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/if.txt[]
+--------------------------------------------------
+
+.How It Works
+
+In this program, we take guesses from the user and check if it is the number that we have. We set
+the variable +number+ to any integer we want, say `23`. Then, we take the user's guess using the
+`raw_input()` function. Functions are just reusable pieces of programs. We'll read more about them
+in the <<functions,next chapter>>.
+
+We supply a string to the built-in `raw_input` function which prints it to the screen and waits for
+input from the user. Once we enter something and press kbd:[enter] key, the `raw_input()` function
+returns what we entered, as a string. We then convert this string to an integer using `int` and
+then store it in the variable `guess`. Actually, the `int` is a class but all you need to know
+right now is that you can use it to convert a string to an integer (assuming the string contains a
+valid integer in the text).
+
+Next, we compare the guess of the user with the number we have chosen. If they are equal, we print
+a success message. Notice that we use indentation levels to tell Python which statements belong to
+which block. This is why indentation is so important in Python. I hope you are sticking to the
+"consistent indentation" rule. Are you?
+
+Notice how the `if` statement contains a colon at the end - we are indicating to Python that a
+block of statements follows.
+
+Then, we check if the guess is less than the number, and if so, we inform the user that they must
+guess a little higher than that. What we have used here is the `elif` clause which actually
+combines two related `if else-if else` statements into one combined `if-elif-else` statement. This
+makes the program easier and reduces the amount of indentation required.
+
+The `elif` and `else` statements must also have a colon at the end of the logical line followed by
+their corresponding block of statements (with proper indentation, of course)
+
+You can have another `if` statement inside the if-block of an `if` statement and so on - this is
+called a nested `if` statement.
+
+Remember that the `elif` and `else` parts are optional. A minimal valid `if` statement is:
+
+[source,python]
+--------------------------------------------------
+if True:
+    print 'Yes, it is true'
+--------------------------------------------------
+
+After Python has finished executing the complete `if` statement along with the associated `elif`
+and `else` clauses, it moves on to the next statement in the block containing the `if`
+statement. In this case, it is the main block (where execution of the program starts), and the next
+statement is the `print 'Done'` statement. After this, Python sees the ends of the program and
+simply finishes up.
+
+Even though this is a very simple program, I have been pointing out a lot of things that you should
+notice. All these are pretty straightforward (and surprisingly simple for those of you from C/C++
+backgrounds). You will need to become aware of all these things initially, but after some practice
+you will become comfortable with them, and it will all feel 'natural' to you.
+
+.Note for C/C++ Programmers
+[NOTE]
+There is no `switch` statement in Python. You can use an `if..elif..else` statement to do the same
+thing (and in some cases, use a <<dictionary,dictionary>> to do it quickly)
+
+=== The while Statement
+
+The `while` statement allows you to repeatedly execute a block of statements as long as a condition
+is true. A `while` statement is an example of what is called a *looping* statement. A `while`
+statement can have an optional `else` clause.
+
+Example (save as `while.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/while.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/while.txt[]
+--------------------------------------------------
+
+.How It Works
+
+In this program, we are still playing the guessing game, but the advantage is that the user is
+allowed to keep guessing until he guesses correctly - there is no need to repeatedly run the
+program for each guess, as we have done in the previous section. This aptly demonstrates the use of
+the `while` statement.
+
+We move the `raw_input` and `if` statements to inside the `while` loop and set the variable
+`running` to `True` before the while loop. First, we check if the variable `running` is `True` and
+then proceed to execute the corresponding *while-block*. After this block is executed, the
+condition is again checked which in this case is the `running` variable. If it is true, we execute
+the while-block again, else we continue to execute the optional else-block and then continue to the
+next statement.
+
+The `else` block is executed when the `while` loop condition becomes `False` - this may even be the
+first time that the condition is checked. If there is an `else` clause for a `while` loop, it is
+always executed unless you break out of the loop with a `break` statement.
+
+The `True` and `False` are called Boolean types and you can consider them to be equivalent to the
+value `1` and `0` respectively.
+
+.Note for C/C++ Programmers
+[NOTE]
+Remember that you can have an `else` clause for the `while` loop.
+
+=== The +for+ loop
+
+The `for..in` statement is another looping statement which *iterates* over a sequence of objects
+i.e. go through each item in a sequence. We will see more about <<sequence,sequences>> in detail in
+later chapters. What you need to know right now is that a sequence is just an ordered collection of
+items.
+
+Example (save as `for.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/for.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/for.txt[]
+--------------------------------------------------
+
+.How It Works
+
+In this program, we are printing a *sequence* of numbers. We generate this sequence of numbers
+using the built-in `range` function.
+
+What we do here is supply it two numbers and `range` returns a sequence of numbers starting from
+the first number and up to the second number. For example, `range(1,5)` gives the sequence `[1, 2,
+3, 4]`. By default, `range` takes a step count of 1. If we supply a third number to `range`, then
+that becomes the step count. For example, `range(1,5,2)` gives `[1,3]`. Remember that the range
+extends *up to* the second number i.e. it does *not* include the second number.
+
+Note that `range()` generates a sequence of numbers, but it will generate only one number at a
+time, when the for loop requests for the next item. If you want to see the full sequence of numbers
+immediately, use `list(range())`. Lists are explained in the <<data_structures,data structures
+chapter>>.
+
+The `for` loop then iterates over this range - `for i in range(1,5)` is equivalent to `for i in [1,
+2, 3, 4]` which is like assigning each number (or object) in the sequence to i, one at a time, and
+then executing the block of statements for each value of `i`.  In this case, we just print the
+value in the block of statements.
+
+Remember that the `else` part is optional. When included, it is always executed once after the
+`for` loop is over unless a <<the_break_statement,break>> statement is encountered.
+
+Remember that the `for..in` loop works for any sequence. Here, we have a list of numbers generated
+by the built-in `range` function, but in general we can use any kind of sequence of any kind of
+objects! We will explore this idea in detail in later chapters.
+
+.Note for C/C++/Java/C# Programmers
+[NOTE]
+--
+The Python `for` loop is radically different from the C/C++ `for` loop. C# programmers will note
+that the `for` loop in Python is similar to the `foreach` loop in C#. Java programmers will note
+that the same is similar to `for (int i : IntArray)` in Java 1.5.
+
+In C/C++, if you want to write `for (int i = 0; i < 5; i++)`, then in Python you write just `for i
+in range(0,5)`. As you can see, the `for` loop is simpler, more expressive and less error prone in
+Python.
+--
+
+[[the_break_statement]]
+=== The break Statement
+
+The `break` statement is used to *break* out of a loop statement i.e. stop the execution of a
+looping statement, even if the loop condition has not become `False` or the sequence of items has
+not been completely iterated over.
+
+An important note is that if you *break* out of a `for` or `while` loop, any corresponding loop
+`else` block is **not** executed.
+
+Example (save as `break.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/break.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/break.txt[]
+--------------------------------------------------
+
+.How It Works
+
+In this program, we repeatedly take the user's input and print the length of each input each
+time. We are providing a special condition to stop the program by checking if the user input is
+`'quit'`. We stop the program by *breaking* out of the loop and reach the end of the program.
+
+The length of the input string can be found out using the built-in `len` function.
+
+Remember that the `break` statement can be used with the `for` loop as well.
+
+.Swaroop's Poetic Python
+**************************************************
+The input I have used here is a mini poem I have written:
+
+[verse]
+Programming is fun
+When the work is done
+if you wanna make your work also fun:
+    use Python!
+**************************************************
+
+[[the_continue_statement]]
+=== The +continue+ Statement
+
+The `continue` statement is used to tell Python to skip the rest of the statements in the current
+loop block and to *continue* to the next iteration of the loop.
+
+Example (save as `continue.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/continue.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/continue.txt[]
+--------------------------------------------------
+
+.How It Works
+
+In this program, we accept input from the user, but we process the input string only if it is at
+least 3 characters long. So, we use the built-in `len` function to get the length and if the length
+is less than 3, we skip the rest of the statements in the block by using the `continue`
+statement. Otherwise, the rest of the statements in the loop are executed, doing any kind of
+processing we want to do here.
+
+Note that the `continue` statement works with the `for` loop as well.
+
+=== Summary
+
+We have seen how to use the three control flow statements - `if`, `while` and `for` along with
+their associated `break` and `continue` statements. These are some of the most commonly used parts
+of Python and hence, becoming comfortable with them is essential.
+
+Next, we will see how to create and use functions.

+ 392 - 0
data_structures.asciidoc

@@ -0,0 +1,392 @@
+[[data_structures]]
+== Data Structures
+
+Data structures are basically just that - they are *structures* which can hold some *data*
+together. In other words, they are used to store a collection of related data.
+
+There are four built-in data structures in Python - _list, tuple, dictionary and set_. We will see
+how to use each of them and how they make life easier for us.
+
+[[list]]
+=== List
+
+A `list` is a data structure that holds an ordered collection of items i.e. you can store a
+*sequence* of items in a list. This is easy to imagine if you can think of a shopping list where
+you have a list of items to buy, except that you probably have each item on a separate line in your
+shopping list whereas in Python you put commas in between them.
+
+The list of items should be enclosed in square brackets so that Python understands that you are
+specifying a list. Once you have created a list, you can add, remove or search for items in the
+list. Since we can add and remove items, we say that a list is a *mutable* data type i.e. this type
+can be altered.
+
+=== Quick Introduction To Objects And Classes
+
+Although I've been generally delaying the discussion of objects and classes till now, a little
+explanation is needed right now so that you can understand lists better. We will explore this topic
+in detail in a <<oop,later chapter>>.
+
+A list is an example of usage of objects and classes. When we use a variable `i` and assign a value
+to it, say integer `5` to it, you can think of it as creating an *object* (i.e. instance) `i` of
+*class* (i.e. type) `int`. In fact, you can read `help(int)` to understand this better.
+
+A class can also have *methods* i.e. functions defined for use with respect to that class only. You
+can use these pieces of functionality only when you have an object of that class. For example,
+Python provides an `append` method for the `list` class which allows you to add an item to the end
+of the list. For example, `mylist.append('an item')` will add that string to the list
+`mylist`. Note the use of dotted notation for accessing methods of the objects.
+
+A class can also have *fields* which are nothing but variables defined for use with respect to that
+class only. You can use these variables/names only when you have an object of that class. Fields
+are also accessed by the dotted notation, for example, `mylist.field`.
+
+Example (save as `ds_using_list.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/ds_using_list.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/ds_using_list.txt[]
+--------------------------------------------------
+
+.How It Works
+
+The variable `shoplist` is a shopping list for someone who is going to the market. In `shoplist`,
+we only store strings of the names of the items to buy but you can add _any kind of object_ to a
+list including numbers and even other lists.
+
+We have also used the `for..in` loop to iterate through the items of the list. By now, you must
+have realised that a list is also a sequence. The speciality of sequences will be discussed in a
+<<sequence,later section>>.
+
+Notice the use of the trailing comma in the `print` statement to indicate that we want to end the
+output with a space instead of the usual line break. Think of the comma as telling Python that we
+have more items to print on the same line.
+
+Next, we add an item to the list using the `append` method of the list object, as already discussed
+before. Then, we check that the item has been indeed added to the list by printing the contents of
+the list by simply passing the list to the `print` statement which prints it neatly.
+
+Then, we sort the list by using the `sort` method of the list. It is important to understand that
+this method affects the list itself and does not return a modified list - this is different from
+the way strings work. This is what we mean by saying that lists are _mutable_ and that strings are
+_immutable_.
+
+Next, when we finish buying an item in the market, we want to remove it from the list. We achieve
+this by using the `del` statement. Here, we mention which item of the list we want to remove and
+the `del` statement removes it from the list for us.  We specify that we want to remove the first
+item from the list and hence we use `del shoplist[0]` (remember that Python starts counting from
+0).
+
+If you want to know all the methods defined by the list object, see `help(list)` for details.
+
+[[tuple]]
+=== Tuple
+
+Tuples are used to hold together multiple objects. Think of them as similar to lists, but without
+the extensive functionality that the list class gives you. One major feature of tuples is that they
+are *immutable* like strings i.e. you cannot modify tuples.
+
+Tuples are defined by specifying items separated by commas within an optional pair of parentheses.
+
+Tuples are usually used in cases where a statement or a user-defined function can safely assume
+that the collection of values i.e. the tuple of values used will not change.
+
+Example (save as `ds_using_tuple.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/ds_using_tuple.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/ds_using_tuple.txt[]
+--------------------------------------------------
+
+.How It Works
+
+The variable `zoo` refers to a tuple of items. We see that the `len` function can be used to get
+the length of the tuple. This also indicates that a tuple is a <<sequence,sequence>> as well.
+
+We are now shifting these animals to a new zoo since the old zoo is being closed. Therefore, the
+`new_zoo` tuple contains some animals which are already there along with the animals brought over
+from the old zoo. Back to reality, note that a tuple within a tuple does not lose its identity.
+
+We can access the items in the tuple by specifying the item's position within a pair of square
+brackets just like we did for lists. This is called the _indexing_ operator. We access the third
+item in `new_zoo` by specifying `new_zoo[2]` and we access the third item within the third item in
+the `new_zoo` tuple by specifying `new_zoo[2][2]`. This is pretty simple once you've understood the
+idiom.
+
+.Tuple with 0 or 1 items
+[NOTE]
+An empty tuple is constructed by an empty pair of parentheses such as `myempty = ()`. However, a
+tuple with a single item is not so simple. You have to specify it using a comma following the first
+(and only) item so that Python can differentiate between a tuple and a pair of parentheses
+surrounding the object in an expression i.e. you have to specify `singleton = (2 , )` if you mean
+you want a tuple containing the item `2`.
+
+.Note for Perl programmers
+[NOTE]
+A list within a list does not lose its identity i.e. lists are not flattened as in Perl. The same
+applies to a tuple within a tuple, or a tuple within a list, or a list within a tuple, etc. As far
+as Python is concerned, they are just objects stored using another object, that's all.
+
+[[dictionary]]
+=== Dictionary
+
+A dictionary is like an address-book where you can find the address or contact details of a person
+by knowing only his/her name i.e. we associate *keys* (name) with *values* (details). Note that the
+key must be unique just like you cannot find out the correct information if you have two persons
+with the exact same name.
+
+Note that you can use only immutable objects (like strings) for the keys of a dictionary but you
+can use either immutable or mutable objects for the values of the dictionary.  This basically
+translates to say that you should use only simple objects for keys.
+
+Pairs of keys and values are specified in a dictionary by using the notation `d = {key1 : value1,
+key2 : value2 }`. Notice that the key-value pairs are separated by a colon and the pairs are
+separated themselves by commas and all this is enclosed in a pair of curly braces.
+
+Remember that key-value pairs in a dictionary are not ordered in any manner. If you want a
+particular order, then you will have to sort them yourself before using it.
+
+The dictionaries that you will be using are instances/objects of the `dict` class.
+
+Example (save as `ds_using_dict.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/ds_using_dict.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/ds_using_dict.txt[]
+--------------------------------------------------
+
+.How It Works
+
+We create the dictionary `ab` using the notation already discussed. We then access key-value pairs
+by specifying the key using the indexing operator as discussed in the context of lists and
+tuples. Observe the simple syntax.
+
+We can delete key-value pairs using our old friend - the `del` statement. We simply specify the
+dictionary and the indexing operator for the key to be removed and pass it to the `del`
+statement. There is no need to know the value corresponding to the key for this operation.
+
+Next, we access each key-value pair of the dictionary using the `items` method of the dictionary
+which returns a list of tuples where each tuple contains a pair of items - the key followed by the
+value. We retrieve this pair and assign it to the variables `name` and `address` correspondingly
+for each pair using the `for..in` loop and then print these values in the for-block.
+
+We can add new key-value pairs by simply using the indexing operator to access a key and assign
+that value, as we have done for Guido in the above case.
+
+We can check if a key-value pair exists using the `in` operator.
+
+For the list of methods of the `dict` class, see `help(dict)`.
+
+.Keyword Arguments and Dictionaries
+[TIP]
+If you have used keyword arguments in your functions, you have already used dictionaries! Just
+think about it - the key-value pair is specified by you in the parameter list of the function
+definition and when you access variables within your function, it is just a key access of a
+dictionary (which is called the _symbol table_ in compiler design terminology).
+
+[[sequence]]
+=== Sequence
+
+Lists, tuples and strings are examples of sequences, but what are sequences and what is so special
+about them?
+
+The major features are *membership tests*, (i.e. the `in` and `not in` expressions) and *indexing
+operations*, which allow us to fetch a particular item in the sequence directly.
+
+The three types of sequences mentioned above - lists, tuples and strings, also have a *slicing*
+operation which allows us to retrieve a slice of the sequence i.e. a part of the sequence.
+
+Example (save as `ds_seq.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/ds_seq.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/ds_seq.txt[]
+--------------------------------------------------
+
+.How It Works
+
+First, we see how to use indexes to get individual items of a sequence. This is also referred to as
+the _subscription operation_. Whenever you specify a number to a sequence within square brackets as
+shown above, Python will fetch you the item corresponding to that position in the
+sequence. Remember that Python starts counting numbers from 0. Hence, `shoplist[0]` fetches the
+first item and `shoplist[3]` fetches the fourth item in the `shoplist`sequence.
+
+The index can also be a negative number, in which case, the position is calculated from the end of
+the sequence. Therefore, `shoplist[-1]` refers to the last item in the sequence and `shoplist[-2]`
+fetches the second last item in the sequence.
+
+The slicing operation is used by specifying the name of the sequence followed by an optional pair
+of numbers separated by a colon within square brackets. Note that this is very similar to the
+indexing operation you have been using till now. Remember the numbers are optional but the colon
+isn't.
+
+The first number (before the colon) in the slicing operation refers to the position from where the
+slice starts and the second number (after the colon) indicates where the slice will stop at. If the
+first number is not specified, Python will start at the beginning of the sequence. If the second
+number is left out, Python will stop at the end of the sequence. Note that the slice returned
+_starts_ at the start position and will end just before the _end_ position i.e. the start position
+is included but the end position is excluded from the sequence slice.
+
+Thus, `shoplist[1:3]` returns a slice of the sequence starting at position 1, includes position 2
+but stops at position 3 and therefore a *slice* of two items is returned.  Similarly, `shoplist[:]`
+returns a copy of the whole sequence.
+
+You can also do slicing with negative positions. Negative numbers are used for positions from the
+end of the sequence. For example, `shoplist[:-1]` will return a slice of the sequence which
+excludes the last item of the sequence but contains everything else.
+
+You can also provide a third argument for the slice, which is the _step_ for the slicing (by
+default, the step size is 1):
+
+[source,python]
+--------------------------------------------------
+>>> shoplist = ['apple', 'mango', 'carrot', 'banana']
+>>> shoplist[::1]
+['apple', 'mango', 'carrot', 'banana']
+>>> shoplist[::2]
+['apple', 'carrot']
+>>> shoplist[::3]
+['apple', 'banana']
+>>> shoplist[::-1]
+['banana', 'carrot', 'mango', 'apple']
+--------------------------------------------------
+
+Notice that when the step is 2, we get the items with position 0, 2,... When the step size is 3, we
+get the items with position 0, 3, etc.
+
+Try various combinations of such slice specifications using the Python interpreter interactively
+i.e. the prompt so that you can see the results immediately. The great thing about sequences is
+that you can access tuples, lists and strings all in the same way!
+
+[[set]]
+=== Set
+
+Sets are _unordered_ collections of simple objects. These are used when the existence of an object
+in a collection is more important than the order or how many times it occurs.
+
+Using sets, you can test for membership, whether it is a subset of another set, find the
+intersection between two sets, and so on.
+
+[source,python]
+--------------------------------------------------
+>>> bri = set(['brazil', 'russia', 'india'])
+>>> 'india' in bri
+True
+>>> 'usa' in bri
+False
+>>> bric = bri.copy()
+>>> bric.add('china')
+>>> bric.issuperset(bri)
+True
+>>> bri.remove('russia')
+>>> bri & bric # OR bri.intersection(bric)
+{'brazil', 'india'}
+--------------------------------------------------
+
+.How It Works
+
+The example is pretty much self-explanatory because it involves basic set theory mathematics taught
+in school.
+
+[[references]]
+=== References
+
+When you create an object and assign it to a variable, the variable only _refers_ to the object and
+does not represent the object itself!  That is, the variable name points to that part of your
+computer's memory where the object is stored. This is called *binding* the name to the object.
+
+Generally, you don't need to be worried about this, but there is a subtle effect due to references
+which you need to be aware of:
+
+Example (save as `ds_reference.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/ds_reference.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/ds_reference.txt[]
+--------------------------------------------------
+
+.How It Works
+
+Most of the explanation is available in the comments.
+
+Remember that if you want to make a copy of a list or such kinds of sequences or complex objects
+(not simple _objects_ such as integers), then you have to use the slicing operation to make a
+copy. If you just assign the variable name to another name, both of them will ''refer'' to the same
+object and this could be trouble if you are not careful.
+
+.Note for Perl programmers
+[NOTE]
+Remember that an assignment statement for lists does **not** create a copy. You have to use slicing
+operation to make a copy of the sequence.
+
+[[more_strings]]
+=== More About Strings
+
+We have already discussed strings in detail earlier. What more can there be to know?  Well, did you
+know that strings are also objects and have methods which do everything from checking part of a
+string to stripping spaces!
+
+The strings that you use in program are all objects of the class `str`.  Some useful methods of
+this class are demonstrated in the next example. For a complete list of such methods, see
+`help(str)`.
+
+Example (save as `ds_str_methods.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/ds_str_methods.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/ds_str_methods.txt[]
+--------------------------------------------------
+
+.How It Works
+
+Here, we see a lot of the string methods in action. The `startswith` method is used to find out
+whether the string starts with the given string. The `in` operator is used to check if a given
+string is a part of the string.
+
+The `find` method is used to locate the position of the given substring within the string; `find`
+returns -1 if it is unsuccessful in finding the substring. The `str` class also has a neat method
+to `join` the items of a sequence with the string acting as a delimiter between each item of the
+sequence and returns a bigger string generated from this.
+
+=== Summary
+
+We have explored the various built-in data structures of Python in detail. These data structures
+will be essential for writing programs of reasonable size.
+
+Now that we have a lot of the basics of Python in place, we will next see how to design and write a
+real-world Python program.

+ 13 - 0
dedication.asciidoc

@@ -0,0 +1,13 @@
+[[dedication]]
+[dedication]
+== Dedication
+
+To http://www.kalyanvarma.net/[Kalyan Varma] and many other seniors at http://www.pes.edu/[PESIT]
+who introduced us to GNU/Linux and the world of open source.
+
+To the memory of http://www.nextbigwhat.com/atul-chitnis-obituary-297/[Atul Chitnis], a friend and
+guide who shall be missed greatly.
+
+To the http://www.ibiblio.org/pioneers/index.html[pioneers who made the Internet happen]. This book
+was first written in 2003. It still remains popular, thanks to the nature of sharing knowledge on
+the Internet as envisioned by the pioneers.

+ 181 - 0
exceptions.asciidoc

@@ -0,0 +1,181 @@
+[[exceptions]]
+== Exceptions
+
+Exceptions occur when _exceptional_ situations occur in your program. For example, what if you are
+going to read a file and the file does not exist? Or what if you accidentally deleted it when the
+program was running? Such situations are handled using *exceptions*.
+
+Similarly, what if your program had some invalid statements? This is handled by Python which
+*raises* its hands and tells you there is an *error*.
+
+=== Errors
+
+Consider a simple `print` function call. What if we misspelt `print` as `Print`? Note the
+capitalization. In this case, Python _raises_ a syntax error.
+
+--------------------------------------------------
+>>> Print "Hello World"
+  File "<stdin>", line 1
+    Print "Hello World"
+                      ^
+SyntaxError: invalid syntax
+>>> print "Hello World"
+Hello World
+--------------------------------------------------
+
+Observe that a `SyntaxError` is raised and also the location where the error was detected is
+printed. This is what an *error handler* for this error does.
+
+=== Exceptions
+
+We will *try* to read input from the user. Press `ctrl-d` and see what happens.
+
+--------------------------------------------------
+>>> s = raw_input('Enter something --> ')
+Enter something --> Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+EOFError
+--------------------------------------------------
+
+Python raises an error called `EOFError` which basically means it found an *end of file* symbol
+(which is represented by `ctrl-d`) when it did not expect to see it.
+
+=== Handling Exceptions
+
+We can handle exceptions using the `try..except` statement.  We basically put our usual statements
+within the try-block and put all our error handlers in the except-block.
+
+Example (save as `exceptions_handle.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/exceptions_handle.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/exceptions_handle.txt[]
+--------------------------------------------------
+
+.How It Works
+
+We put all the statements that might raise exceptions/errors inside the `try` block and then put
+handlers for the appropriate errors/exceptions in the `except` clause/block. The `except` clause
+can handle a single specified error or exception, or a parenthesized list of errors/exceptions. If
+no names of errors or exceptions are supplied, it will handle _all_ errors and exceptions.
+
+Note that there has to be at least one `except` clause associated with every `try`
+clause. Otherwise, what's the point of having a try block?
+
+If any error or exception is not handled, then the default Python handler is called which just
+stops the execution of the program and prints an error message. We have already seen this in action
+above.
+
+You can also have an `else` clause associated with a `try..except` block. The `else` clause is
+executed if no exception occurs.
+
+In the next example, we will also see how to get the exception object so that we can retrieve
+additional information.
+
+=== Raising Exceptions
+
+You can _raise_ exceptions using the `raise` statement by providing the name of the error/exception
+and the exception object that is to be _thrown_.
+
+The error or exception that you can raise should be a class which directly or indirectly must be a
+derived class of the `Exception` class.
+
+Example (save as `exceptions_raise.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/exceptions_raise.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/exceptions_raise.txt[]
+--------------------------------------------------
+
+.How It Works
+
+Here, we are creating our own exception type. This new exception type is called
+`ShortInputException`. It has two fields - `length` which is the length of the given input, and
+`atleast` which is the minimum length that the program was expecting.
+
+In the `except` clause, we mention the class of error which will be stored `as` the variable name
+to hold the corresponding error/exception object. This is analogous to parameters and arguments in
+a function call. Within this particular `except` clause, we use the`length` and `atleast` fields of
+the exception object to print an appropriate message to the user.
+
+=== Try ... Finally
+
+Suppose you are reading a file in your program. How do you ensure that the file object is closed
+properly whether or not an exception was raised? This can be done using the `finally` block.
+
+Save this program as `exceptions_finally.py`:
+
+[source,python]
+--------------------------------------------------
+include::programs/exceptions_finally.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/exceptions_finally.txt[]
+--------------------------------------------------
+
+.How It Works
+
+We do the usual file-reading stuff, but we have arbitrarily introduced sleeping for 2 seconds after
+printing each line using the `time.sleep` function so that the program runs slowly (Python is very
+fast by nature). When the program is still running, press `ctrl + c` to interrupt/cancel the
+program.
+
+Observe that the `KeyboardInterrupt` exception is thrown and the program quits. However, before the
+program exits, the finally clause is executed and the file object is always closed.
+
+Note that we use `sys.stdout.flush()` after `print` so that it prints to the screen immediately.
+
+[[with]]
+=== The with statement
+
+Acquiring a resource in the `try` block and subsequently releasing the resource in the `finally`
+block is a common pattern. Hence, there is also a `with` statement that enables this to be done in
+a clean manner:
+
+Save as `exceptions_using_with.py`:
+
+[source,python]
+--------------------------------------------------
+include::programs/exceptions_using_with.py[]
+--------------------------------------------------
+
+.How It Works
+
+The output should be same as the previous example. The difference here is that we are using the
+`open` function with the `with` statement - we leave the closing of the file to be done
+automatically by `with open`.
+
+What happens behind the scenes is that there is a protocol used by the `with` statement. It fetches
+the object returned by the `open` statement, let's call it "thefile" in this case.
+
+It _always_ calls the `thefile.__enter__` function before starting the block of code under it and
+_always_ calls `thefile.__exit__` after finishing the block of code.
+
+So the code that we would have written in a `finally` block should be taken care of automatically
+by the `__exit__` method. This is what helps us to avoid having to use explicit `try..finally`
+statements repeatedly.
+
+More discussion on this topic is beyond scope of this book, so please refer
+http://www.python.org/dev/peps/pep-0343/[PEP 343] for a comprehensive explanation.
+
+=== Summary
+
+We have discussed the usage of the `try..except` and `try..finally` statements. We have seen how to
+create our own exception types and how to raise exceptions as well.
+
+Next, we will explore the Python Standard Library.

+ 216 - 0
first_steps.asciidoc

@@ -0,0 +1,216 @@
+[[first_steps]]
+== First Steps
+
+We will now see how to run a traditional 'Hello World' program in Python. This will teach you how
+to write, save and run Python programs.
+
+There are two ways of using Python to run your program - using the interactive interpreter prompt
+or using a source file. We will now see how to use both of these methods.
+
+=== Using The Interpreter Prompt
+
+Open the terminal in your operating system (as discussed previously in the
+<<installation,Installation>> chapter) and then open the Python prompt by typing +python+ and
+pressing kbd:[enter] key.
+
+Once you have started Python, you should see `>>>` where you can start typing stuff. This is called
+the _Python interpreter prompt_.
+
+At the Python interpreter prompt, type:
+
+[source,python]
+--------------------------------------------------
+print "Hello World"
+--------------------------------------------------
+
+followed by the kbd:[enter] key. You should see the words +Hello World+ printed to the screen.
+
+Here is an example of what you should be seeing, when using a Mac OS X computer. The details about
+the Python software will differ based on your computer, but the part from the prompt (i.e. from
+`>>>` onwards) should be the same regardless of the operating system.
+
+--------------------------------------------------
+$ python
+Python 2.7.6 (default, Feb 23 2014, 16:08:15)
+[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> print "hello world"
+hello world
+>>>
+--------------------------------------------------
+
+Notice that Python gives you the output of the line immediately! What you just entered is a single
+Python _statement_. We use +print+ to (unsurprisingly) print any value that you supply to it. Here,
+we are supplying the text +hello world+ and this is promptly printed to the screen.
+
+.How to Quit the Interpreter Prompt
+[NOTE]
+--
+If you are using a GNU/Linux or OS X shell, you can exit the interpreter prompt by pressing
+kbd:[ctrl + d] or entering +exit()+ (note: remember to include the parentheses, +()+) followed by
+the kbd:[enter] key.
+
+If you are using the Windows command prompt, press kbd:[ctrl + z] followed by the kbd:[enter] key.
+--
+
+=== Choosing An Editor
+
+We cannot type out our program at the interpreter prompt every time we want to run something, so we
+have to save them in files and can run our programs any number of times.
+
+To create our Python source files, we need an editor software where you can type and save. A good
+programmer's editor will make your life easier in writing the source files. Hence, the choice of an
+editor is crucial indeed. You have to choose an editor as you would choose a car you would buy. A
+good editor will help you write Python programs easily, making your journey more comfortable and
+helps you reach your destination (achieve your goal) in a much faster and safer way.
+
+One of the very basic requirements is _syntax highlighting_ where all the different parts of your
+Python program are colorized so that you can _see_ your program and visualize its running.
+
+If you have no idea where to start, I would recommend using http://www.lighttable.com/[Light Table]
+software which is available on Windows, Mac OS X and GNU/Linux. Details in the next section.
+
+If you are using Windows, *do not use Notepad* - it is a bad choice because it does not do syntax
+highlighting and also importantly it does not support indentation of the text which is very
+important in our case as we will see later. Good editors will automatically do this.
+
+If you are an experienced programmer, then you must be already using http://www.vim.org[Vim] or
+http://www.gnu.org/software/emacs/[Emacs]. Needless to say, these are two of the most powerful
+editors and you will benefit from using them to write your Python programs. I personally use both
+for most of my programs, and have even written an http://swaroopch.com/notes/vim[entire book on
+Vim].
+
+In case you are willing to take the time to learn Vim or Emacs, then I highly recommend that you do
+learn to use either of them as it will be very useful for you in the long run. However, as I
+mentioned before, beginners can start with Light Table and focus the learning on Python rather than
+the editor at this moment.
+
+To reiterate, please choose a proper editor - it can make writing Python programs more fun and
+easy.
+
+=== Light Table
+
+http://www.lighttable.com[Light Table] is a free editor which you can use for writing Python
+programs.
+
+Click on +File+ -> +New file+, type the following:
+
+[source,python]
+--------------------------------------------------
+print "hello world"
+--------------------------------------------------
+
+Click on +File+ -> +Save+ and call it +hello.py+.
+
+Click on +View+ -> +Console+.
+
+Now, place your cursor at the end of the above line and press kbd:[command + enter] to _evaluate_
+the line and you'll see the output in the console.
+
+Do watch the videos in the http://docs.lighttable.com/tutorials/python/[LightTable for Python
+tutorial] to understand how to use Light Table.
+
+image::light_table_screenshot.png[Screenshot of Light Table,594,536]
+
+=== Vim
+
+. Install http://www.vim.org[Vim]
+  .. Mac OS X users should install +macvim+ package via http://brew.sh/[HomeBrew]
+  .. Windows users should download the "self-installing executable" from
+  http://www.vim.org/download.php
+  .. GNU/Linux users should get Vim from their distribution's software repositories, e.g. Debian and
+  Ubuntu users can install the http://packages.ubuntu.com/saucy/vim[vim] package.
+. Read the http://blog.sontek.net/blog/detail/turning-vim-into-a-modern-python-ide[Vim as Python
+IDE] article by John M Anderson.
+. Install https://github.com/davidhalter/jedi-vim[jedi-vim] plugin for autocompletion.
+
+=== Emacs
+
+. Install http://www.gnu.org/software/emacs/[Emacs 24].
+  .. Mac OS X users should get Emacs from http://emacsformacosx.com
+  .. Windows users should get Emacs from http://ftp.gnu.org/gnu/emacs/windows/
+  .. GNU/Linux users should get Emacs from their distribution's software repositories, e.g. Debian
+  and Ubuntu users can install the http://packages.ubuntu.com/saucy/emacs24[emacs24] package.
+. Install https://github.com/jorgenschaefer/elpy[ELPY]
+. Read https://github.com/jorgenschaefer/elpy/wiki[ELPY wiki] for details.
+. Also recommended is the https://github.com/bbatsov/prelude[Emacs Prelude] distribution.
+
+=== Using A Source File
+
+Now let's get back to programming. There is a tradition that whenever you learn a new programming
+language, the first program that you write and run is the 'Hello World' program - all it does is
+just say 'Hello World' when you run it. As Simon Cozens footnote:[the author of the amazing
+'Beginning Perl' book] says, it is the "traditional incantation to the programming gods to help you
+learn the language better."
+
+Start your choice of editor, enter the following program and save it as +hello.py+.
+
+If you are using Light Table, click on +File+ -> +New file+, type the lines:
+
+[source,python]
+--------------------------------------------------
+print "hello world"
+--------------------------------------------------
+
+In Light Table, click on +File+ -> +Save+ to save a file called +hello.py+.
+
+Where should you save the file? To any folder for which you know the location of the folder. If you
+don't understand what that means, create a new folder and use that location to save and run all
+your Python programs:
+
+- `/tmp/py` on Mac OS X
+- `/tmp/py` on GNU/Linux
+- `C:\\py` on Windows
+
+To create the above folder (for the operating system you are using), use the +mkdir+ command in the
+terminal, for example, +mkdir /tmp/py+.
+
+IMPORTANT: Always ensure that you give it the file extension of +.py+, for example, +foo.py+.
+
+To run your Python program:
+
+. Open a terminal window (see the previous <<installation,Installation>> chapter on how to do that)
+. **C**hange **d**irectory to where you saved the file, for example, +cd /tmp/py+
+. Run the program by entering the command +python hello.py+. The output is as shown below.
+
+--------------------------------------------------
+$ python hello.py
+hello world
+--------------------------------------------------
+
+image::terminal_screenshot.png[Screenshot of running program in terminal,593,395]
+
+If you got the output as shown above, congratulations! - you have successfully run your first
+Python program. You have successfully crossed the hardest part of learning programming, which is,
+getting started with your first program!
+
+In case you got an error, please type the above program _exactly_ as shown above and run the
+program again. Note that Python is case-sensitive i.e. +print+ is not the same as +Print+ - note
+the lowercase +p+ in the former and the uppercase +P+ in the latter. Also, ensure there are no
+spaces or tabs before the first character in each line - we will see <<indentation,why this is
+important>> later.
+
+.How It Works
+A Python program is composed of _statements_. In our first program, we have only one statement. In
+this statement, we call the +print+ _statement_ to which we supply the text "hello world".
+
+=== Getting Help
+
+If you need quick information about any function or statement in Python, then you can use the
+built-in +help+ functionality. This is very useful especially when using the interpreter
+prompt. For example, run `help('len')` - this displays the help for the +len+ function which is
+used to count number of items.
+
+TIP: Press +q+ to exit the help.
+
+Similarly, you can obtain information about almost anything in Python. Use +help()+ to learn more
+about using +help+ itself!
+
+In case you need to get help for operators like +return+, then you need to put those inside quotes
+such as `help('return')` so that Python doesn't get confused on what we're trying to do.
+
+=== Summary
+
+You should now be able to write, save and run Python programs at ease.
+
+Now that you are a Python user, let's learn some more Python concepts.

+ 74 - 0
floss.asciidoc

@@ -0,0 +1,74 @@
+[[floss]]
+== Appendix: FLOSS
+
+NOTE: Please note that this section was written in 2003, so some of this might sound quaint to you
+:-)
+
+"Free/Libre and Open Source Software", in short, http://en.wikipedia.org/wiki/FLOSS[FLOSS] is based
+on the concept of a community, which itself is based on the concept of sharing, and particularly
+the sharing of knowledge. FLOSS are free for usage, modification and redistribution.
+
+If you have already read this book, then you are already familiar with FLOSS since you have been
+using *Python* all along and Python is an open source software!
+
+Here are some examples of FLOSS to give an idea of the kind of things that community sharing and
+building can create:
+
+http://www.kernel.org[Linux] ::
+This is a FLOSS OS kernel used in the GNU/Linux operating system. Linux, the kernel, was started by
+Linus Torvalds as a student. Android is based on Linux. Any website you use these days will mostly
+be running on Linux.
+
+http://www.ubuntu.com[Ubuntu] ::
+This is a community-driven distribution, sponsored by Canonical and it is the most popular
+GNU/Linux distribution today. It allows you to install a plethora of FLOSS available and all this
+in an easy-to-use and easy-to-install manner. Best of all, you can just reboot your computer and
+run GNU/Linux off the CD! This allows you to completely try out the new OS before installing it on
+your computer. However, Ubuntu is not entirely free software; it contains proprietary drivers,
+firmware, and applications.
+
+http://www.libreoffice.org/[LibreOffice] ::
+This is an excellent community-driven and developed office suite with a writer, presentation,
+spreadsheet and drawing components among other things. It can even open and edit MS Word and MS
+PowerPoint files with ease. It runs on almost all platforms and is entirely free, libre and open
+source software.
+
+http://www.mozilla.org/products/firefox[Mozilla Firefox] ::
+This is _the_ best web browser. It is blazingly fast and has gained critical acclaim for its
+sensible and impressive features. The extensions concept allows any kind of plugins to be used.
+
+http://www.mono-project.com[Mono] ::
+This is an open source implementation of the Microsoft .NET platform.  It allows .NET applications
+to be created and run on GNU/Linux, Windows, FreeBSD, Mac OS and many other platforms as well.
+
+http://httpd.apache.org[Apache web server] ::
+
+This is the popular open source web server. In fact, it is _the_ most popular web server on the
+planet! It runs nearly more than half of the websites out there. Yes, that's right - Apache handles
+more websites than all the competition (including Microsoft IIS) combined.
+
+http://www.videolan.org/vlc/[VLC Player] ::
+This is a video player that can play anything from DivX to MP3 to Ogg to VCDs and DVDs to ... who
+says open source ain't fun? ;-)
+
+This list is just intended to give you a brief idea - there are many more excellent FLOSS out
+there, such as the Perl language, PHP language, Drupal content management system for websites,
+PostgreSQL database server, TORCS racing game, KDevelop IDE, Xine - the movie player, VIM editor,
+Quanta+ editor, Banshee audio player, GIMP image editing program, ... This list could go on
+forever.
+
+To get the latest buzz in the FLOSS world, check out the following websites:
+
+- http://www.omgubuntu.co.uk/[OMG! Ubuntu!]
+- http://www.webupd8.org/[Web Upd8]
+- http://www.distrowatch.com[DistroWatch]
+- http://planet.debian.org/[Planet Debian]
+
+Visit the following websites for more information on FLOSS:
+
+- http://github.com/explore[GitHub Explore]
+- http://www.codetriage.com/[Code Triage]
+- http://www.sourceforge.net[SourceForge]
+- http://www.freshmeat.net[FreshMeat]
+
+So, go ahead and explore the vast, free and open world of FLOSS!

+ 374 - 0
frontpage.asciidoc

@@ -0,0 +1,374 @@
+[[frontpage]]
+==  Welcome
+
+//////////////////////////////////////////////////
+This book is written for Python 2 series, even though Python 3 series is the latest. You can read
+more about why in the <<python2vs3,Python 2 vs. 3>> section.
+//////////////////////////////////////////////////
+
+[[who_reads_bop]]
+=== Who reads A Byte of Python?
+
+Here are what people are saying about the book:
+
+[quote,'mailto:wmich50@theramp.net[Walt Michalik]']
+__________________________________________________
+This is the best beginner's tutorial I've ever seen! Thank you for your effort.
+__________________________________________________
+
+[quote,'mailto:joshrob@poczta.onet.pl[Joshua Robin]']
+__________________________________________________
+The best thing i found was "A Byte of Python", which is simply a brilliant book for a
+beginner. It's well written, the concepts are well explained with self evident examples.
+__________________________________________________
+
+[quote,'https://twitter.com/ShanRajasekaran/status/268910645842423809[Shan Rajasekaran]']
+__________________________________________________
+Excellent gentle introduction to programming #Python for beginners
+__________________________________________________
+
+[quote,'https://twitter.com/nickaigi/status/175508815729541120[Nickson Kaigi]']
+__________________________________________________
+Best newbie guide to python
+__________________________________________________
+
+[quote,'https://twitter.com/HerbertFeutl/status/11901471389913088[Herbert Feutl]']
+__________________________________________________
+start to love python with every single page read
+__________________________________________________
+
+[quote,'https://twitter.com/Dili_mathilakam/status/220033783066411008[Dilip]']
+__________________________________________________
+perfect beginners guide for python, will give u key to unlock magical world of python
+__________________________________________________
+
+[quote,'https://twitter.com/BiologistJohn/statuses/194726001803132928[Biologist John]']
+__________________________________________________
+I should be doing my actual "work" but just found "A Byte of Python". A great guide with great
+examples.
+__________________________________________________
+
+[quote,'https://twitter.com/mangeshnanoti/status/225680668867321857[Mangesh]']
+__________________________________________________
+Recently started reading a Byte of python. Awesome work. And that too for free. Highly recommended
+for aspiring pythonistas.
+__________________________________________________
+
+[quote,'http://apas.gr/2010/04/27/learning-python/[Apostolos]']
+__________________________________________________
+A Byte of Python, written by Swaroop. (this is the book I'm currently reading). Probably the best
+to start with, and probably the best in the world for every newbie or even a more experienced user.
+__________________________________________________
+
+[quote,Franklin]
+__________________________________________________
+Thank you so much for writing A Byte Of Python. I just started learning how to code two days ago
+and I'm already building some simple games. Your guide has been a dream and I just wanted to let
+you know how valuable it has been.
+__________________________________________________
+
+[quote,Madhura]
+__________________________________________________
+I'm from Dayanandasagar College of Engineering (7th sem, CSE). Firstly i want to say that your book
+"The byte of python" is too good a book for a beginner in python like me.The concepts are so well
+explained with simple examples that helped me to easily learn python. Thank you so much.
+__________________________________________________
+
+[quote,Matt]
+__________________________________________________
+I am a 18 year old IT student studying at University in Ireland. I would like to express my
+gratitude to you for writing your book "A Byte of Python", I already had knowledge of 3 programming
+langagues - C, Java and Javascript, and Python was by far the easiest langague I have ever learned,
+and that was mainly because your book was fantastic and made learning python very simple and
+interesting. It is one of the best written and easy to follow programming books I have ever
+read. Congratulations and keep up the great work.
+__________________________________________________
+
+[quote,'mailto:pavel.simo@gmail.com[Pavel Simo]']
+__________________________________________________
+Hi, I'm from Dominican Republic. My name is Pavel, recently I read your book _A Byte of Python_ and
+I consider it excellent!!  :). I learnt much from all the examples. Your book is of great help for
+newbies like me...
+__________________________________________________
+
+[quote,Roy Lau]
+__________________________________________________
+I am a student from China, Now ,I have read you book A byte of Python, Oh it's beautiful. The book
+is very simple but can help all the first learnners. You know I am interesting in Java and cloud
+computing many times, i have to coding programm for the server, so i think python is a good choice,
+finish your book, i think its not only a good choice its must use the Python. My English is not
+very well, the email to you, i just wanna thank you! Best Wishes for you and your family.
+__________________________________________________
+
+[quote,'mailto:sy137@gmail.com[Samuel Young]']
+__________________________________________________
+I recently finished reading Byte of Python, and I thought I really ought to thank you. I was very
+sad to reach the final pages as I now have to go back to dull, tedious oreilly or etc.  manuals for
+learning about python. Anyway, I really appreciate your book.
+__________________________________________________
+
+[quote,'mailto:jduarte1@cfl.rr.com[Joseph Duarte]']
+__________________________________________________
+Dear Swaroop, I am taking a class from an instructor that has no interest in teaching. We are using
+Learning Python, second edition, by O'Reilly. It is not a text for beginner without any programming
+knowledge, and an instructor that should be working in another field.  Thank you very much for your
+book, without it I would be clueless about Python and programming. Thanks a million, you are able
+to _break the message down_ to a level that beginners can understand and not everyone can.
+__________________________________________________
+
+[quote,Chris-André Sommerseth]
+__________________________________________________
+I love your book! It is the greatest Python tutorial ever, and a very useful reference. Brilliant,
+a true masterpiece! Keep up the good work!
+__________________________________________________
+
+[quote,'mailto:m_gallivan12@hotmail.com[Matt Gallivan]']
+__________________________________________________
+I'm just e-mailing you to thank you for writing Byte of Python online.  I had been attempting
+Python for a few months prior to stumbling across your book, and although I made limited success
+with pyGame, I never completed a program.
+
+Thanks to your simplification of the categories, Python actually seems a reachable goal. It seems
+like I have finally learned the foundations and I can continue into my real goal, game development.
+
+...
+
+Once again, thanks VERY much for placing such a structured and helpful guide to basic programming
+on the web.  It shoved me into and out of OOP with an understanding where two text books had
+failed.
+__________________________________________________
+
+[quote,'mailto:sedo_91@hotmail.com[Ahmed Mohammed]']
+__________________________________________________
+I would like to thank you for your book _A Byte of Python_ which i myself find the best way to
+learn python. I am a 15 year old i live in egypt my name is Ahmed. Python was my second programming
+language i learn visual basic 6 at school but didn't enjoy it, however i really enjoyed learning
+python. I made the addressbook program and i was sucessful. i will try to start make more programs
+and read python programs (if you could tell me source that would be helpful). I will also start on
+learning java and if you can tell me where to find a tutorial as good as yours for java that would
+help me a lot. Thanx.
+__________________________________________________
+
+[quote,'http://www.linux.com/feature/126522[Drew Ames]']
+__________________________________________________
+A wonderful resource for beginners wanting to learn more about Python is the 110-page PDF tutorial
+A Byte of Python by Swaroop C H. It is well-written, easy to follow, and may be the best
+introduction to Python programming available.
+__________________________________________________
+
+[quote,'http://paxmodept.com/telesto/blogitem.htm?id=627[Jason Delport]']
+__________________________________________________
+Yesterday I got through most of Byte of Python on my Nokia N800 and it's the easiest and most
+concise introduction to Python I have yet encountered. Highly recommended as a starting point for
+learning Python.
+__________________________________________________
+
+[quote,'http://twitter.com/suren/status/12840485454[Surendran]']
+__________________________________________________
+Byte of Vim and Python by @swaroopch is by far the best works in technical writing to me. Excellent
+reads #FeelGoodFactor
+__________________________________________________
+
+[quote,'http://www.facebook.com/pythonlang/posts/406873916788[Justin LoveTrue]']
+__________________________________________________
+"Byte of python" best one by far man
+
+(in response to the question "Can anyone suggest a good, inexpensive resource for learning the
+basics of Python? ")
+__________________________________________________
+
+[quote,'https://twitter.com/a_chinmay/status/258822633741762560[Chinmay]']
+__________________________________________________
+The Book Byte of python was very helpful ..Thanks bigtime :)
+__________________________________________________
+
+[quote,'http://stackoverflow.com/a/457785/4869[Patrick Harrington]']
+__________________________________________________
+Always been a fan of A Byte of Python - made for both new and experienced programmers.
+__________________________________________________
+
+[quote,'https://twitter.com/Pagal_e_azam/statuses/242865885256232960[Gadadhari Bheem]']
+__________________________________________________
+I started learning python few days ago from your book..thanks for such a nice book. it is so well
+written, you made my life easy..so you found a new fan of yours..thats me :) tons of thanks.
+__________________________________________________
+
+[quote,Bob]
+__________________________________________________
+Thank you ever so much for this book!!
+
+This book cleared up many questions I had about certain aspects of Python such as object oriented
+programming.
+
+I do not feel like an expert at OO but I know this book helped me on a first step or two.
+
+I have now written several python programs that actually do real things for me as a system
+administrator. They are all procedural oriented but they are small by most peoples standards.
+
+Again, thanks for this book. Thank you for having it on the web.
+__________________________________________________
+
+[quote,"The Walrus"]
+__________________________________________________
+I just want to thank you for writing the first book on programming I've ever really read. Python is
+now my first language, and I can just imagine all the possibilities. So thank you for giving me the
+tools to create things I never would have imagined I could do before.
+__________________________________________________
+
+[quote,Chris]
+__________________________________________________
+I wanted to thank you for writing _A Byte Of Python_ (2 & 3 Versions).  It has been invaluable to
+my learning experience in Python & Programming in general.
+
+Needless to say, I am a beginner in the programming world, a couple of months of self study up to
+this point. I had been using youtube tutorials & some other online tutorials including other free
+books. I decided to dig into your book yesterday, & I've learned more on the first few pages than
+any other book or tutorial. A few things I had been confused about, were cleared right up with a
+GREAT example & explanation. Can't wait to read (and learn) more!!
+
+Thank you so much for not only writing the book, but for putting it under the creative commons
+license (free). Thank goodness there are unselfish people like you out there to help & teach the
+rest of us.
+__________________________________________________
+
+[quote,Nick]
+__________________________________________________
+I wrote you back in 2011 and I was just getting into Python and wanted to thank you for your
+tutorial "A Byte of Python".  Without it, I would have fallen by the wayside.  Since then I have
+gone on to program a number of functions in my organization with this language with yet more on the
+horizon.  I would not call myself an advanced programmer by any stretch but I notice the occasional
+request for assistance now from others since I started using it.  I discovered, while reading
+"Byte" why I had ceased studying C and C\++ and it was because the book given to me started out with
+an example containing an augmented assignment.  Of course, there was no explanation for this
+arrangement of operators and I fell on my head trying to make sense of what was on the written
+page.  As I recall it was a most frustrating exercise which I eventually abandoned. Doesn't mean C
+or C++ is impossible to learn, or even that I am stupid, but it does mean that the documentation I
+worked my way through did not define the symbols and words which is an essential part of any
+instruction. Just as computers will not be able to understand a computer word or computer symbol
+that is outside the syntax for the language being used, a student new to any field will not grasp
+his subject if he encounters words or symbols for which there are no definitions.  You get a "blue
+screen" as it were in either case.  The solution is simple, though: find the word or symbol and get
+the proper definition or symbol and lo and behold,the computer or student can proceed.  Your book
+was so well put together that I found very little in it I couldn't grasp.  So, thank you.  I
+encourage you to continue to include full definitions of terms.  The documentation with Python is
+good, once you know, (the examples are its strength from what I see) but in many cases it seems
+that you have to know in order to understand the documentation which to my mind is not what
+should be.  Third party tutorials express the need for clarification of the documentation and their
+success largely depends on the words that are used to describe the terminology.  I have recommended
+your book to many others. Some in Australia, some in the Caribbean and yet others in the US. It
+fills a niche no others do.  I hope you are doing well and wish you all the success in the future.
+__________________________________________________
+
+[quote,Ankush]
+__________________________________________________
+hey, this is ankush(19). I was facing a great difficulty to start with python. I tried a lot of
+books but all were bulkier and not target oriented; and then i found this lovely one, which made me
+love python in no time. Thanks a lot for this "beautiful piece of book".
+__________________________________________________
+
+[quote,Luca]
+__________________________________________________
+I would like to thank you for your excellent guide on Python. I am a molecular biologist (with
+little programming background) and for my work I need to handle big datasets of DNA sequences and
+to analyse microscope images. For both things, programming in python has been useful, if not
+essential to complete and publish a 6-years project.
+
+That such a guide is freely available is a clear sign that the forces of evil are not yet ruling
+the world! :)
+__________________________________________________
+
+[quote,'http://www.overclock.net/t/1177951/want-to-learn-programming-where-do-i-start#post_15837176["{Unregistered}"]']
+__________________________________________________
+Since this is going to be the first language you learn, you should use A Byte of Python. It really
+gives a proper introduction into programming in Python and it is paced well enough for the average
+beginner. The most important thing from then on will be actually starting to practice making your
+own little programs.
+__________________________________________________
+
+[quote,Jocimar]
+__________________________________________________
+Just to say a loud and happy _thank you very much_ for publishing "A Byte of Python" and "A Byte of
+Vim". Those books were very useful to me four or five years ago when I starting learning
+programming. Right now I'm developing a project that was a dream for a long, long time and just
+want to say _thank you_. Keep walking. You are a source of motivation. All the best.
+__________________________________________________
+
+[quote,Dattatray]
+__________________________________________________
+Finished reading A byte of Python in 3 days. It is thoroughly interesting. Not a single page was
+boring. I want to understand the Orca screen reader code. Your book has hopefully equipped me
+for it.
+__________________________________________________
+
+The book is even used by NASA! It is being used in their
+http://dsnra.jpl.nasa.gov/software/Python/byte-of-python/output/byteofpython_html/[Jet Propulsion
+Laboratory] with their Deep Space Network project.
+
+=== Academic Courses
+
+This book is/was being used as instructional material in various educational institutions:
+
+- 'Principles of Programming Languages' course at
+  http://www.few.vu.nl/~nsilvis/PPL/2007/index.html['Vrije Universiteit, Amsterdam']
+- 'Basic Concepts of Computing' course at
+  http://www.cs.ucdavis.edu/courses/exp_course_desc/10.html['University of California, Davis']
+- 'Programming With Python' course at
+  http://www.people.fas.harvard.edu/~preshman/python_winter.html['Harvard University']
+- 'Introduction to Programming' course at http://www.comp.leeds.ac.uk/acom1900/['University of
+  Leeds']
+- 'Introduction to Application Programming' course at
+  http://www.cs.bu.edu/courses/cs108/materials.html['Boston University']
+- 'Information Technology Skills for Meteorology' course at
+  http://gentry.metr.ou.edu/byteofpython/['University of Oklahoma']
+- 'Geoprocessing' course at http://www.msu.edu/~ashton/classes/825/index.html['Michigan State
+  University']
+- 'Multi Agent Semantic Web Systems' course at the
+  http://homepages.inf.ed.ac.uk/ewan/masws/['University of Edinburgh']
+- 'Introduction to Computer Science and Programming' at
+  http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-00sc-introduction-to-computer-science-and-programming-spring-2011/references/['MIT
+  OpenCourseWare']
+
+=== License
+
+This book is licensed under a http://creativecommons.org/licenses/by-sa/4.0/[Creative Commons
+Attribution-ShareAlike 4.0 International License].
+
+This means:
+
+- You are free to Share i.e. to copy, distribute and transmit this book
+- You are free to Remix i.e. to make changes to this book (especially translations)
+- You are free to use it for commercial purposes
+
+Please note:
+
+- Please do *not* sell electronic or printed copies of the book unless you have clearly and
+  prominently mentioned in the description that these copies are *not* from the original author of
+  this book.
+- Attribution *must* be shown in the introductory description and front page of the document by
+  linking back to {homepage} and clearly indicating that the original text can be fetched from this
+  location.
+- All the code/scripts provided in this book is licensed under the
+  http://www.opensource.org/licenses/bsd-license.php[3-clause BSD License] unless otherwise noted.
+
+=== Read Now
+
+You can read the book online at {homepage}
+
+=== Buy The Book
+
+A printed hardcopy of the book can be purchased at {buy} for your offline reading pleasure, and to
+support the continued development and improvement of this book.
+
+=== Download
+
+- http://files.swaroopch.com/python/byte_of_python.pdf[PDF]
+- http://files.swaroopch.com/python/byte_of_python.epub[EPUB]
+- https://github.com/swaroopch/byte_of_python[GitHub]
+
+If you wish to support the continued development of this book, please consider
+{buy}[buying a hardcopy].
+
+=== Read the book in your native language
+
+If you are interested in reading or contributing translations of this book to other human
+languages, please see <<translations,Translations>>.

+ 358 - 0
functions.asciidoc

@@ -0,0 +1,358 @@
+[[functions]]
+== Functions
+
+Functions are reusable pieces of programs. They allow you to give a name to a block of statements,
+allowing you to run that block using the specified name anywhere in your program and any number of
+times. This is known as *calling* the function. We have already used many built-in functions such
+as `len` and `range`.
+
+The function concept is probably *the* most important building block of any non-trivial software
+(in any programming language), so we will explore various aspects of functions in this chapter.
+
+Functions are defined using the `def` keyword. After this keyword comes an *identifier* name for
+the function, followed by a pair of parentheses which may enclose some names of variables, and by
+the final colon that ends the line. Next follows the block of statements that are part of this
+function. An example will show that this is actually very simple:
+
+Example (save as `function1.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/function1.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/function1.txt[]
+--------------------------------------------------
+
+.How It Works
+
+We define a function called `say_hello` using the syntax as explained above. This function takes no
+parameters and hence there are no variables declared in the parentheses. Parameters to functions
+are just input to the function so that we can pass in different values to it and get back
+corresponding results.
+
+Notice that we can call the same function twice which means we do not have to write the same code
+again.
+
+[[function_parameters]]
+=== Function Parameters
+
+A function can take parameters, which are values you supply to the function so that the function
+can *do* something utilising those values. These parameters are just like variables except that the
+values of these variables are defined when we call the function and are already assigned values
+when the function runs.
+
+Parameters are specified within the pair of parentheses in the function definition, separated by
+commas. When we call the function, we supply the values in the same way.  Note the terminology
+used - the names given in the function definition are called *parameters* whereas the values you
+supply in the function call are called *arguments*.
+
+Example (save as `function_param.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/function_param.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/function_param.txt[]
+--------------------------------------------------
+
+.How It Works
+
+Here, we define a function called `print_max` that uses two parameters called `a` and `b`.  We find
+out the greater number using a simple `if..else` statement and then print the bigger number.
+
+The first time we call the function `print_max`, we directly supply the numbers as arguments. In
+the second case, we call the function with variables as arguments. `print_max(x, y)` causes the
+value of argument `x` to be assigned to parameter `a` and the value of argument `y` to be assigned
+to parameter `b`. The printMax function works the same way in both cases.
+
+[[local_variables]]
+=== Local Variables
+
+When you declare variables inside a function definition, they are not related in any way to other
+variables with the same names used outside the function - i.e. variable names are *local* to the
+function. This is called the *scope* of the variable. All variables have the scope of the block
+they are declared in starting from the point of definition of the name.
+
+Example (save as `function_local.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/function_local.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/function_local.txt[]
+--------------------------------------------------
+
+.How It Works
+
+The first time that we print the *value* of the name *x* with the first line in the function's
+body, Python uses the value of the parameter declared in the main block, above the function
+definition.
+
+Next, we assign the value `2` to `x`. The name `x` is local to our function.  So, when we change
+the value of `x` in the function, the `x` defined in the main block remains unaffected.
+
+With the last `print` statement, we display the value of `x` as defined in the main block, thereby
+confirming that it is actually unaffected by the local assignment within the previously called
+function.
+
+[[the_global_statement]]
+=== The +global+ statement
+
+If you want to assign a value to a name defined at the top level of the program (i.e. not inside
+any kind of scope such as functions or classes), then you have to tell Python that the name is not
+local, but it is *global*. We do this using the `global` statement. It is impossible to assign a
+value to a variable defined outside a function without the `global` statement.
+
+You can use the values of such variables defined outside the function (assuming there is no
+variable with the same name within the function). However, this is not encouraged and should be
+avoided since it becomes unclear to the reader of the program as to where that variable's
+definition is. Using the `global` statement makes it amply clear that the variable is defined in an
+outermost block.
+
+Example (save as `function_global.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/function_global.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/function_global.txt[]
+--------------------------------------------------
+
+.How It Works
+
+The `global` statement is used to declare that `x` is a global variable - hence, when we assign a
+value to `x` inside the function, that change is reflected when we use the value of `x` in the main
+block.
+
+You can specify more than one global variable using the same `global` statement e.g. `global x, y,
+z`.
+
+[[default_argument_values]]
+=== Default Argument Values
+
+For some functions, you may want to make some parameters *optional* and use default values in case
+the user does not want to provide values for them. This is done with the help of default argument
+values. You can specify default argument values for parameters by appending to the parameter name
+in the function definition the assignment operator (`=`) followed by the default value.
+
+Note that the default argument value should be a constant. More precisely, the default argument
+value should be immutable - this is explained in detail in later chapters. For now, just remember
+this.
+
+Example (save as `function_default.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/function_default.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/function_default.txt[]
+--------------------------------------------------
+
+.How It Works
+
+The function named `say` is used to print a string as many times as specified. If we don't supply a
+value, then by default, the string is printed just once. We achieve this by specifying a default
+argument value of `1` to the parameter `times`.
+
+In the first usage of `say`, we supply only the string and it prints the string once. In the second
+usage of `say`, we supply both the string and an argument `5` stating that we want to *say* the
+string message 5 times.
+
+[CAUTION]
+--
+Only those parameters which are at the end of the parameter list can be given default argument
+values i.e. you cannot have a parameter with a default argument value preceding a parameter without
+a default argument value in the function's parameter list.
+
+This is because the values are assigned to the parameters by position. For example,`def func(a,
+b=5)` is valid, but `def func(a=5, b)` is *not valid*.
+--
+
+[[keyword_arguments]]
+=== Keyword Arguments
+
+If you have some functions with many parameters and you want to specify only some of them, then you
+can give values for such parameters by naming them - this is called *keyword arguments* - we use
+the name (keyword) instead of the position (which we have been using all along) to specify the
+arguments to the function.
+
+There are two advantages - one, using the function is easier since we do not need to worry about
+the order of the arguments. Two, we can give values to only those parameters to which we want to,
+provided that the other parameters have default argument values.
+
+Example (save as `function_keyword.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/function_keyword.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/function_keyword.txt[]
+--------------------------------------------------
+
+.How It Works
+
+The function named `func` has one parameter without a default argument value, followed by two
+parameters with default argument values.
+
+In the first usage, `func(3, 7)`, the parameter `a` gets the value `3`, the parameter `b` gets the
+value `7` and `c` gets the default value of `10`.
+
+In the second usage `func(25, c=24)`, the variable `a` gets the value of 25 due to the position of
+the argument. Then, the parameter `c` gets the value of `24` due to naming i.e. keyword
+arguments. The variable `b` gets the default value of `5`.
+
+In the third usage `func(c=50, a=100)`, we use keyword arguments for all specified values. Notice
+that we are specifying the value for parameter `c` before that for `a` even though `a` is defined
+before `c` in the function definition.
+
+[[varargs_parameters]]
+=== VarArgs parameters
+
+Sometimes you might want to define a function that can take _any_ number of parameters,
+i.e. **var**iable number of **arg**uments, this can be achieved by using the stars (save as
+`function_varargs.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/function_varargs.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/function_varargs.txt[]
+--------------------------------------------------
+
+.How It Works
+
+When we declare a starred parameter such as `*param`, then all the positional arguments from that
+point till the end are collected as a tuple called 'param'.
+
+Similarly, when we declare a double-starred parameter such as `**param`, then all the keyword
+arguments from that point till the end are collected as a dictionary called 'param'.
+
+We will explore tuples and dictionaries in a <<data_structures,later chapter>>.
+
+[[the_return_statement]]
+=== The +return+ statement
+
+The `return` statement is used to *return* from a function i.e. break out of the function. We can
+optionally *return a value* from the function as well.
+
+Example (save as `function_return.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/function_return.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/function_return.txt[]
+--------------------------------------------------
+
+.How It Works
+
+The `maximum` function returns the maximum of the parameters, in this case the numbers supplied to
+the function. It uses a simple `if..else` statement to find the greater value and then *returns*
+that value.
+
+Note that a `return` statement without a value is equivalent to `return None`. `None` is a special
+type in Python that represents nothingness. For example, it is used to indicate that a variable has
+no value if it has a value of `None`.
+
+Every function implicitly contains a `return None` statement at the end unless you have written
+your own `return` statement. You can see this by running `print some_function()` where the function
+`some_function` does not use the `return` statement such as:
+
+[source,python]
+--------------------------------------------------
+def some_function():
+    pass
+--------------------------------------------------
+
+The `pass` statement is used in Python to indicate an empty block of statements.
+
+TIP: There is a built-in function called `max` that already implements the 'find maximum'
+functionality, so use this built-in function whenever possible.
+
+[[docstrings]]
+=== DocStrings
+
+Python has a nifty feature called *documentation strings*, usually referred to by its shorter name
+*docstrings*. DocStrings are an important tool that you should make use of since it helps to
+document the program better and makes it easier to understand. Amazingly, we can even get the
+docstring back from, say a function, when the program is actually running!
+
+Example (save as `function_docstring.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/function_docstring.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/function_docstring.txt[]
+--------------------------------------------------
+
+.How It Works
+
+A string on the first logical line of a function is the *docstring* for that function. Note that
+DocStrings also apply to <<modules,modules>> and <<oop,classes>> which we will learn about in the
+respective chapters.
+
+The convention followed for a docstring is a multi-line string where the first line starts with a
+capital letter and ends with a dot. Then the second line is blank followed by any detailed
+explanation starting from the third line. You are *strongly advised* to follow this convention for
+all your docstrings for all your non-trivial functions.
+
+We can access the docstring of the `print_max` function using the `__doc__` (notice the *double
+underscores*) attribute (name belonging to) of the function. Just remember that Python treats
+*everything* as an object and this includes functions. We'll learn more about objects in the
+chapter on <<oop,classes>>.
+
+If you have used `help()` in Python, then you have already seen the
+usage of docstrings! What it does is just fetch the `__doc__`
+attribute of that function and displays it in a neat manner for
+you. You can try it out on the function above - just include `help(print_max)` in your
+program. Remember to press the `q` key to exit `help`.
+
+Automated tools can retrieve the documentation from your program in this manner. Therefore, I
+*strongly recommend* that you use docstrings for any non-trivial function that you write. The
+`pydoc` command that comes with your Python distribution works similarly to `help()` using
+docstrings.
+
+=== Summary
+
+We have seen so many aspects of functions but note that we still haven't covered all aspects of
+them. However, we have already covered most of what you'll use regarding Python functions on an
+everyday basis.
+
+Next, we will see how to use as well as create Python modules.

+ 96 - 0
installation.asciidoc

@@ -0,0 +1,96 @@
+[[installation]]
+== Installation
+
+When we refer to "Python 2" in this book, we will be referring to any version of Python equal to or
+greater than version https://www.python.org/downloads/[*2.7*].
+
+[[install_windows]]
+=== Installation on Windows
+
+Visit https://www.python.org/downloads/ and download the latest version. The installation is just
+like any other Windows-based software.
+
+CAUTION: When you are given the option of unchecking any "optional" components, don't uncheck any.
+
+[[dos_prompt]]
+==== DOS Prompt
+
+If you want to be able to use Python from the Windows command line i.e. the DOS prompt, then you
+need to set the PATH variable appropriately.
+
+For Windows 2000, XP, 2003 , click on +Control Panel+ -> +System+ -> +Advanced+ -> +Environment
+Variables+. Click on the variable named +PATH+ in the _System Variables_ section, then select
++Edit+ and add `;C:\Python27` (please verify that this folder exists, it will be different for
+newer versions of Python) to the end of what is already there. Of course, use the appropriate
+directory name.
+
+For older versions of Windows, open the file `C:\AUTOEXEC.BAT` and add the line
+`PATH=%PATH%;C:\Python33` and restart the system. For Windows NT, use the +AUTOEXEC.NT+ file.
+
+For Windows Vista:
+
+. Click Start and choose +Control Panel+
+. Click System, on the right you'll see "View basic information about your computer"
+. On the left is a list of tasks, the last of which is +Advanced system settings+. Click that.
+. The +Advanced+ tab of the +System Properties+ dialog box is shown. Click the +Environment
+Variables+ button on the bottom right.
+. In the lower box titled +System Variables+ scroll down to Path and click the +Edit+ button.
+. Change your path as need be.
+. Restart your system. Vista didn't pick up the system path environment variable change until I
+restarted.
+
+For Windows 7:
+
+. Right click on Computer from your desktop and select +Properties+ or click +Start+ and choose
++Control Panel+ -> +System and Security+ -> +System+. Click on +Advanced system settings+ on the
+left and then click on the +Advanced+ tab. At the bottom click on +Environment Variables+ and under
++System variables+, look for the +PATH+ variable, select and then press +Edit+.
+. Go to the end of the line under Variable value and append `;C:\Python33`.
+. If the value was `%SystemRoot%\system32;` It will now become `%SystemRoot%\system32;C:\Python33`
+. Click +OK+ and you are done. No restart is required.
+
+==== Running Python prompt on Windows
+
+For Windows users, you can run the interpreter in the command line if you have <<dos_prompt,set the
+`PATH` variable appropriately>>.
+
+To open the terminal in Windows, click the start button and click +Run+. In the dialog box, type
++cmd+ and press kbd:[enter] key.
+
+Then, type +python+ and ensure there are no errors.
+
+[[install_osx]]
+=== Installation on Mac OS X
+
+For Mac OS X users, Python must be installed already.
+
+To verify, open the terminal by pressing kbd:[Command + Space] keys (to open Spotlight search),
+type +Terminal+ and press kbd:[enter] key. Now, run +python+ and ensure there are no errors.
+
+[[install_linux]]
+=== Installation on GNU/Linux
+
+For GNU/Linux users, Python must be installed already.
+
+To verify, open the terminal by opening the +Terminal+ application or by pressing kbd:[Alt + F2]
+and entering +gnome-terminal+. If that doesn't work, please refer the documentation of your
+particular GNU/Linux distribution. Now, run +python+ and ensure there are no errors.
+
+You can see the version of Python on the screen by running:
+
+--------------------------------------------------
+$ python -V
+Python 2.7.6
+--------------------------------------------------
+
+NOTE: `$` is the prompt of the shell. It will be different for you depending on the settings of the
+operating system on your computer, hence I will indicate the prompt by just the `$` symbol.
+
+CAUTION: Output may be different on your computer, depending on the version of Python software
+installed on your computer.
+
+=== Summary
+
+From now on, we will assume that you have Python installed on your system.
+
+Next, we will write our first Python program.

+ 142 - 0
intro.asciidoc

@@ -0,0 +1,142 @@
+[[intro]]
+== Introduction
+
+Python is one of those rare languages which can claim to be both _simple_ and _powerful_.  You will
+find yourself pleasantly surprised to see how easy it is to concentrate on the solution to the
+problem rather than the syntax and structure of the language you are programming in.
+
+The official introduction to Python is:
+
+__________________________________________________
+Python is an easy to learn, powerful programming language. It has efficient high-level data
+structures and a simple but effective approach to object-oriented programming. Python's elegant
+syntax and dynamic typing, together with its interpreted nature, make it an ideal language for
+scripting and rapid application development in many areas on most platforms.
+__________________________________________________
+
+I will discuss most of these features in more detail in the next section.
+
+.Story behind the name
+**************************************************
+Guido van Rossum, the creator of the Python language, named the language after the BBC show "Monty
+Python's Flying Circus". He doesn't particularly like snakes that kill animals for food by winding
+their long bodies around them and crushing them.
+**************************************************
+
+=== Features of Python
+
+ Simple ::
+Python is a simple and minimalistic language. Reading a good Python program feels almost like
+reading English, although very strict English! This pseudo-code nature of Python is one of its
+greatest strengths. It allows you to concentrate on the solution to the problem rather than the
+language itself.
+
+Easy to Learn ::
+As you will see, Python is extremely easy to get started with. Python has an extraordinarily simple
+syntax, as already mentioned.
+
+Free and Open Source ::
+Python is an example of a _FLOSS_ (Free/Libré and Open Source Software). In simple terms, you can
+freely distribute copies of this software, read its source code, make changes to it, and use pieces
+of it in new free programs. FLOSS is based on the concept of a community which shares
+knowledge. This is one of the reasons why Python is so good - it has been created and is constantly
+improved by a community who just want to see a better Python.
+
+High-level Language ::
+When you write programs in Python, you never need to bother about the low-level details such as
+managing the memory used by your program, etc.
+
+Portable ::
+Due to its open-source nature, Python has been ported to (i.e. changed to make it work on) many
+platforms. All your Python programs can work on any of these platforms without requiring any
+changes at all if you are careful enough to avoid any system-dependent features.
++
+You can use Python on GNU/Linux, Windows, FreeBSD, Macintosh, Solaris, OS/2, Amiga, AROS, AS/400,
+BeOS, OS/390, z/OS, Palm OS, QNX, VMS, Psion, Acorn RISC OS, VxWorks, PlayStation, Sharp Zaurus,
+Windows CE and PocketPC!
++
+You can even use a platform like http://kivy.org[Kivy] to create games for your computer _and_ for
+iPhone, iPad, and Android.
+
+[[interpreted]]
+Interpreted ::
+This requires a bit of explanation.
++
+A program written in a compiled language like C or C\++ is converted from the source language
+i.e. C or C++ into a language that is spoken by your computer (binary code i.e. 0s and 1s) using a
+compiler with various flags and options. When you run the program, the linker/loader software
+copies the program from hard disk to memory and starts running it.
++
+Python, on the other hand, does not need compilation to binary. You just _run_ the program directly
+from the source code. Internally, Python converts the source code into an intermediate form called
+bytecodes and then translates this into the native language of your computer and then runs it. All
+this, actually, makes using Python much easier since you don't have to worry about compiling the
+program, making sure that the proper libraries are linked and loaded, etc. This also makes your
+Python programs much more portable, since you can just copy your Python program onto another
+computer and it just works!
+
+Object Oriented ::
+Python supports procedure-oriented programming as well as object-oriented programming. In
+_procedure-oriented_ languages, the program is built around procedures or functions which are
+nothing but reusable pieces of programs. In _object-oriented_ languages, the program is built
+around objects which combine data and functionality. Python has a very powerful but simplistic way
+of doing OOP, especially when compared to big languages like C++ or Java.
+
+Extensible ::
+If you need a critical piece of code to run very fast or want to have some piece of algorithm not
+to be open, you can code that part of your program in C or C\++ and then use it from your Python
+program.
+
+Embeddable ::
+You can embed Python within your C/C\++ programs to give _scripting_ capabilities for your
+program's users.
+
+Extensive Libraries ::
+The Python Standard Library is huge indeed. It can help you do various things involving regular
+expressions,documentation generation, unit testing, threading, databases, web browsers, CGI, FTP,
+email, XML, XML-RPC, HTML, WAV files, cryptography, GUI (graphical user interfaces), and other
+system-dependent stuff. Remember, all this is always available wherever Python is installed. This
+is called the _Batteries Included_ philosophy of Python.
++
+Besides the standard library, there are various other high-quality libraries which you can find at
+the http://pypi.python.org/pypi[Python Package Index].
+
+Summary ::
+Python is indeed an exciting and powerful language. It has the right combination of performance and
+features that make writing programs in Python both fun and easy.
+
+=== Python 2 versus 3
+
+You can ignore this section if you're not interested in the difference between Python 2 and
+Python 3. But please do be aware of which version you are using.
+
+Remember that once you have properly understood and learn to use either of them, you can easily
+learn the changes between the two versions and adapt easily. The hard part is learning programming
+and understanding the core Python language itself. That is our goal in this book, and once you have
+achieved that goal, you can easily use Python 2 or Python 3 depending on your situation.
+
+For details on differences between Python 2 to Python 3, see:
+
+- http://lwn.net/Articles/547191/[The future of Python 2]
+- https://wiki.ubuntu.com/Python/3[Python/3 page on the Ubuntu wiki]
+
+=== What Programmers Say
+
+You may find it interesting to read what great hackers like ESR have to say about Python:
+
+. _Eric S. Raymond_ is the author of "The Cathedral and the Bazaar" and is also the person who
+coined the term _Open Source_. He says that http://www.python.org/about/success/esr/[Python has
+become his favorite programming language]. This article was the real inspiration for my first brush
+with Python.
+
+. _Bruce Eckel_ is the author of the famous 'Thinking in Java' and 'Thinking in C++' books. He says
+that no language has made him more productive than Python. He says that Python is perhaps the only
+language that focuses on making things easier for the programmer. Read the
+http://www.artima.com/intv/aboutme.html[complete interview] for more details.
+
+. _Peter Norvig_ is a well-known Lisp author and Director of Search Quality at Google (thanks to
+Guido van Rossum for pointing that out). He says that
+https://news.ycombinator.com/item?id=1803815[writing Python is like writing in pseudocode]. He says
+that Python has always been an integral part of Google. You can actually verify this statement by
+looking at the http://www.google.com/jobs/index.html[Google Jobs] page which lists Python knowledge
+as a requirement for software engineers.

+ 180 - 0
io.asciidoc

@@ -0,0 +1,180 @@
+[[io]]
+== Input and Output
+
+There will be situations where your program has to interact with the user. For example, you would
+want to take input from the user and then print some results back. We can achieve this using the
+`raw_input()` function and `print` statement respectively.
+
+For output, we can also use the various methods of the `str` (string) class. For example, you can
+use the `rjust` method to get a string which is right justified to a specified width. See
+`help(str)` for more details.
+
+Another common type of input/output is dealing with files. The ability to create, read and write
+files is essential to many programs and we will explore this aspect in this chapter.
+
+=== Input from user
+
+Save this program as `io_input.py`:
+
+[source,python]
+--------------------------------------------------
+include::programs/io_input.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/io_input.txt[]
+--------------------------------------------------
+
+.How It Works
+
+We use the slicing feature to reverse the text. We've already seen how we can make
+<<sequence,slices from sequences>> using the `seq[a:b]` code starting from position `a` to position
+`b`. We can also provide a third argument that determines the _step_ by which the slicing is
+done. The default step is `1` because of which it returns a continuous part of the text. Giving a
+negative step, i.e., `-1` will return the text in reverse.
+
+The `raw_input()` function takes a string as argument and displays it to the user. Then it waits
+for the user to type something and press the return key. Once the user has entered and pressed the
+return key, the `raw_input()` function will then return that text the user has entered.
+
+We take that text and reverse it. If the original text and reversed text are equal, then the text
+is a http://en.wiktionary.org/wiki/palindrome[palindrome].
+
+==== Homework exercise
+
+Checking whether a text is a palindrome should also ignore punctuation, spaces and case. For
+example, "Rise to vote, sir." is also a palindrome but our current program doesn't say it is. Can
+you improve the above program to recognize this palindrome?
+
+If you need a hint, the idea is that... footnote:[Use a tuple (you can find a list of _all_
+http://grammar.ccc.commnet.edu/grammar/marks/marks.htm[punctuation marks here]) to hold all the
+forbidden characters, then use the membership test to determine whether a character should be
+removed or not, i.e. forbidden = (`!`, `?`, `.`, ...).]
+
+=== Files
+
+You can open and use files for reading or writing by creating an object of the `file` class and
+using its `read`, `readline` or `write` methods appropriately to read from or write to the
+file. The ability to read or write to the file depends on the mode you have specified for the file
+opening. Then finally, when you are finished with the file, you call the `close` method to tell
+Python that we are done using the file.
+
+Example (save as `io_using_file.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/io_using_file.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/io_using_file.txt[]
+--------------------------------------------------
+
+.How It Works
+
+First, open a file by using the built-in `open` function and specifying the name of the file and
+the mode in which we want to open the file. The mode can be a read mode (`'r'`), write mode (`'w'`)
+or append mode (`'a'`). We can also specify whether we are reading, writing, or appending in text
+mode (`'t'`) or binary mode (`'b'`). There are actually many more modes available and `help(open)`
+will give you more details about them. By default, `open()` considers the file to be a 't'ext file
+and opens it in 'r'ead mode.
+
+In our example, we first open the file in write text mode and use the `write` method of the file
+object to write to the file and then we finally `close` the file.
+
+Next, we open the same file again for reading. We don't need to specify a mode because 'read text
+file' is the default mode. We read in each line of the file using the `readline` method in a
+loop. This method returns a complete line including the newline character at the end of the
+line. When an _empty_ string is returned, it means that we have reached the end of the file and we
+'break' out of the loop.
+
+In the end, we finally `close`the file.
+
+Now, check the contents of the `poem.txt` file to confirm that the program has indeed written to
+and read from that file.
+
+[[pickle]]
+=== Pickle
+
+Python provides a standard module called `pickle` using which you can store _any_ plain Python
+object in a file and then get it back later. This is called storing the object *persistently*.
+
+Example (save as `io_pickle.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/io_pickle.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/io_pickle.txt[]
+--------------------------------------------------
+
+.How It Works
+
+To store an object in a file, we have to first `open` the file in __w__rite __b__inary mode and
+then call the `dump` function of the `pickle` module. This process is called _pickling_.
+
+Next, we retrieve the object using the `load` function of the `pickle` module which returns the
+object. This process is called _unpickling_.
+
+[[unicode]]
+=== Unicode
+
+So far, when we have been writing and using strings, or reading and writing to a file, we have used
+simple English characters only. If we want to be able to read and write other non-English
+languages, we need to use the `unicode` type, and it all starts with the character `u`:
+
+--------------------------------------------------
+>>> "hello world"
+'hello world'
+>>> type("hello world")
+<type 'str'>
+>>> u"hello world"
+u'hello world'
+>>> type(u"hello world")
+<type 'unicode'>
+--------------------------------------------------
+
+We use the `unicode` type instead of `strings` to make sure that we handle non-English languages in
+our programs. However, when we read or write to a file or when we talk to other computers on the
+Internet, we need to convert our unicode strings into a format that can be sent and received, and
+that format is called "UTF-8". We can read and write in that format, using a simple keyword
+argument to our standard `open` function:
+
+[source,python]
+--------------------------------------------------
+include::programs/io_unicode.py[]
+--------------------------------------------------
+
+.How It Works
+
+You can ignore the `import` statement for now, we'll explore that in detail in the <<module,modules
+chapter>>.
+
+Whenever we write a program that uses Unicode literals like we have used above, we have to make
+sure that Python itself is told that our program uses UTF-8, and we have to put `# encoding=utf-8`
+comment at the top of our program.
+
+We use `io.open` and provide the "encoding" and "decoding" argument to tell Python that we are
+using unicode, and in fact, we have to pass in a string in the form of `u""` to make it clear that
+we are using Unicode strings.
+
+You should learn more about this topic by reading:
+
+- http://www.joelonsoftware.com/articles/Unicode.html["The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets"]
+- http://docs.python.org/2/howto/unicode.html[Python Unicode Howto]
+- http://nedbatchelder.com/text/unipain.html[Pragmatic Unicode talk by Nat Batchelder]
+
+=== Summary
+
+We have discussed various types of input/output, about file handling, about the pickle module and
+about Unicode.
+
+Next, we will explore the concept of exceptions.

BIN
light_table_screenshot.png


+ 315 - 0
modules.asciidoc

@@ -0,0 +1,315 @@
+[[modules]]
+== Modules
+
+You have seen how you can reuse code in your program by defining functions once. What if you wanted
+to reuse a number of functions in other programs that you write? As you might have guessed, the
+answer is modules.
+
+There are various methods of writing modules, but the simplest way is to create a file with a `.py`
+extension that contains functions and variables.
+
+Another method is to write the modules in the native language in which the Python interpreter
+itself was written. For example, you can write modules in the http://docs.python.org/2/extending/[C
+programming language] and when compiled, they can be used from your Python code when using the
+standard Python interpreter.
+
+A module can be *imported* by another program to make use of its functionality. This is how we can
+use the Python standard library as well. First, we will see how to use the standard library
+modules.
+
+Example (save as `module_using_sys.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/module_using_sys.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/module_using_sys.txt[]
+--------------------------------------------------
+
+.How It Works
+
+First, we *import* the `sys` module using the `import` statement. Basically, this translates to us
+telling Python that we want to use this module. The `sys` module contains functionality related to
+the Python interpreter and its environment i.e. the **sys**tem.
+
+When Python executes the `import sys` statement, it looks for the `sys` module. In this case, it is
+one of the built-in modules, and hence Python knows where to find it.
+
+If it was not a compiled module i.e. a module written in Python, then the Python interpreter will
+search for it in the directories listed in its `sys.path` variable. If the module is found, then
+the statements in the body of that module are run and the module is made *available* for you
+to use. Note that the initialization is done only the *first* time that we import a module.
+
+The `argv` variable in the `sys` module is accessed using the dotted notation i.e. `sys.argv`. It
+clearly indicates that this name is part of the `sys` module. Another advantage of this approach is
+that the name does not clash with any `argv` variable used in your program.
+
+The `sys.argv` variable is a *list* of strings (lists are explained in detail in a
+<<data_structures,later chapter>>. Specifically, the `sys.argv` contains the list of *command line
+arguments* i.e. the arguments passed to your program using the command line.
+
+If you are using an IDE to write and run these programs, look for a way to specify command line
+arguments to the program in the menus.
+
+Here, when we execute `python module_using_sys.py we are arguments`, we run the module
+`module_using_sys.py` with the `python` command and the other things that follow are arguments
+passed to the program. Python stores the command line arguments in the `sys.argv` variable for us
+to use.
+
+Remember, the name of the script running is always the first argument in the `sys.argv` list. So,
+in this case we will have `'using_sys.py'` as `sys.argv[0]`, `'we'` as `sys.argv[1]`, `'are'` as
+`sys.argv[2]` and `'arguments'` as `sys.argv[3]`. Notice that Python starts counting from 0 and
+not 1.
+
+The `sys.path` contains the list of directory names where modules are imported from. Observe that
+the first string in `sys.path` is empty - this empty string indicates that the current directory is
+also part of the `sys.path` which is same as the `PYTHONPATH` environment variable. This means that
+you can directly import modules located in the current directory. Otherwise, you will have to place
+your module in one of the directories listed in `sys.path`.
+
+Note that the current directory is the directory from which the program is launched. Run `import
+os; print os.getcwd()` to find out the current directory of your program.
+
+[[pyc]]
+=== Byte-compiled .pyc files
+
+Importing a module is a relatively costly affair, so Python does some tricks to make it faster. One
+way is to create *byte-compiled* files with the extension `.pyc` which is an intermediate form that
+Python transforms the program into (remember the <<interpreted,introduction section>> on how Python
+works?). This `.pyc` file is useful when you import the module the next time from a different
+program - it will be much faster since a portion of the processing required in importing a module
+is already done. Also, these byte-compiled files are platform-independent.
+
+NOTE: These `.pyc` files are usually created in the same directory as the corresponding `.py`
+files. If Python does not have permission to write to files in that directory, then the `.pyc`
+files will _not_ be created.
+
+[[the_from_import_statement]]
+=== The from ... import statement
+
+If you want to directly import the `argv` variable into your program (to avoid typing the `sys.`
+everytime for it), then you can use the `from sys import argv` statement.
+
+In general, you *should avoid* using this statement and use the `import` statement instead since
+your program will avoid name clashes and will be more readable.
+
+Example:
+
+[source,python]
+--------------------------------------------------
+from math import sqrt
+print "Square root of 16 is", sqrt(16)
+--------------------------------------------------
+
+[[module_name]]
+=== A module's `__name__`
+
+Every module has a name and statements in a module can find out the name of their module. This is
+handy for the particular purpose of figuring out whether the module is being run standalone or
+being imported. As mentioned previously, when a module is imported for the first time, the code it
+contains gets executed. We can use this to make the module behave in different ways depending on
+whether it is being used by itself or being imported from another module. This can be achieved
+using the `__name__` attribute of the module.
+
+Example (save as `module_using_name.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/module_using_name.py[]
+--------------------------------------------------
+
+Output:
+--------------------------------------------------
+include::programs/module_using_name.txt[]
+--------------------------------------------------
+
+.How It Works
+
+Every Python module has its `__name__` defined. If this is `'__main__'`, that implies that the
+module is being run standalone by the user and we can take appropriate actions.
+
+=== Making Your Own Modules
+
+Creating your own modules is easy, you've been doing it all along!  This is because every Python
+program is also a module. You just have to make sure it has a `.py` extension. The following
+example should make it clear.
+
+Example (save as `mymodule.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/mymodule.py[]
+--------------------------------------------------
+
+The above was a sample *module*. As you can see, there is nothing particularly special about it
+compared to our usual Python program. We will next see how to use this module in our other Python
+programs.
+
+Remember that the module should be placed either in the same directory as the program from which we
+import it, or in one of the directories listed in `sys.path`.
+
+Another module (save as `mymodule_demo.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/mymodule_demo.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/mymodule_demo.txt[]
+--------------------------------------------------
+
+.How It Works
+
+Notice that we use the same dotted notation to access members of the module. Python makes good
+reuse of the same notation to give the distinctive 'Pythonic' feel to it so that we don't have to
+keep learning new ways to do things.
+
+Here is a version utilising the `from..import` syntax (save as `mymodule_demo2.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/mymodule_demo2.py[]
+--------------------------------------------------
+
+The output of `mymodule_demo2.py` is same as the output of `mymodule_demo.py`.
+
+Notice that if there was already a `__version__` name declared in the module that imports mymodule,
+there would be a clash. This is also likely because it is common practice for each module to
+declare it's version number using this name. Hence, it is always recommended to prefer the `import`
+statement even though it might make your program a little longer.
+
+You could also use:
+
+[source,python]
+--------------------------------------------------
+from mymodule import *
+--------------------------------------------------
+
+This will import all public names such as `sayhi` but would not import `__version__` because it
+starts with double underscores.
+
+WARNING: Remember that you should avoid using import-star, i.e. `from mymodule import *`.
+
+.Zen of Python
+**************************************************
+One of Python's guiding principles is that "Explicit is better than Implicit". Run `import this` in
+Python to learn more and see http://stackoverflow.com/questions/228181/zen-of-python[this
+StackOverflow discussion] which lists examples for each of the principles.
+**************************************************
+
+[[the_dir_function]]
+=== The +dir+ function
+
+You can use the built-in `dir` function to list the identifiers that an object defines. For
+example, for a module, the identifiers include the functions, classes and variables defined in that
+module.
+
+When you supply a module name to the`dir()` function, it returns the list of the names defined in
+that module. When no argument is applied to it, it returns the list of names defined in the current
+module.
+
+Example:
+
+--------------------------------------------------
+$ python
+>>> import sys
+
+# get names of attributes in sys module
+>>> dir(sys)
+['__displayhook__', '__doc__',
+'argv', 'builtin_module_names',
+'version', 'version_info']
+# only few entries shown here
+
+# get names of attributes for current module
+>>> dir()
+['__builtins__', '__doc__',
+'__name__', '__package__']
+
+# create a new variable 'a'
+>>> a = 5
+
+>>> dir()
+['__builtins__', '__doc__', '__name__', '__package__', 'a']
+
+# delete/remove a name
+>>> del a
+
+>>> dir()
+['__builtins__', '__doc__', '__name__', '__package__']
+--------------------------------------------------
+
+.How It Works
+
+First, we see the usage of `dir` on the imported `sys` module. We can see the huge list of
+attributes that it contains.
+
+Next, we use the `dir` function without passing parameters to it. By default, it returns the list
+of attributes for the current module. Notice that the list of imported modules is also part of this
+list.
+
+In order to observe the `dir` in action, we define a new variable `a` and assign it a value and
+then check `dir` and we observe that there is an additional value in the list of the same name. We
+remove the variable/attribute of the current module using the `del` statement and the change is
+reflected again in the output of the `dir` function.
+
+A note on `del` - this statement is used to *delete* a variable/name and after the statement has
+run, in this case `del a`, you can no longer access the variable `a` - it is as if it never existed
+before at all.
+
+Note that the `dir()` function works on *any* object. For example, run `dir('print')` to learn
+about the attributes of the print function, or `dir(str)` for the attributes of the str class.
+
+There is also a http://docs.python.org/2/library/functions.html#vars[`vars()`] function which can
+potentially give you the attributes and their values, but it will not work for all cases.
+
+[[packages]]
+=== Packages
+
+By now, you must have started observing the hierarchy of organizing your programs. Variables
+usually go inside functions. Functions and global variables usually go inside modules. What if you
+wanted to organize modules? That's where packages come into the picture.
+
+Packages are just folders of modules with a special `__init__.py` file that indicates to Python
+that this folder is special because it contains Python modules.
+
+Let's say you want to create a package called 'world' with subpackages 'asia', 'africa', etc. and
+these subpackages in turn contain modules like 'india', 'madagascar', etc.
+
+This is how you would structure the folders:
+
+--------------------------------------------------
+- <some folder present in the sys.path>/
+    - world/
+        - __init__.py
+        - asia/
+            - __init__.py
+            - india/
+                - __init__.py
+                - foo.py
+        - africa/
+            - __init__.py
+            - madagascar/
+                - __init__.py
+                - bar.py
+--------------------------------------------------
+
+Packages are just a convenience to hierarchically organize modules. You will see many instances of
+this in the <<standard_library,standard library>>.
+
+=== Summary
+
+Just like functions are reusable parts of programs, modules are reusable programs. Packages are
+another hierarchy to organize modules. The standard library that comes with Python is an example of
+such a set of packages and modules.
+
+We have seen how to use these modules and create our own modules.
+
+Next, we will learn about some interesting concepts called data structures.

+ 232 - 0
more.asciidoc

@@ -0,0 +1,232 @@
+[[more]]
+== More
+
+So far we have covered a majority of the various aspects of Python that you will use. In this
+chapter, we will cover some more aspects that will make our knowledge of Python more well-rounded.
+
+=== Passing tuples around
+
+Ever wished you could return two different values from a function? You can. All you have to do is
+use a tuple.
+
+--------------------------------------------------
+>>> def get_error_details():
+...     return (2, 'details')
+...
+>>> errnum, errstr = get_error_details()
+>>> errnum
+2
+>>> errstr
+'details'
+--------------------------------------------------
+
+Notice that the usage of `a, b = <some expression>` interprets the result of the expression as a
+tuple with two values.
+
+This also means the fastest way to swap two variables in Python is:
+
+--------------------------------------------------
+>>> a = 5; b = 8
+>>> a, b
+(5, 8)
+>>> a, b = b, a
+>>> a, b
+(8, 5)
+--------------------------------------------------
+
+=== Special Methods
+
+There are certain methods such as the `__init__` and `__del__` methods which have special
+significance in classes.
+
+Special methods are used to mimic certain behaviors of built-in types. For example, if you want to
+use the `x[key]` indexing operation for your class (just like you use it for lists and tuples),
+then all you have to do is implement the `__getitem__()` method and your job is done. If you think
+about it, this is what Python does for the `list` class itself!
+
+Some useful special methods are listed in the following table. If you
+want to know about all the special methods,
+http://docs.python.org/2/reference/datamodel.html#special-method-names[see the manual].
+
+`__init__(self, ...)` ::
+This method is called just before the newly created object is returned for usage.
+
+`__del__(self)` ::
+Called just before the object is destroyed (which has unpredictable timing, so avoid using this)
+
+`__str__(self)` ::
+Called when we use the `print` statement or when `str()` is used.
+
+`__lt__(self, other)` ::
+Called when the _less than_ operator (&lt;) is used. Similarly, there are special methods for all
+the operators (+, >, etc.)
+
+`__getitem__(self, key)` ::
+Called when `x[key]` indexing operation is used.
+
+`__len__(self)` ::
+Called when the built-in `len()` function is used for the sequence object.
+
+=== Single Statement Blocks
+
+We have seen that each block of statements is set apart from the rest by its own indentation
+level. Well, there is one caveat. If your block of statements contains only one single statement,
+then you can specify it on the same line of, say, a conditional statement or looping statement. The
+following example should make this clear:
+
+--------------------------------------------------
+>>> flag = True
+>>> if flag: print 'Yes'
+...
+Yes
+--------------------------------------------------
+
+Notice that the single statement is used in-place and not as a separate block.  Although, you can
+use this for making your program _smaller_, I strongly recommend avoiding this short-cut method,
+except for error checking, mainly because it will be much easier to add an extra statement if you
+are using proper indentation.
+
+=== Lambda Forms
+
+A `lambda` statement is used to create new function objects. Essentially, the `lambda` takes a
+parameter followed by a single expression only which becomes the body of the function and the value
+of this expression is returned by the new function.
+
+Example (save as `more_lambda.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/more_lambda.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/more_lambda.txt[]
+--------------------------------------------------
+
+.How It Works
+
+Notice that the `sort` method of a `list` can take a `key` parameter which determines how the list
+is sorted (usually we know only about ascending or descending order). In our case, we want to do a
+custom sort, and for that we need to write a function but instead of writing a separate `def` block
+for a function that will get used in only this one place, we use a lambda expression to create a
+new function.
+
+[[list_comprehension]]
+=== List Comprehension
+
+List comprehensions are used to derive a new list from an existing list. Suppose you have a list of
+numbers and you want to get a corresponding list with all the numbers multiplied by 2 only when the
+number itself is greater than 2. List comprehensions are ideal for such situations.
+
+Example (save as `more_list_comprehension.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/more_list_comprehension.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/more_list_comprehension.txt[]
+--------------------------------------------------
+
+.How It Works
+
+Here, we derive a new list by specifying the manipulation to be done (`2*i`) when some condition is
+satisfied (`if i > 2`). Note that the original list remains unmodified.
+
+The advantage of using list comprehensions is that it reduces the amount of boilerplate code
+required when we use loops to process each element of a list and store it in a new list.
+
+=== Receiving Tuples and Dictionaries in Functions
+
+There is a special way of receiving parameters to a function as a tuple or a dictionary using the
+`*` or `**` prefix respectively. This is useful when taking variable number of arguments in the
+function.
+
+--------------------------------------------------
+>>> def powersum(power, *args):
+...     '''Return the sum of each argument raised to the specified power.'''
+...     total = 0
+...     for i in args:
+...         total += pow(i, power)
+...     return total
+...
+>>> powersum(2, 3, 4)
+25
+>>> powersum(2, 10)
+100
+--------------------------------------------------
+
+Because we have a `*` prefix on the `args` variable, all extra arguments passed to the function are
+stored in `args` as a tuple.  If a `**` prefix had been used instead, the extra parameters would be
+considered to be key/value pairs of a dictionary.
+
+=== The assert statement
+
+The `assert` statement is used to assert that something is true. For example, if you are very sure
+that you will have at least one element in a list you are using and want to check this, and raise
+an error if it is not true, then `assert` statement is ideal in this situation. When the assert
+statement fails, an `AssertionError` is raised.
+
+--------------------------------------------------
+>>> mylist = ['item']
+>>> assert len(mylist) >= 1
+>>> mylist.pop()
+'item'
+>>> assert len(mylist) >= 1
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+AssertionError
+--------------------------------------------------
+
+The `assert` statement should be used judiciously. Most of the time, it is better to catch
+exceptions, either handle the problem or display an error message to the user and then quit.
+
+[[decorator]]
+=== Decorators
+
+Decorators are a shortcut to applying wrapper functions. This is helpful to "wrap" functionality
+with the same code over and over again. For example, I created a `retry` decorator for myself that
+I can just apply to any function and if any exception is thrown during a run, it is retried again,
+till a maximum of 5 times and with a delay between each retry. This is especially useful for
+situations where you are trying to make a network call to a remote computer:
+
+[source,python]
+--------------------------------------------------
+include::programs/more_decorator.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/more_decorator.txt[]
+--------------------------------------------------
+
+.How It Works
+
+See:
+
+-  http://www.ibm.com/developerworks/linux/library/l-cpdecor.html
+- http://toumorokoshi.github.io/dry-principles-through-python-decorators.html
+
+[[2_vs_3]]
+=== Differences between Python 2 and Python 3
+
+See:
+
+- http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/[Porting to Python 3 Redux by Armin]
+- http://pydanny.com/experiences-with-django-python3.html[Python 3 experience by PyDanny]
+- https://docs.djangoproject.com/en/dev/topics/python3/[Official Django Guide to Porting to Python 3]
+
+=== Summary
+
+We have covered some more features of Python in this chapter and yet we haven't covered all the
+features of Python. However, at this stage, we have covered most of what you are ever going to use
+in practice. This is sufficient for you to get started with whatever programs you are going to
+create.
+
+Next, we will discuss how to explore Python further.

+ 329 - 0
oop.asciidoc

@@ -0,0 +1,329 @@
+[[oop]]
+== Object Oriented Programming
+
+In all the programs we wrote till now, we have designed our program around functions i.e. blocks of
+statements which manipulate data. This is called the _procedure-oriented_ way of programming. There
+is another way of organizing your program which is to combine data and functionality and wrap it
+inside something called an object. This is called the _object oriented_ programming paradigm. Most
+of the time you can use procedural programming, but when writing large programs or have a problem
+that is better suited to this method, you can use object oriented programming techniques.
+
+Classes and objects are the two main aspects of object oriented programming. A *class* creates a
+new _type_ where *objects* are *instances* of the class. An analogy is that you can have variables
+of type `int` which translates to saying that variables that store integers are variables which are
+instances (objects) of the `int` class.
+
+.Note for Static Language Programmers
+[NOTE]
+--
+Note that even integers are treated as objects (of the `int` class). This is unlike C++ and Java
+(before version 1.5) where integers are primitive native types.
+
+See `help(int)` for more details on the class.
+
+C# and Java 1.5 programmers will find this similar to the _boxing and unboxing_ concept.
+--
+
+Objects can store data using ordinary variables that _belong_ to the object. Variables that belong
+to an object or class are referred to as *fields*. Objects can also have functionality by using
+functions that _belong_ to a class. Such functions are called *methods* of the class. This
+terminology is important because it helps us to differentiate between functions and variables which
+are independent and those which belong to a class or object. Collectively, the fields and methods
+can be referred to as the *attributes* of that class.
+
+Fields are of two types - they can belong to each instance/object of the class or they can belong
+to the class itself. They are called *instance variables* and *class variables* respectively.
+
+A class is created using the `class` keyword. The fields and methods of the class are listed in an
+indented block.
+
+[[self]]
+=== The +self+
+
+Class methods have only one specific difference from ordinary
+functions - they must have an extra first name that has to be added to
+the beginning of the parameter list, but you *do not* give a value
+for this parameter when you call the method, Python will provide
+it. This particular variable refers to the object _itself_, and by convention, it is given the name
+`self`.
+
+Although, you can give any name for this parameter, it is _strongly recommended_ that you use the
+name `self` - any other name is definitely frowned upon. There are many advantages to using a
+standard name - any reader of your program will immediately recognize it and even specialized IDEs
+(Integrated Development Environments) can help you if you use `self`.
+
+.Note for C++/Java/C# Programmers
+[NOTE]
+The `self` in Python is equivalent to the `this` pointer in C++ and the `this` reference in Java
+and C#.
+
+You must be wondering how Python gives the value for `self` and why you don't need to give a value
+for it. An example will make this clear. Say you have a class called `MyClass` and an instance of
+this class called `myobject`. When you call a method of this object as `myobject.method(arg1,
+arg2)`, this is automatically converted by Python into `MyClass.method(myobject, arg1, arg2)` -
+this is all the special `self` is about.
+
+This also means that if you have a method which takes no arguments, then you still have to have one
+argument - the `self`.
+
+[[class]]
+=== Classes
+
+The simplest class possible is shown in the following example (save as `oop_simplestclass.py`).
+
+[source,python]
+--------------------------------------------------
+include::programs/oop_simplestclass.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/oop_simplestclass.txt[]
+--------------------------------------------------
+
+.How It Works
+
+We create a new class using the `class` statement and the name of the class. This is followed by an
+indented block of statements which form the body of the class. In this case, we have an empty block
+which is indicated using the `pass` statement.
+
+Next, we create an object/instance of this class using the name of the class followed by a pair of
+parentheses. (We will learn <<init,more about instantiation>> in the next section). For our
+verification, we confirm the type of the variable by simply printing it. It tells us that we have
+an instance of the `Person` class in the `__main__` module.
+
+Notice that the address of the computer memory where your object is stored is also printed. The
+address will have a different value on your computer since Python can store the object wherever it
+finds space.
+
+[[methods]]
+=== Methods
+
+We have already discussed that classes/objects can have methods just like functions except that we
+have an extra `self` variable. We will now see an example (save as `oop_method.py`).
+
+[source,python]
+--------------------------------------------------
+include::programs/oop_method.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/oop_method.txt[]
+--------------------------------------------------
+
+.How It Works
+
+Here we see the `self` in action. Notice that the `say_hi` method takes no parameters but still has
+the `self` in the function definition.
+
+[[init]]
+=== The `__init__` method
+
+There are many method names which have special significance in Python classes. We will see the
+significance of the `__init__` method now.
+
+The `__init__` method is run as soon as an object of a class is instantiated. The method is useful
+to do any *initialization* you want to do with your object. Notice the double underscores both at
+the beginning and at the end of the name.
+
+Example (save as `oop_init.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/oop_init.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/oop_init.txt[]
+--------------------------------------------------
+
+.How It Works
+
+Here, we define the `__init__` method as taking a parameter `name` (along with the usual `self`).
+Here, we just create a new field also called `name`. Notice these are two different variables even
+though they are both called 'name'. There is no problem because the dotted notation `self.name`
+means that there is something called "name" that is part of the object called "self" and the other
+`name` is a local variable. Since we explicitly indicate which name we are referring to, there is
+no confusion.
+
+Most importantly, notice that we do not explicitly call the `__init__` method but pass the
+arguments in the parentheses following the class name when creating a new instance of the
+class. This is the special significance of this method.
+
+Now, we are able to use the `self.name` field in our methods which is demonstrated in the `sayHi`
+method.
+
+[[class_obj_vars]]
+=== Class And Object Variables
+
+We have already discussed the functionality part of classes and objects (i.e. methods), now let us
+learn about the data part. The data part, i.e. fields, are nothing but ordinary variables that are
+_bound_ to the *namespaces* of the classes and objects. This means that these names are valid
+within the context of these classes and objects only. That's why they are called _name spaces_.
+
+There are two types of _fields_ - class variables and object variables which are classified
+depending on whether the class or the object _owns_ the variables respectively.
+
+*Class variables* are shared - they can be accessed by all instances of that class. There is only
+one copy of the class variable and when any one object makes a change to a class variable, that
+change will be seen by all the other instances.
+
+*Object variables* are owned by each individual object/instance of the class. In this case, each
+object has its own copy of the field i.e. they are not shared and are not related in any way to the
+field by the same name in a different instance. An example will make this easy to understand (save
+as `oop_objvar.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/oop_objvar.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/oop_objvar.txt[]
+--------------------------------------------------
+
+.How It Works
+
+This is a long example but helps demonstrate the nature of class and object variables. Here,
+`population` belongs to the`Robot` class and hence is a class variable. The `name` variable belongs
+to the object (it is assigned using `self`) and hence is an object variable.
+
+Thus, we refer to the `population` class variable as `Robot.population` and not as
+`self.population`. We refer to the object variable `name` using `self.name` notation in the methods
+of that object. Remember this simple difference between class and object variables. Also note that
+an object variable with the same name as a class variable will hide the class variable!
+
+Instead of `Robot.population`, we could have also used `self.__class__.population` because every
+object refers to it's class via the `self.__class__` attribute.
+
+The `how_many` is actually a method that belongs to the class and not to the object. This means we
+can define it as either a `classmethod` or a `staticmethod` depending on whether we need to know
+which class we are part of. Since we refer to a class variable, let's use `classmethod`.
+
+We have marked the `how_many` method as a class method using a <<decorator,decorator>>.
+
+Decorators can be imagined to be a shortcut to calling a wrapper function, so applying the
+`@classmethod` decorator is same as calling:
+
+[source,python]
+--------------------------------------------------
+how_many = classmethod(how_many)
+--------------------------------------------------
+
+Observe that the `__init__` method is used to initialize the `Robot` instance with a name. In this
+method, we increase the `population` count by 1 since we have one more robot being added. Also
+observe that the values of `self.name` is specific to each object which indicates the nature of
+object variables.
+
+Remember, that you must refer to the variables and methods of the same object using the `self`
+*only*. This is called an *attribute reference*.
+
+In this program, we also see the use of *docstrings* for classes as well as methods. We can access
+the class docstring at runtime using `Robot.__doc__` and the method docstring as
+`Robot.say_hi.__doc__`
+
+In the `die` method, we simply decrease the `Robot.population` count by 1.
+
+All class members are public. One exception: If you use data members with names using the _double
+underscore prefix_ such as `__privatevar`, Python uses name-mangling to effectively make it a
+private variable.
+
+Thus, the convention followed is that any variable that is to be used only within the class or
+object should begin with an underscore and all other names are public and can be used by other
+classes/objects. Remember that this is only a convention and is not enforced by Python (except for
+the double underscore prefix).
+
+.Note for C++/Java/C# Programmers
+[NOTE]
+All class members (including the data members) are _public_ and all the methods are _virtual_ in
+Python.
+
+=== Inheritance
+
+One of the major benefits of object oriented programming is *reuse* of code and one of the ways
+this is achieved is through the *inheritance* mechanism. Inheritance can be best imagined as
+implementing a *type and subtype* relationship between classes.
+
+Suppose you want to write a program which has to keep track of the teachers and students in a
+college. They have some common characteristics such as name, age and address. They also have
+specific characteristics such as salary, courses and leaves for teachers and, marks and fees for
+students.
+
+You can create two independent classes for each type and process them but adding a new common
+characteristic would mean adding to both of these independent classes. This quickly becomes
+unwieldy.
+
+A better way would be to create a common class called `SchoolMember` and then have the teacher and
+student classes _inherit_ from this class i.e. they will become sub-types of this type (class) and
+then we can add specific characteristics to these sub-types.
+
+There are many advantages to this approach. If we add/change any functionality in `SchoolMember`,
+this is automatically reflected in the subtypes as well. For example, you can add a new ID card
+field for both teachers and students by simply adding it to the SchoolMember class. However,
+changes in the subtypes do not affect other subtypes. Another advantage is that if you can refer to
+a teacher or student object as a `SchoolMember` object which could be useful in some situations
+such as counting of the number of school members. This is called *polymorphism* where a sub-type
+can be substituted in any situation where a parent type is expected i.e. the object can be treated
+as an instance of the parent class.
+
+Also observe that we reuse the code of the parent class and we do not need to repeat it in the
+different classes as we would have had to in case we had used independent classes.
+
+The `SchoolMember` class in this situation is known as the *base class* or the *superclass*. The
+`Teacher` and `Student` classes are called the *derived classes* or *subclasses*.
+
+We will now see this example as a program (save as `oop_subclass.py`):
+
+[source,python]
+--------------------------------------------------
+include::programs/oop_subclass.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/oop_subclass.txt[]
+--------------------------------------------------
+
+.How It Works
+
+To use inheritance, we specify the base class names in a tuple following the class name in the
+class definition. Next, we observe that the `__init__` method of the base class is explicitly
+called using the `self` variable so that we can initialize the base class part of the object. This
+is very important to remember - Python does not automatically call the constructor of the base
+class, you have to explicitly call it yourself.
+
+We also observe that we can call methods of the base class by prefixing the class name to the
+method call and then pass in the `self` variable along with any arguments.
+
+Notice that we can treat instances of `Teacher` or `Student` as just instances of the
+`SchoolMember` when we use the `tell` method of the `SchoolMember` class.
+
+Also, observe that the `tell` method of the subtype is called and not the `tell` method of the
+`SchoolMember` class. One way to understand this is that Python _always_ starts looking for methods
+in the actual type, which in this case it does. If it could not find the method, it starts looking
+at the methods belonging to its base classes one by one in the order they are specified in the
+tuple in the class definition.
+
+A note on terminology - if more than one class is listed in the inheritance tuple, then it is
+called *multiple inheritance*.
+
+The trailing comma is used at the end of the `print` statement in the superclass's `tell()` method
+to print a line and allow the next print to continue on the same line. This is a trick to make
+`print` not print a `\n` (newline) symbol at the end of the printing.
+
+=== Summary
+
+We have now explored the various aspects of classes and objects as well as the various
+terminologies associated with it. We have also seen the benefits and pitfalls of object-oriented
+programming. Python is highly object-oriented and understanding these concepts carefully will help
+you a lot in the long run.
+
+Next, we will learn how to deal with input/output and how to access files in Python.

+ 278 - 0
op_exp.asciidoc

@@ -0,0 +1,278 @@
+[[op_exp]]
+== Operators and Expressions
+
+Most statements (logical lines) that you write will contain _expressions_. A simple example of an
+expression is `2 + 3`. An expression can be broken down into operators and operands.
+
+_Operators_ are functionality that do something and can be represented by symbols such as `+` or by
+special keywords. Operators require some data to operate on and such data is called _operands_. In
+this case, `2` and `3` are the operands.
+
+=== Operators
+
+We will briefly take a look at the operators and their usage.
+
+Note that you can evaluate the expressions given in the examples using the interpreter
+interactively. For example, to test the expression `2 + 3`, use the interactive Python interpreter
+prompt:
+
+[source,python]
+--------------------------------------------------
+>>> 2 + 3
+5
+>>> 3 * 5
+15
+>>>
+--------------------------------------------------
+
+Here is a quick overview of the available operators:
+
+`+` (plus) ::
+Adds two objects
++
+`3 + 5` gives `8`. `'a' + 'b'` gives `'ab'`.
+
+`-` (minus) ::
+Gives the subtraction of one number from the other; if the first operand is absent it is assumed to
+be zero.
++
+`-5.2` gives a negative number and `50 - 24` gives `26`.
+
+`*` (multiply) ::
+Gives the multiplication of the two numbers or returns the string repeated that many times.
++
+`2 * 3` gives `6`. `'la' * 3` gives `'lalala'`.
+
+`**` (power) ::
+Returns x to the power of y
++
+`3 ** 4` gives `81` (i.e. `3 * 3 * 3 * 3`)
+
+`/` (divide) ::
+Divide x by y
++
+`13 / 3` gives `4.333333333333333`.
+
+`//` (floor division) ::
+Returns the floor of the quotient
++
+`13 // 3` gives `4`.
+
+`%` (modulo) ::
+Returns the remainder of the division
++
+`13 % 3` gives `1`. `-25.5 % 2.25` gives `1.5`.
+
+`<<` (left shift) ::
+Shifts the bits of the number to the left by the number of bits specified. (Each number is
+represented in memory by bits or binary digits i.e. 0 and 1)
++
+`2 << 2` gives `8`. `2` is represented by `10` in bits.
++
+Left shifting by 2 bits gives `1000` which represents the decimal `8`.
+
+`>>` (right shift) ::
+Shifts the bits of the number to the right by the number of bits specified.
++
+`11 >> 1` gives `5`.
++
+`11` is represented in bits by `1011` which when right shifted by 1 bit gives `101`which is the
+decimal `5`.
+
+`&` (bit-wise AND) ::
+Bit-wise AND of the numbers
++
+`5 & 3` gives `1`.
+
+`|` (bit-wise OR) ::
+Bitwise OR of the numbers
++
+`5 | 3` gives `7`
+
+`^` (bit-wise XOR) ::
+Bitwise XOR of the numbers
++
+`5 ^ 3` gives `6`
+
+`~` (bit-wise invert) ::
+The bit-wise inversion of x is -(x+1)
++
+`~5` gives `-6`. More details at http://stackoverflow.com/a/11810203
+
+`<` (less than) ::
+Returns whether x is less than y. All comparison operators return `True` or `False`. Note the
+capitalization of these names.
++
+`5 &lt; 3` gives `False` and `3 &lt; 5` gives `True`.
++
+Comparisons can be chained arbitrarily: `3 < 5 < 7` gives `True`.
+
+`>` (greater than) ::
+Returns whether x is greater than y
++
+`5 > 3` returns `True`. If both operands are numbers, they are first converted to a common
+type. Otherwise, it always returns `False`.
+
+`<=` (less than or equal to) ::
+Returns whether x is less than or equal to y
++
+`x = 3; y = 6; x <= y` returns `True`.
+
+`>=` (greater than or equal to) ::
+Returns whether x is greater than or equal to y
++
+`x = 4; y = 3; x >= 3` returns `True`.
+
+`==` (equal to) ::
+Compares if the objects are equal
++
+`x = 2; y = 2; x == y` returns `True`.
++
+`x = 'str'; y = 'stR'; x == y` returns `False`.
++
+`x = 'str'; y = 'str'; x == y` returns `True`.
+
+`!=` (not equal to) ::
+Compares if the objects are not equal
++
+`x = 2; y = 3; x != y` returns `True`.
+
+`not` (boolean NOT) ::
+If x is `True`, it returns `False`. If x is `False`, it returns `True`.
++
+`x = True; not x` returns `False`.
+
+`and` (boolean AND) ::
+`x and y` returns `False` if x is `False`, else it returns evaluation of y
++
+`x = False; y = True; x and y` returns `False` since x is False. In this case, Python will not
+evaluate y since it knows that the left hand side of the 'and' expression is `False` which implies
+that the whole expression will be `False` irrespective of the other values. This is called
+short-circuit evaluation.
+
+`or` (boolean OR) ::
+If x is `True`, it returns True, else it returns evaluation of y
++
+`x = True; y = False; x or y` returns `True`. Short-circuit evaluation applies here as well.
+
+=== Shortcut for math operation and assignment
+
+It is common to run a math operation on a variable and then assign the result of the operation back
+to the variable, hence there is a shortcut for such expressions:
+
+[source,python]
+--------------------------------------------------
+a = 2
+a = a * 3
+--------------------------------------------------
+
+can be written as:
+
+[source,python]
+--------------------------------------------------
+a = 2
+a *= 3
+--------------------------------------------------
+
+Notice that `var = var operation expression` becomes `var operation= expression`.
+
+=== Evaluation Order
+
+If you had an expression such as `2 + 3 * 4`, is the addition done first or the multiplication? Our
+high school maths tells us that the multiplication should be done first. This means that the
+multiplication operator has higher precedence than the addition operator.
+
+The following table gives the precedence table for Python, from the lowest precedence (least
+binding) to the highest precedence (most binding). This means that in a given expression, Python
+will first evaluate the operators and expressions lower in the table before the ones listed higher
+in the table.
+
+The following table, taken from the
+http://docs.python.org/3/reference/expressions.html#operator-precedence[Python reference manual],
+is provided for the sake of completeness. It is far better to use parentheses to group operators
+and operands appropriately in order to explicitly specify the precedence. This makes the program
+more readable. See <<changing_order_of_evaluation,Changing the Order of Evaluation>> below for
+details.
+
+`lambda` :: Lambda Expression
+`if - else` :: Conditional expression
+`or` :: Boolean OR
+`and` :: Boolean AND
+`not x` :: Boolean NOT
+`in, not in, is, is not, <, <=, >, >=, !=, ==` :: Comparisons, including membership tests and identity tests
+`|` :: Bitwise OR
+`^` :: Bitwise XOR
+`&` :: Bitwise AND
+`<<, >>` :: Shifts
+`+, -` :: Addition and subtraction
+`*, /, //, %` :: Multiplication, Division, Floor Division and Remainder
+`+x, -x, ~x` :: Positive, Negative, bitwise NOT
+`**` :: Exponentiation
+`x[index], x[index:index], x(arguments...), x.attribute` :: Subscription, slicing, call, attribute reference
+`(expressions...), [expressions...], {key: value...}, {expressions...}` :: Binding or tuple display, list display, dictionary display, set display
+
+The operators which we have not already come across will be explained in later chapters.
+
+Operators with the _same precedence_ are listed in the same row in the above table. For example,
+`+` and `-` have the same precedence.
+
+[[changing_order_of_evaluation]]
+=== Changing the Order Of Evaluation
+
+To make the expressions more readable, we can use parentheses. For example, `2 + (3 * 4)` is
+definitely easier to understand than `2 + 3 * 4` which requires knowledge of the operator
+precedences. As with everything else, the parentheses should be used reasonably (do not overdo it)
+and should not be redundant, as in `(2 + (3 * 4))`.
+
+There is an additional advantage to using parentheses - it helps us to change the order of
+evaluation. For example, if you want addition to be evaluated before multiplication in an
+expression, then you can write something like `(2 + 3) * 4`.
+
+=== Associativity
+
+Operators are usually associated from left to right. This means that operators with the same
+precedence are evaluated in a left to right manner. For example, `2 + 3 + 4` is evaluated as `(2 +
+3) + 4`. Some operators like assignment operators have right to left associativity i.e. `a = b = c`
+is treated as `a = (b = c)`.
+
+=== Expressions
+
+Example (save as +expression.py+):
+
+[source,python]
+--------------------------------------------------
+length = 5
+breadth = 2
+
+area = length * breadth
+print 'Area is', area
+print 'Perimeter is', 2 * (length + breadth)
+
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+$ python expression.py
+Area is 10
+Perimeter is 14
+--------------------------------------------------
+
+.How It Works
+
+The length and breadth of the rectangle are stored in variables by the same name. We use these to
+calculate the area and perimeter of the rectangle with the help of expressions. We store the result
+of the expression `length * breadth` in the variable +area+ and then print it using the +print+
+function. In the second case, we directly use the value of the expression `2 * (length + breadth)`
+in the print statement.
+
+Also, notice how Python _pretty-prints_ the output. Even though we have not specified a space
+between `'Area is'` and the variable `area`, Python puts it for us so that we get a clean nice
+output and the program is much more readable this way (since we don't need to worry about spacing
+in the strings we use for output). This is an example of how Python makes life easy for the
+programmer.
+
+=== Summary
+
+We have seen how to use operators, operands and expressions - these are the basic building blocks
+of any program. Next, we will see how to make use of these in our programs using statements.

+ 88 - 0
preface.asciidoc

@@ -0,0 +1,88 @@
+[[preface]]
+[preface]
+== Preface
+
+Python is probably one of the few programming languages which is both simple and powerful. This is
+good for beginners as well as for experts, and more importantly, is fun to program with. This book
+aims to help you learn this wonderful language and show how to get things done quickly and
+painlessly - in effect 'The Anti-venom to your programming problems'.
+
+=== Who This Book Is For
+
+This book serves as a guide or tutorial to the Python programming language. It is mainly targeted
+at newbies. It is useful for experienced programmers as well.
+
+The aim is that if all you know about computers is how to save text files, then you can learn
+Python from this book. If you have previous programming experience, then you can also learn Python
+from this book.
+
+If you do have previous programming experience, you will be interested in the differences between
+Python and your favorite programming language - I have highlighted many such differences. A little
+warning though, Python is soon going to become your favorite programming language!
+
+[[history_lesson]]
+=== History Lesson
+
+I first started with Python when I needed to write an installer for software I had written called
+'Diamond' so that I could make the installation easy. I had to choose between Python and Perl
+bindings for the Qt library. I did some research on the web and I came across
+http://www.python.org/about/success/esr/[an article by Eric S. Raymond], a famous and respected
+hacker, where he talked about how Python had become his favorite programming language. I also found
+out that the PyQt bindings were more mature compared to Perl-Qt. So, I decided that Python was the
+language for me.
+
+Then, I started searching for a good book on Python. I couldn't find any!  I did find some O'Reilly
+books but they were either too expensive or were more like a reference manual than a guide. So, I
+settled for the documentation that came with Python. However, it was too brief and small. It did
+give a good idea about Python but was not complete. I managed with it since I had previous
+programming experience, but it was unsuitable for newbies.
+
+About six months after my first brush with Python, I installed the (then) latest Red Hat 9.0 Linux
+and I was playing around with KWord. I got excited about it and suddenly got the idea of writing
+some stuff on Python. I started writing a few pages but it quickly became 30 pages long. Then, I
+became serious about making it more useful in a book form. After a _lot_ of rewrites, it has
+reached a stage where it has become a useful guide to learning the Python language.  I consider
+this book to be my contribution and tribute to the open source community.
+
+This book started out as my personal notes on Python and I still consider it in the same way,
+although I've taken a lot of effort to make it more palatable to others :)
+
+In the true spirit of open source, I have received lots of constructive suggestions, criticisms and
+<<who_reads_bop,feedback>> from enthusiastic readers which has helped me improve this book a lot.
+
+=== Status Of The Book
+
+- Latest update of this book was in Mar-Apr 2014, converted to
+  http://asciidoctor.org/docs/what-is-asciidoc/[Asciidoc] using
+  http://swaroopch.com/2013/10/17/emacs-configuration-tutorial/[Emacs 24] and
+  https://github.com/sensorflo/adoc-mode/wiki[adoc-mode].
+- In Dec 2008, the book was updated for the Python 3.0 release (one of the first books to do
+  so). But now, I have converted the book back for Python 2 language because readers would often
+  get confused between the default Python 2 installed on their systems vs. Python 3 which they had
+  to separately install and all the tooling, esp. editors would assume Python 2 as well. I had a
+  hard time justifying why I had to aggravate readers and make them go through all this when the
+  fact is that they can learn either one and it would be just as useful. So, Python 2 it is.
+
+The book needs the help of its readers such as yourselves to point out any parts of the book which
+are not good, not comprehensible or are simply wrong. Please {contact}[write to the main author] or
+the respective <<translations,translators>> with your comments and suggestions.
+
+=== Official Website
+
+The official website of the book is {homepage} where you can read the whole book online, download
+the latest versions of the book, {buy}[buy a printed hard copy] and also send me feedback.
+
+=== Something To Think About
+
+[quote,C. A. R. Hoare]
+__________________________________________________
+There are two ways of constructing a software design: one way is to make it so simple that there
+are obviously no deficiencies; the other is to make it so complicated that there are no obvious
+deficiencies.
+__________________________________________________
+
+[quote,C. W. Wendte]
+__________________________________________________
+Success in life is a matter not so much of talent and opportunity as of concentration and
+perseverance.
+__________________________________________________

+ 276 - 0
problem_solving.asciidoc

@@ -0,0 +1,276 @@
+[[problem_solving]]
+== Problem Solving
+
+We have explored various parts of the Python language and now we will take a look at how all these
+parts fit together, by designing and writing a program which _does_ something useful. The idea is
+to learn how to write a Python script on your own.
+
+=== The Problem
+
+The problem we want to solve is:
+
+__________________________________________________
+I want a program which creates a backup of all my important files.
+__________________________________________________
+
+Although, this is a simple problem, there is not enough information for us to get started with the
+solution. A little more *analysis* is required. For example, how do we specify _which_ files are to
+be backed up? _How_ are they stored? _Where_ are they stored?
+
+After analyzing the problem properly, we *design* our program. We make a list of things about how
+our program should work. In this case, I have created the following list on how _I_ want it to
+work. If you do the design, you may not come up with the same kind of analysis since every person
+has their own way of doing things, so that is perfectly okay.
+
+- The files and directories to be backed up are specified in a list.
+- The backup must be stored in a main backup directory.
+- The files are backed up into a zip file.
+- The name of the zip archive is the current date and time.
+- We use the standard `zip` command available by default in any standard GNU/Linux or Unix
+  distribution. Note that you can use any archiving command you
+  want as long as it has a command line interface.
+
+.For Windows users
+[NOTE]
+Windows users can http://gnuwin32.sourceforge.net/downlinks/zip.php[install] the `zip` command from
+the http://gnuwin32.sourceforge.net/packages/zip.htm[GnuWin32 project page] and add `C:\Program
+Files\GnuWin32\bin` to your system `PATH` environment variable, similar to <<dos_prompt,what we did
+for recognizing the python command itself>>.
+
+=== The Solution
+
+As the design of our program is now reasonably stable, we can write the code which is an
+*implementation* of our solution.
+
+Save as `backup_ver1.py`:
+
+[source,python]
+--------------------------------------------------
+include::programs/backup_ver1.py[]
+--------------------------------------------------
+
+Output:
+--------------------------------------------------
+include::programs/backup_ver1.txt[]
+--------------------------------------------------
+
+Now, we are in the *testing* phase where we test that our program works properly. If it doesn't
+behave as expected, then we have to *debug* our program i.e. remove the *bugs* (errors) from the
+program.
+
+If the above program does not work for you, copy the line printed after the `Zip command is` line
+in the output, paste it in the shell (on GNU/Linux and Mac OS X) / `cmd` (on Windows), see what the
+error is and try to fix it. Also check the zip command manual on what could be wrong. If this
+command succeeds, then the problem might be in the Python program itself, so check if it exactly
+matches the program written above.
+
+.How It Works
+
+You will notice how we have converted our *design* into *code* in a step-by-step manner.
+
+We make use of the `os` and `time` modules by first importing them. Then, we specify the files and
+directories to be backed up in the `source` list. The target directory is where we store all the
+backup files and this is specified in the `target_dir` variable. The name of the zip archive that
+we are going to create is the current date and time which we generate using the `time.strftime()`
+function. It will also have the `.zip` extension and will be stored in the `target_dir` directory.
+
+Notice the use of the `os.sep` variable - this gives the directory separator according to your
+operating system i.e. it will be `'/'` in GNU/Linux and Unix, it will be `'\\'` in Windows and
+`':'` in Mac OS. Using `os.sep` instead of these characters directly will make our program portable
+and work across all of these systems.
+
+The `time.strftime()` function takes a specification such as the one we have used in the above
+program. The `%Y` specification will be replaced by the year with the century. The `%m`
+specification will be replaced by the month as a decimal number between `01` and `12` and
+so on. The complete list of such specifications can be found in the
+http://docs.python.org/2/library/time.html#time.strftime[Python Reference Manual].
+
+We create the name of the target zip file using the addition operator which _concatenates_ the
+strings i.e. it joins the two strings together and returns a new one. Then, we create a string
+`zip_command` which contains the command that we are going to execute. You can check if this
+command works by running it in the shell (GNU/Linux terminal or DOS prompt).
+
+The `zip` command that we are using has some options and parameters passed. The `-r` option
+specifies that the zip command should work **r**ecursively for directories i.e. it should include
+all the subdirectories and files. The two options are combined and specified in a shortcut as
+`-qr`. The options are followed by the name of the zip archive to create followed by the list of
+files and directories to backup. We convert the `source` list into a string using the `join` method
+of strings which we have already seen how to
+use.
+
+Then, we finally *run* the command using the `os.system` function which runs the command as if it
+was run from the *system* i.e. in the shell - it returns `0` if the command was successfully, else
+it returns an error number.
+
+Depending on the outcome of the command, we print the appropriate message that the backup has
+failed or succeeded.
+
+That's it, we have created a script to take a backup of our important files!
+
+.Note to Windows Users
+[NOTE]
+Instead of double backslash escape sequences, you can also use raw strings. For example, use
+`'C:\\Documents'` or `r'C:\Documents'`. However, do *not* use `'C:\Documents'` since you end up
+using an unknown escape sequence `\D`.
+
+Now that we have a working backup script, we can use it whenever we want to take a backup of the
+files. This is called the *operation* phase or the *deployment* phase of the software.
+
+The above program works properly, but (usually) first programs do not work exactly as you
+expect. For example, there might be problems if you have not designed the program properly or if
+you have made a mistake when typing the code, etc. Appropriately, you will have to go back to the
+design phase or you will have to debug your program.
+
+=== Second Version
+
+The first version of our script works. However, we can make some refinements to it so that it can
+work better on a daily basis. This is called the *maintenance* phase of the software.
+
+One of the refinements I felt was useful is a better file-naming mechanism - using the _time_ as
+the name of the file within a directory with the current _date_ as a directory within the main
+backup directory. The first advantage is that your backups are stored in a hierarchical manner and
+therefore it is much easier to manage. The second advantage is that the filenames are much
+shorter. The third advantage is that separate directories will help you check if you have made a
+backup for each day since the directory would be created only if you have made a backup for
+that day.
+
+Save as `backup_ver2.py`:
+
+[source,python]
+--------------------------------------------------
+include::programs/backup_ver2.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/backup_ver2.txt[]
+--------------------------------------------------
+
+.How It Works
+
+Most of the program remains the same. The changes are that we check if there is a directory with
+the current day as its name inside the main backup directory using the `os.path.exists`
+function. If it doesn't exist, we create it using the `os.mkdir` function.
+
+=== Third Version
+
+The second version works fine when I do many backups, but when there are lots of backups, I am
+finding it hard to differentiate what the backups were for! For example, I might have made some
+major changes to a program or presentation, then I want to associate what those changes are with
+the name of the zip archive. This can be easily achieved by attaching a user-supplied comment to
+the name of the zip archive.
+
+WARNING: The following program does not work, so do not be alarmed, please follow along because
+there's a lesson in here.
+
+Save as `backup_ver3.py`:
+
+[source,python]
+--------------------------------------------------
+include::programs/backup_ver3.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/backup_ver3.txt[]
+--------------------------------------------------
+
+.How This (does not) Work
+
+*This program does not work!* Python says there is a syntax error which means that the script does
+not satisfy the structure that Python expects to see. When we observe the error given by Python, it
+also tells us the place where it detected the error as well. So we start *debugging* our program
+from that line.
+
+On careful observation, we see that the single logical line has been split into two physical lines
+but we have not specified that these two physical lines belong together. Basically, Python has
+found the addition operator (`+`) without any operand in that logical line and hence it doesn't
+know how to continue. Remember that we can specify that the logical line continues in the next
+physical line by the use of a backslash at the end of the physical line. So, we make this
+correction to our program. This correction of the program when we find errors is called *bug
+fixing*.
+
+=== Fourth Version
+
+Save as `backup_ver4.py`:
+
+[source,python]
+--------------------------------------------------
+include::programs/backup_ver4.py[]
+--------------------------------------------------
+
+Output:
+
+--------------------------------------------------
+include::programs/backup_ver4.txt[]
+--------------------------------------------------
+
+.How It Works
+
+This program now works! Let us go through the actual enhancements that we had made in version 3. We
+take in the user's comments using the `input` function and then check if the user actually entered
+something by finding out the length of the input using the `len` function. If the user has just
+pressed `enter` without entering anything (maybe it was just a routine backup or no special changes
+were made), then we proceed as we have done before.
+
+However, if a comment was supplied, then this is attached to the name of the zip archive just
+before the `.zip` extension.  Notice that we are replacing spaces in the comment with underscores -
+this is because managing filenames without spaces is much easier.
+
+=== More Refinements
+
+The fourth version is a satisfactorily working script for most users, but there is always room for
+improvement. For example, you can include a _verbosity_ level for the program where you can specify
+a `-v` option to make your program become more talkative or a `-q` to make it _quiet_.
+
+Another possible enhancement would be to allow extra files and directories to be passed to the
+script at the command line. We can get these names from the `sys.argv` list and we can add them to
+our `source` list using the `extend`method provided by the `list` class.
+
+The most important refinement would be to not use the `os.system` way of creating archives and
+instead using the http://docs.python.org/2/library/zipfile.html[zipfile] or
+http://docs.python.org/2/library/tarfile.html[tarfile] built-in modules to create these
+archives. They are part of the standard library and available already for you to use without
+external dependencies on the zip program to be available on your computer.
+
+However, I have been using the `os.system` way of creating a backup in the above examples purely
+for pedagogical purposes, so that the example is simple enough to be understood by everybody but
+real enough to be useful.
+
+Can you try writing the fifth version that uses the
+http://docs.python.org/2/library/zipfile.html[zipfile] module instead of the `os.system` call?
+
+=== The Software Development Process
+
+We have now gone through the various *phases* in the process of writing a software. These phases
+can be summarised as follows:
+
+1. What (Analysis)
+2. How (Design)
+3. Do It (Implementation)
+4. Test (Testing and Debugging)
+5. Use (Operation or Deployment)
+6. Maintain (Refinement)
+
+A recommended way of writing programs is the procedure we have
+followed in creating the backup script: Do the analysis and
+design. Start implementing with a simple version. Test and debug
+it. Use it to ensure that it works as expected. Now, add any features that you want and continue to
+repeat the Do It-Test-Use cycle as many times as required.
+
+Remember:
+
+[quote,'http://97things.oreilly.com/wiki/index.php/Great_software_is_not_built,_it_is_grown[Bill de hÓra]']
+__________________________________________________
+Software is grown, not built.
+__________________________________________________
+
+=== Summary
+
+We have seen how to create our own Python programs/scripts and the various stages involved in
+writing such programs. You may find it useful to create your own program just like we did in this
+chapter so that you become comfortable with Python as well as problem-solving.
+
+Next, we will discuss object-oriented programming.

+ 1 - 0
programs/abc.txt

@@ -0,0 +1 @@
+Imagine non-English language here

+ 41 - 0
programs/backup_ver1.py

@@ -0,0 +1,41 @@
+import os
+import time
+
+# 1. The files and directories to be backed up are
+# specified in a list.
+# Example on Windows:
+# source = ['"C:\\My Documents"', 'C:\\Code']
+# Example on Mac OS X and Linux:
+source = ['/Users/swa/notes']
+# Notice we had to use double quotes inside the string
+# for names with spaces in it.
+
+# 2. The backup must be stored in a
+# main backup directory
+# Example on Windows:
+# target_dir = 'E:\\Backup'
+# Example on Mac OS X and Linux:
+target_dir = '/Users/swa/backup'
+# Remember to change this to which folder you will be using
+
+# 3. The files are backed up into a zip file.
+# 4. The name of the zip archive is the current date and time
+target = target_dir + os.sep + \
+         time.strftime('%Y%m%d%H%M%S') + '.zip'
+
+# Create target directory if it is not present
+if not os.path.exists(target_dir):
+    os.mkdir(target_dir) # make directory
+
+# 5. We use the zip command to put the files in a zip archive
+zip_command = "zip -r {0} {1}".format(target,
+                                      ' '.join(source))
+
+# Run the backup
+print "Zip command is:"
+print zip_command
+print "Running:"
+if os.system(zip_command) == 0:
+    print 'Successful backup to', target
+else:
+    print 'Backup FAILED'

+ 9 - 0
programs/backup_ver1.txt

@@ -0,0 +1,9 @@
+$ python backup_ver1.py
+Zip command is:
+zip -r /Users/swa/backup/20140328084844.zip /Users/swa/notes
+Running:
+  adding: Users/swa/notes/ (stored 0%)
+  adding: Users/swa/notes/blah1.txt (stored 0%)
+  adding: Users/swa/notes/blah2.txt (stored 0%)
+  adding: Users/swa/notes/blah3.txt (stored 0%)
+Successful backup to /Users/swa/backup/20140328084844.zip

+ 51 - 0
programs/backup_ver2.py

@@ -0,0 +1,51 @@
+import os
+import time
+
+# 1. The files and directories to be backed up are
+# specified in a list.
+# Example on Windows:
+# source = ['"C:\\My Documents"', 'C:\\Code']
+# Example on Mac OS X and Linux:
+source = ['/Users/swa/notes']
+# Notice we had to use double quotes inside the string
+# for names with spaces in it.
+
+# 2. The backup must be stored in a
+# main backup directory
+# Example on Windows:
+# target_dir = 'E:\\Backup'
+# Example on Mac OS X and Linux:
+target_dir = '/Users/swa/backup'
+# Remember to change this to which folder you will be using
+
+# Create target directory if it is not present
+if not os.path.exists(target_dir):
+    os.mkdir(target_dir) # make directory
+
+# 3. The files are backed up into a zip file.
+# 4. The current day is the name of the subdirectory
+# in the main directory.
+today = target_dir + os.sep + time.strftime('%Y%m%d')
+# The current time is the name of the zip archive.
+now = time.strftime('%H%M%S')
+
+# The name of the zip file
+target = today + os.sep + now + '.zip'
+
+# Create the subdirectory if it isn't already there
+if not os.path.exists(today):
+    os.mkdir(today)
+    print 'Successfully created directory', today
+
+# 5. We use the zip command to put the files in a zip archive
+zip_command = "zip -r {0} {1}".format(target,
+                                      ' '.join(source))
+
+# Run the backup
+print "Zip command is:"
+print zip_command
+print "Running:"
+if os.system(zip_command) == 0:
+    print 'Successful backup to', target
+else:
+    print 'Backup FAILED'

+ 10 - 0
programs/backup_ver2.txt

@@ -0,0 +1,10 @@
+$ python backup_ver2.py
+Successfully created directory /Users/swa/backup/20140329
+Zip command is:
+zip -r /Users/swa/backup/20140329/073201.zip /Users/swa/notes
+Running:
+  adding: Users/swa/notes/ (stored 0%)
+  adding: Users/swa/notes/blah1.txt (stored 0%)
+  adding: Users/swa/notes/blah2.txt (stored 0%)
+  adding: Users/swa/notes/blah3.txt (stored 0%)
+Successful backup to /Users/swa/backup/20140329/073201.zip

+ 58 - 0
programs/backup_ver3.py

@@ -0,0 +1,58 @@
+import os
+import time
+
+# 1. The files and directories to be backed up are
+# specified in a list.
+# Example on Windows:
+# source = ['"C:\\My Documents"', 'C:\\Code']
+# Example on Mac OS X and Linux:
+source = ['/Users/swa/notes']
+# Notice we had to use double quotes inside the string
+# for names with spaces in it.
+
+# 2. The backup must be stored in a
+# main backup directory
+# Example on Windows:
+# target_dir = 'E:\\Backup'
+# Example on Mac OS X and Linux:
+target_dir = '/Users/swa/backup'
+# Remember to change this to which folder you will be using
+
+# Create target directory if it is not present
+if not os.path.exists(target_dir):
+    os.mkdir(target_dir) # make directory
+
+# 3. The files are backed up into a zip file.
+# 4. The current day is the name of the subdirectory
+# in the main directory.
+today = target_dir + os.sep + time.strftime('%Y%m%d')
+# The current time is the name of the zip archive.
+now = time.strftime('%H%M%S')
+
+# Take a comment from the user to
+# create the name of the zip file
+comment = raw_input('Enter a comment --> ')
+# Check if a comment was entered
+if len(comment) == 0:
+    target = today + os.sep + now + '.zip'
+else:
+    target = today + os.sep + now + '_' +
+        comment.replace(' ', '_') + '.zip'
+
+# Create the subdirectory if it isn't already there
+if not os.path.exists(today):
+    os.mkdir(today)
+    print 'Successfully created directory', today
+
+# 5. We use the zip command to put the files in a zip archive
+zip_command = "zip -r {0} {1}".format(target,
+                                      ' '.join(source))
+
+# Run the backup
+print "Zip command is:"
+print zip_command
+print "Running:"
+if os.system(zip_command) == 0:
+    print 'Successful backup to', target
+else:
+    print 'Backup FAILED'

+ 5 - 0
programs/backup_ver3.txt

@@ -0,0 +1,5 @@
+$ python backup_ver3.py
+  File "backup_ver3.py", line 39
+    target = today + os.sep + now + '_' +
+                                        ^
+SyntaxError: invalid syntax

+ 58 - 0
programs/backup_ver4.py

@@ -0,0 +1,58 @@
+import os
+import time
+
+# 1. The files and directories to be backed up are
+# specified in a list.
+# Example on Windows:
+# source = ['"C:\\My Documents"', 'C:\\Code']
+# Example on Mac OS X and Linux:
+source = ['/Users/swa/notes']
+# Notice we had to use double quotes inside the string
+# for names with spaces in it.
+
+# 2. The backup must be stored in a
+# main backup directory
+# Example on Windows:
+# target_dir = 'E:\\Backup'
+# Example on Mac OS X and Linux:
+target_dir = '/Users/swa/backup'
+# Remember to change this to which folder you will be using
+
+# Create target directory if it is not present
+if not os.path.exists(target_dir):
+    os.mkdir(target_dir) # make directory
+
+# 3. The files are backed up into a zip file.
+# 4. The current day is the name of the subdirectory
+# in the main directory.
+today = target_dir + os.sep + time.strftime('%Y%m%d')
+# The current time is the name of the zip archive.
+now = time.strftime('%H%M%S')
+
+# Take a comment from the user to
+# create the name of the zip file
+comment = raw_input('Enter a comment --> ')
+# Check if a comment was entered
+if len(comment) == 0:
+    target = today + os.sep + now + '.zip'
+else:
+    target = today + os.sep + now + '_' + \
+        comment.replace(' ', '_') + '.zip'
+
+# Create the subdirectory if it isn't already there
+if not os.path.exists(today):
+    os.mkdir(today)
+    print 'Successfully created directory', today
+
+# 5. We use the zip command to put the files in a zip archive
+zip_command = "zip -r {0} {1}".format(target,
+                                      ' '.join(source))
+
+# Run the backup
+print "Zip command is:"
+print zip_command
+print "Running:"
+if os.system(zip_command) == 0:
+    print 'Successful backup to', target
+else:
+    print 'Backup FAILED'

+ 10 - 0
programs/backup_ver4.txt

@@ -0,0 +1,10 @@
+$ python backup_ver4.py
+Enter a comment --> added new examples
+Zip command is:
+zip -r /Users/swa/backup/20140329/074122_added_new_examples.zip /Users/swa/notes
+Running:
+  adding: Users/swa/notes/ (stored 0%)
+  adding: Users/swa/notes/blah1.txt (stored 0%)
+  adding: Users/swa/notes/blah2.txt (stored 0%)
+  adding: Users/swa/notes/blah3.txt (stored 0%)
+Successful backup to /Users/swa/backup/20140329/074122_added_new_examples.zip

+ 6 - 0
programs/break.py

@@ -0,0 +1,6 @@
+while True:
+    s = raw_input('Enter something : ')
+    if s == 'quit':
+        break
+    print 'Length of the string is', len(s)
+print 'Done'

+ 11 - 0
programs/break.txt

@@ -0,0 +1,11 @@
+$ python break.py
+Enter something : Programming is fun
+Length of the string is 18
+Enter something : When the work is done
+Length of the string is 21
+Enter something : if you wanna make your work also fun:
+Length of the string is 37
+Enter something : use Python!
+Length of the string is 11
+Enter something : quit
+Done

+ 9 - 0
programs/continue.py

@@ -0,0 +1,9 @@
+while True:
+    s = raw_input('Enter something : ')
+    if s == 'quit':
+        break
+    if len(s) < 3:
+        print 'Too small'
+        continue
+    print 'Input is of sufficient length'
+    # Do other kinds of processing here...

+ 8 - 0
programs/continue.txt

@@ -0,0 +1,8 @@
+$ python continue.py
+Enter something : a
+Too small
+Enter something : 12
+Too small
+Enter something : abc
+Input is of sufficient length
+Enter something : quit

+ 23 - 0
programs/ds_reference.py

@@ -0,0 +1,23 @@
+print 'Simple Assignment'
+shoplist = ['apple', 'mango', 'carrot', 'banana']
+# mylist is just another name pointing to the same object!
+mylist = shoplist
+
+# I purchased the first item, so I remove it from the list
+del shoplist[0]
+
+print 'shoplist is', shoplist
+print 'mylist is', mylist
+# Notice that both shoplist and mylist both print
+# the same list without the 'apple' confirming that
+# they point to the same object
+
+print 'Copy by making a full slice'
+# Make a copy by doing a full slice
+mylist = shoplist[:]
+# Remove first item
+del mylist[0]
+
+print 'shoplist is', shoplist
+print 'mylist is', mylist
+# Notice that now the two lists are different

+ 7 - 0
programs/ds_reference.txt

@@ -0,0 +1,7 @@
+$ python ds_reference.py
+Simple Assignment
+shoplist is ['mango', 'carrot', 'banana']
+mylist is ['mango', 'carrot', 'banana']
+Copy by making a full slice
+shoplist is ['mango', 'carrot', 'banana']
+mylist is ['carrot', 'banana']

+ 23 - 0
programs/ds_seq.py

@@ -0,0 +1,23 @@
+shoplist = ['apple', 'mango', 'carrot', 'banana']
+name = 'swaroop'
+
+# Indexing or 'Subscription' operation #
+print 'Item 0 is', shoplist[0]
+print 'Item 1 is', shoplist[1]
+print 'Item 2 is', shoplist[2]
+print 'Item 3 is', shoplist[3]
+print 'Item -1 is', shoplist[-1]
+print 'Item -2 is', shoplist[-2]
+print 'Character 0 is', name[0]
+
+# Slicing on a list #
+print 'Item 1 to 3 is', shoplist[1:3]
+print 'Item 2 to end is', shoplist[2:]
+print 'Item 1 to -1 is', shoplist[1:-1]
+print 'Item start to end is', shoplist[:]
+
+# Slicing on a string #
+print 'characters 1 to 3 is', name[1:3]
+print 'characters 2 to end is', name[2:]
+print 'characters 1 to -1 is', name[1:-1]
+print 'characters start to end is', name[:]

+ 16 - 0
programs/ds_seq.txt

@@ -0,0 +1,16 @@
+$ python ds_seq.py
+Item 0 is apple
+Item 1 is mango
+Item 2 is carrot
+Item 3 is banana
+Item -1 is banana
+Item -2 is carrot
+Character 0 is s
+Item 1 to 3 is ['mango', 'carrot']
+Item 2 to end is ['carrot', 'banana']
+Item 1 to -1 is ['mango', 'carrot']
+Item start to end is ['apple', 'mango', 'carrot', 'banana']
+characters 1 to 3 is wa
+characters 2 to end is aroop
+characters 1 to -1 is waroo
+characters start to end is swaroop

+ 15 - 0
programs/ds_str_methods.py

@@ -0,0 +1,15 @@
+# This is a string object
+name = 'Swaroop'
+
+if name.startswith('Swa'):
+    print 'Yes, the string starts with "Swa"'
+
+if 'a' in name:
+    print 'Yes, it contains the string "a"'
+
+if name.find('war') != -1:
+    print 'Yes, it contains the string "war"'
+
+delimiter = '_*_'
+mylist = ['Brazil', 'Russia', 'India', 'China']
+print delimiter.join(mylist)

+ 5 - 0
programs/ds_str_methods.txt

@@ -0,0 +1,5 @@
+$ python ds_str_methods.py
+Yes, the string starts with "Swa"
+Yes, it contains the string "a"
+Yes, it contains the string "war"
+Brazil_*_Russia_*_India_*_China

+ 23 - 0
programs/ds_using_dict.py

@@ -0,0 +1,23 @@
+# 'ab' is short for 'a'ddress'b'ook
+
+ab = {  'Swaroop'   : 'swaroop@swaroopch.com',
+        'Larry'     : 'larry@wall.org',
+        'Matsumoto' : 'matz@ruby-lang.org',
+        'Spammer'   : 'spammer@hotmail.com'
+    }
+
+print "Swaroop's address is", ab['Swaroop']
+
+# Deleting a key-value pair
+del ab['Spammer']
+
+print '\nThere are {} contacts in the address-book\n'.format(len(ab))
+
+for name, address in ab.items():
+    print 'Contact {} at {}'.format(name, address)
+
+# Adding a key-value pair
+ab['Guido'] = 'guido@python.org'
+
+if 'Guido' in ab:
+    print "\nGuido's address is", ab['Guido']

+ 10 - 0
programs/ds_using_dict.txt

@@ -0,0 +1,10 @@
+$ python ds_using_dict.py
+Swaroop's address is swaroop@swaroopch.com
+
+There are 3 contacts in the address-book
+
+Contact Swaroop at swaroop@swaroopch.com
+Contact Matsumoto at matz@ruby-lang.org
+Contact Larry at larry@wall.org
+
+Guido's address is guido@python.org

+ 22 - 0
programs/ds_using_list.py

@@ -0,0 +1,22 @@
+# This is my shopping list
+shoplist = ['apple', 'mango', 'carrot', 'banana']
+
+print 'I have', len(shoplist), 'items to purchase.'
+
+print 'These items are:',
+for item in shoplist:
+    print item,
+
+print '\nI also have to buy rice.'
+shoplist.append('rice')
+print 'My shopping list is now', shoplist
+
+print 'I will sort my list now'
+shoplist.sort()
+print 'Sorted shopping list is', shoplist
+
+print 'The first item I will buy is', shoplist[0]
+olditem = shoplist[0]
+del shoplist[0]
+print 'I bought the', olditem
+print 'My shopping list is now', shoplist

+ 10 - 0
programs/ds_using_list.txt

@@ -0,0 +1,10 @@
+$ python ds_using_list.py
+I have 4 items to purchase.
+These items are: apple mango carrot banana
+I also have to buy rice.
+My shopping list is now ['apple', 'mango', 'carrot', 'banana', 'rice']
+I will sort my list now
+Sorted shopping list is ['apple', 'banana', 'carrot', 'mango', 'rice']
+The first item I will buy is apple
+I bought the apple
+My shopping list is now ['banana', 'carrot', 'mango', 'rice']

+ 14 - 0
programs/ds_using_tuple.py

@@ -0,0 +1,14 @@
+# I would recommend always using parentheses
+# to indicate start and end of tuple
+# even though parentheses are optional.
+# Explicit is better than implicit.
+zoo = ('python', 'elephant', 'penguin')
+print 'Number of animals in the zoo is', len(zoo)
+
+new_zoo = 'monkey', 'camel', zoo
+print 'Number of cages in the new zoo is', len(new_zoo)
+print 'All animals in new zoo are', new_zoo
+print 'Animals brought from old zoo are', new_zoo[2]
+print 'Last animal brought from old zoo is', new_zoo[2][2]
+print 'Number of animals in the new zoo is', \
+    len(new_zoo)-1+len(new_zoo[2])

+ 7 - 0
programs/ds_using_tuple.txt

@@ -0,0 +1,7 @@
+$ python ds_using_tuple.py
+Number of animals in the zoo is 3
+Number of cages in the new zoo is 3
+All animals in new zoo are ('monkey', 'camel', ('python', 'elephant', 'penguin'))
+Animals brought from old zoo are ('python', 'elephant', 'penguin')
+Last animal brought from old zoo is penguin
+Number of animals in the new zoo is 5

+ 24 - 0
programs/exceptions_finally.py

@@ -0,0 +1,24 @@
+import sys
+import time
+
+f = None
+try:
+    f = open("poem.txt")
+    # Our usual file-reading idiom
+    while True:
+        line = f.readline()
+        if len(line) == 0:
+            break
+        print line,
+        sys.stdout.flush()
+        print "Press ctrl+c now"
+        # To make sure it runs for a while
+        time.sleep(2)
+except IOError:
+    print "Could not find file poem.txt"
+except KeyboardInterrupt:
+    print "!! You cancelled the reading from the file."
+finally:
+    if f:
+        f.close()
+    print "(Cleaning up: Closed the file)"

+ 5 - 0
programs/exceptions_finally.txt

@@ -0,0 +1,5 @@
+$ python exceptions_finally.py
+Programming is fun
+Press ctrl+c now
+^C!! You cancelled the reading from the file.
+(Cleaning up: Closed the file)

+ 8 - 0
programs/exceptions_handle.py

@@ -0,0 +1,8 @@
+try:
+    text = raw_input('Enter something --> ')
+except EOFError:
+    print 'Why did you do an EOF on me?'
+except KeyboardInterrupt:
+    print 'You cancelled the operation.'
+else:
+    print 'You entered {}'.format(text)

+ 11 - 0
programs/exceptions_handle.txt

@@ -0,0 +1,11 @@
+# Press ctrl + d
+$ python exceptions_handle.py
+Enter something --> Why did you do an EOF on me?
+
+# Press ctrl + c
+$ python exceptions_handle.py
+Enter something --> ^CYou cancelled the operation.
+
+$ python exceptions_handle.py
+Enter something --> No exceptions
+You entered No exceptions

+ 20 - 0
programs/exceptions_raise.py

@@ -0,0 +1,20 @@
+class ShortInputException(Exception):
+    '''A user-defined exception class.'''
+    def __init__(self, length, atleast):
+        Exception.__init__(self)
+        self.length = length
+        self.atleast = atleast
+
+try:
+    text = raw_input('Enter something --> ')
+    if len(text) < 3:
+        raise ShortInputException(len(text), 3)
+    # Other work can continue as usual here
+except EOFError:
+    print 'Why did you do an EOF on me?'
+except ShortInputException as ex:
+    print ('ShortInputException: The input was ' + \
+           '{0} long, expected at least {1}')\
+          .format(ex.length, ex.atleast)
+else:
+    print 'No exception was raised.'

+ 7 - 0
programs/exceptions_raise.txt

@@ -0,0 +1,7 @@
+$ python exceptions_raise.py
+Enter something --> a
+ShortInputException: The input was 1 long, expected at least 3
+
+$ python exceptions_raise.py
+Enter something --> abc
+No exception was raised.

+ 3 - 0
programs/exceptions_using_with.py

@@ -0,0 +1,3 @@
+with open("poem.txt") as f:
+    for line in f:
+        print line,

+ 4 - 0
programs/for.py

@@ -0,0 +1,4 @@
+for i in range(1, 5):
+    print i
+else:
+    print 'The for loop is over'

+ 6 - 0
programs/for.txt

@@ -0,0 +1,6 @@
+$ python for.py
+1
+2
+3
+4
+The for loop is over

+ 7 - 0
programs/function1.py

@@ -0,0 +1,7 @@
+def say_hello():
+    # block belonging to the function
+    print 'hello world'
+# End of function
+
+say_hello() # call the function
+say_hello() # call the function again

+ 3 - 0
programs/function1.txt

@@ -0,0 +1,3 @@
+$ python function1.py
+hello world
+hello world

+ 5 - 0
programs/function_default.py

@@ -0,0 +1,5 @@
+def say(message, times=1):
+    print message * times
+
+say('Hello')
+say('World', 5)

+ 3 - 0
programs/function_default.txt

@@ -0,0 +1,3 @@
+$ python function_default.py
+Hello
+WorldWorldWorldWorldWorld

+ 15 - 0
programs/function_docstring.py

@@ -0,0 +1,15 @@
+def print_max(x, y):
+    '''Prints the maximum of two numbers.
+
+    The two values must be integers.'''
+    # convert to integers, if possible
+    x = int(x)
+    y = int(y)
+
+    if x > y:
+        print x, 'is maximum'
+    else:
+        print y, 'is maximum'
+
+print_max(3, 5)
+print print_max.__doc__

+ 5 - 0
programs/function_docstring.txt

@@ -0,0 +1,5 @@
+$ python function_docstring.py
+5 is maximum
+Prints the maximum of two numbers.
+
+    The two values must be integers.

+ 11 - 0
programs/function_global.py

@@ -0,0 +1,11 @@
+x = 50
+
+def func():
+    global x
+
+    print 'x is', x
+    x = 2
+    print 'Changed global x to', x
+
+func()
+print 'Value of x is', x

+ 4 - 0
programs/function_global.txt

@@ -0,0 +1,4 @@
+$ python function_global.py
+x is 50
+Changed global x to 2
+Value of x is 2

+ 6 - 0
programs/function_keyword.py

@@ -0,0 +1,6 @@
+def func(a, b=5, c=10):
+    print 'a is', a, 'and b is', b, 'and c is', c
+
+func(3, 7)
+func(25, c=24)
+func(c=50, a=100)

+ 4 - 0
programs/function_keyword.txt

@@ -0,0 +1,4 @@
+$ python function_keyword.py
+a is 3 and b is 7 and c is 10
+a is 25 and b is 5 and c is 24
+a is 100 and b is 5 and c is 50

+ 9 - 0
programs/function_local.py

@@ -0,0 +1,9 @@
+x = 50
+
+def func(x):
+    print 'x is', x
+    x = 2
+    print 'Changed local x to', x
+
+func(x)
+print 'x is still', x

+ 4 - 0
programs/function_local.txt

@@ -0,0 +1,4 @@
+$ python function_local.py
+x is 50
+Changed local x to 2
+x is still 50

+ 16 - 0
programs/function_param.py

@@ -0,0 +1,16 @@
+def print_max(a, b):
+    if a > b:
+        print a, 'is maximum'
+    elif a == b:
+        print a, 'is equal to', b
+    else:
+        print b, 'is maximum'
+
+# directly pass literal values
+print_max(3, 4)
+
+x = 5
+y = 7
+
+# pass variables as arguments
+print_max(x, y)

+ 3 - 0
programs/function_param.txt

@@ -0,0 +1,3 @@
+$ python function_param.py
+4 is maximum
+7 is maximum

+ 9 - 0
programs/function_return.py

@@ -0,0 +1,9 @@
+def maximum(x, y):
+    if x > y:
+        return x
+    elif x == y:
+        return 'The numbers are equal'
+    else:
+        return y
+
+print maximum(2, 3)

+ 2 - 0
programs/function_return.txt

@@ -0,0 +1,2 @@
+$ python function_return.py
+3

+ 9 - 0
programs/function_varargs.py

@@ -0,0 +1,9 @@
+def total(initial=5, *numbers, **keywords):
+    count = initial
+    for number in numbers:
+        count += number
+    for key in keywords:
+        count += keywords[key]
+    return count
+
+print total(10, 1, 2, 3, vegetables=50, fruits=100)

+ 2 - 0
programs/function_varargs.txt

@@ -0,0 +1,2 @@
+$ python function_varargs.py
+166

+ 19 - 0
programs/if.py

@@ -0,0 +1,19 @@
+number = 23
+guess = int(raw_input('Enter an integer : '))
+
+if guess == number:
+    # New block starts here
+    print 'Congratulations, you guessed it.'
+    print '(but you do not win any prizes!)'
+    # New block ends here
+elif guess < number:
+    # Another block
+    print 'No, it is a little higher than that'
+    # You can do whatever you want in a block ...
+else:
+    print 'No, it is a little lower than that'
+    # you must have guessed > number to reach here
+
+print 'Done'
+# This last statement is always executed,
+# after the if statement is executed.

+ 15 - 0
programs/if.txt

@@ -0,0 +1,15 @@
+$ python if.py
+Enter an integer : 50
+No, it is a little lower than that
+Done
+
+$ python if.py
+Enter an integer : 22
+No, it is a little higher than that
+Done
+
+$ python if.py
+Enter an integer : 23
+Congratulations, you guessed it.
+(but you do not win any prizes!)
+Done

+ 11 - 0
programs/io_input.py

@@ -0,0 +1,11 @@
+def reverse(text):
+    return text[::-1]
+
+def is_palindrome(text):
+    return text == reverse(text)
+
+something = raw_input("Enter text: ")
+if is_palindrome(something):
+    print "Yes, it is a palindrome"
+else:
+    print "No, it is not a palindrome"

+ 11 - 0
programs/io_input.txt

@@ -0,0 +1,11 @@
+$ python io_input.py
+Enter text: sir
+No, it is not a palindrome
+
+$ python io_input.py
+Enter text: madam
+Yes, it is a palindrome
+
+$ python io_input.py
+Enter text: racecar
+Yes, it is a palindrome

+ 21 - 0
programs/io_pickle.py

@@ -0,0 +1,21 @@
+import pickle
+
+# The name of the file where we will store the object
+shoplistfile = 'shoplist.data'
+# The list of things to buy
+shoplist = ['apple', 'mango', 'carrot']
+
+# Write to the file
+f = open(shoplistfile, 'wb')
+# Dump the object to a file
+pickle.dump(shoplist, f)
+f.close()
+
+# Destroy the shoplist variable
+del shoplist
+
+# Read back from the storage
+f = open(shoplistfile, 'rb')
+# Load the object from the file
+storedlist = pickle.load(f)
+print storedlist

+ 2 - 0
programs/io_pickle.txt

@@ -0,0 +1,2 @@
+$ python io_pickle.py
+['apple', 'mango', 'carrot']

+ 9 - 0
programs/io_unicode.py

@@ -0,0 +1,9 @@
+# encoding=utf-8
+import io
+
+f = io.open("abc.txt", "wt", encoding="utf-8")
+f.write(u"Imagine non-English language here")
+f.close()
+
+text = io.open("abc.txt", encoding="utf-8").read()
+print text

+ 28 - 0
programs/io_using_file.py

@@ -0,0 +1,28 @@
+poem = '''\
+Programming is fun
+When the work is done
+if you wanna make your work also fun:
+    use Python!
+'''
+
+# Open for 'w'riting
+f = open('poem.txt', 'w')
+# Write text to file
+f.write(poem)
+# Close the file
+f.close()
+
+# If no mode is specified,
+# 'r'ead mode is assumed by default
+f = open('poem.txt')
+while True:
+    line = f.readline()
+    # Zero length indicates EOF
+    if len(line) == 0:
+        break
+    # The `line` already has a newline
+    # at the end of each line
+    # since it is reading from a file.
+    print line,
+# close the file
+f.close()

+ 5 - 0
programs/io_using_file.txt

@@ -0,0 +1,5 @@
+$ python io_using_file.py
+Programming is fun
+When the work is done
+if you wanna make your work also fun:
+    use Python!

+ 4 - 0
programs/module_using_name.py

@@ -0,0 +1,4 @@
+if __name__ == '__main__':
+    print 'This program is being run by itself'
+else:
+    print 'I am being imported from another module'

+ 7 - 0
programs/module_using_name.txt

@@ -0,0 +1,7 @@
+$ python module_using_name.py
+This program is being run by itself
+
+$ python
+>>> import module_using_name
+I am being imported from another module
+>>>

+ 7 - 0
programs/module_using_sys.py

@@ -0,0 +1,7 @@
+import sys
+
+print('The command line arguments are:')
+for i in sys.argv:
+    print i
+
+print '\n\nThe PYTHONPATH is', sys.path, '\n'

+ 12 - 0
programs/module_using_sys.txt

@@ -0,0 +1,12 @@
+$ python module_using_sys.py
+The command line arguments are:
+module_using_sys.py
+we
+are
+arguments
+
+
+The PYTHONPATH is ['/tmp/py',
+# many entries here, not shown here
+'/Library/Python/2.7/site-packages',
+'/usr/local/lib/python2.7/site-packages']

+ 43 - 0
programs/more_decorator.py

@@ -0,0 +1,43 @@
+from time import sleep
+from functools import wraps
+import logging
+logging.basicConfig()
+log = logging.getLogger("retry")
+
+
+def retry(f):
+    @wraps(f)
+    def wrapped_f(*args, **kwargs):
+        MAX_ATTEMPTS = 5
+        for attempt in range(1, MAX_ATTEMPTS + 1):
+            try:
+                return f(*args, **kwargs)
+            except:
+                log.exception("Attempt %s/%s failed : %s",
+                              attempt,
+                              MAX_ATTEMPTS,
+                              (args, kwargs))
+                sleep(10 * attempt)
+        log.critical("All %s attempts failed : %s",
+                     MAX_ATTEMPTS,
+                     (args, kwargs))
+    return wrapped_f
+
+
+counter = 0
+
+
+@retry
+def save_to_database(arg):
+    print "Write to a database or make a network call or etc."
+    print "This will be automatically retried if exception is thrown."
+    global counter
+    counter += 1
+    # This will throw an exception in the first call
+    # And will work fine in the second call (i.e. a retry)
+    if counter < 2:
+        raise ValueError(arg)
+
+
+if __name__ == '__main__':
+    save_to_database("Some bad value")

+ 12 - 0
programs/more_decorator.txt

@@ -0,0 +1,12 @@
+$ python more_decorator.py
+Write to a database or make a network call or etc.
+This will be automatically retried if exception is thrown.
+ERROR:retry:Attempt 1/5 failed : (('Some bad value',), {})
+Traceback (most recent call last):
+  File "more_decorator.py", line 14, in wrapped_f
+    return f(*args, **kwargs)
+  File "more_decorator.py", line 39, in save_to_database
+    raise ValueError(arg)
+ValueError: Some bad value
+Write to a database or make a network call or etc.
+This will be automatically retried if exception is thrown.

+ 4 - 0
programs/more_lambda.py

@@ -0,0 +1,4 @@
+points = [ { 'x' : 2, 'y' : 3 },
+           { 'x' : 4, 'y' : 1 } ]
+points.sort(key=lambda i : i['y'])
+print points

+ 2 - 0
programs/more_lambda.txt

@@ -0,0 +1,2 @@
+$ python more_lambda.py
+[{'y': 1, 'x': 4}, {'y': 3, 'x': 2}]

+ 3 - 0
programs/more_list_comprehension.py

@@ -0,0 +1,3 @@
+listone = [2, 3, 4]
+listtwo = [2*i for i in listone if i > 2]
+print listtwo

+ 2 - 0
programs/more_list_comprehension.txt

@@ -0,0 +1,2 @@
+$ python more_list_comprehension.py
+[6, 8]

+ 4 - 0
programs/mymodule.py

@@ -0,0 +1,4 @@
+def say_hi():
+    print 'Hi, this is mymodule speaking.'
+
+__version__ = '0.1'

+ 4 - 0
programs/mymodule_demo.py

@@ -0,0 +1,4 @@
+import mymodule
+
+mymodule.say_hi()
+print 'Version', mymodule.__version__

+ 3 - 0
programs/mymodule_demo.txt

@@ -0,0 +1,3 @@
+$ python mymodule_demo.py
+Hi, this is mymodule speaking.
+Version 0.1

+ 4 - 0
programs/mymodule_demo2.py

@@ -0,0 +1,4 @@
+from mymodule import say_hi, __version__
+
+say_hi()
+print 'Version', __version__

+ 0 - 0
programs/oop_init.py


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff