image

I am going over Dive in to Python, a book that is a classic reference on Python. Have been wanting to go over it since a month. I had postponed this book for the past one month as I felt I should get some decent practice in python coding before I get on with this classic reference. So, I went over Learning Python the HardWay, Think Python, Python Visual Quick Start guide. Also read a few intro articles to Python like Code Like a Pythonista, Style guides , etc. Now that I am kind of comfortable in coding Python, I though I should go over the book. One of the things that I figured out on the weekend is writing Literate Programming in Python. Pweave is the module that I am using to covert a .Pnw file to Restructured text document, rst and then use rst2wp module to convert it to plain html. The intention behind spending 4-6 hours on getting this setup ready is to document my learnings and code simulataneously. For some reason as soon as I started learning Python, I was eagerly looking to learn literate programming as it has helped me immensely in learning R and some packages in R. So,I was hoping that literate programming would make my Python learning effective.

Chapter 2 - Your First Python Program

  • Python has several implementations such as IronPython, Jython, PyPy, Stackless Python The default interpreter from python.org is the CPython implementation
  • Every Python functions returns something, either a value or None
  • Variable are never explicitly typed in Python. This sort of thing is called dynamic typing
  • Came across a very interesting comparison between Python datatypes and other language data types
    • Statically typed language - A language in which types are fixed at compile time. Most statically typed languages enforce this by requiring you to declare all variables with their datatypes before using them. Java and C are statically typed languages.
    • Dynamically typed language - A language in which types are discovered at execution time; the opposite of statically typed. VBScript and Python are dynamically typed, because they figure out what type a variable is when you first assign it a value.
    • Strongly typed language - A language in which types are always enforced. Java and Python are strongly typed. If you have an integer, you can’t treat it like a string without explicitly converting it.
    • Weakly typed language - A language in which types may be ignored; the opposite of strongly typed. VBScript is weakly typed. In VBScript, you can concatenate the string ‘12’ and the integer 3 to get the string ‘123’, then treat that as the integer 123, all without any explicit conversion.
    • Python is both dynamically typed language and strongly typed language. once a variable has a datatype, it actually matters
  • sys module is written in C . Also all the built-in modules are written in C
  • Everything in Python is an object, and almot everything has attributes and methods
  • sys module is an object that has path as the attribute
  • Definition of a class in Python is rather loose. Everything is an object in the sense that it can be assigned to a variable or passed as an argument to a function. Some objects have neither attributes nor methods. Not all objects are subclassable
  • I thought that 4 spaces as code indent is a MUST. This chapter says that it is not necessary. It only needs to be consistent spacing
  • Indentation is a requirement and not a matter of style. Hence all the programs look similar and hence it is easier to read and understand other people’s code
  • if __name__ trick - Modules are objects, and all modules have a built-in attribute __name__. A module’s __name__ depends on how you’re using the module. If you import the module, then __name__ is the module’s file name , with out a directory path or file extension. If you run the module as a standalone program, __name__ will be a special default value __main__

Chapter 3 - Native Datatypes

  • Dictionary keys are case sensitive
  • Dictionary supports mixed keys. Dictionary values can be string, integers, lists, dictionaries etc. However keys have some restrictions. They can be string, integers and some other data types
  • Dictionaries are an efficient means of storing sparse data
  • Sorting a dictionary using three different ways

import random

def sortedDictValues1(adict):

items = adict.items()

items.sort()

return \[value for key,value in items\]

def sortedDictValues2(adict):

keys = adict.keys()

keys.sort()

return \[adict\[key\] for key in keys\]

def sortedDictValues3(adict):

keys = adict.keys()

keys.sort()

return map(adict.get,keys)

adict ={}

for i in range(10):

adict\[i\] = round( random.random(),2)

print adict

print sortedDictValues1(adict)

print sortedDictValues2(adict)

print sortedDictValues3(adict)

{0: 0.23, 1: 0.97, 2: 0.1, 3: 0.52, 4: 0.42, 5: 0.21, 6: 0.19, 7: 0.36, 8: 0.39, 9: 0.36}

[0.23, 0.97, 0.1, 0.52, 0.42, 0.21, 0.19, 0.36, 0.39, 0.36]

[0.23, 0.97, 0.1, 0.52, 0.42, 0.21, 0.19, 0.36, 0.39, 0.36]

[0.23, 0.97, 0.1, 0.52, 0.42, 0.21, 0.19, 0.36, 0.39, 0.36]

  • Lists have two methods, extend and append, that look like they do the same thing, but are in fact completely different. extend takes a single argument, which is always a list, and adds each of the element of that list to the original list. On the other hand, append take one argument, which can be any data type.

  • Python accepts anything in boolean context according to the following rules

    • 0 is false

    • An empty string is false

    • An empty list is false

    • An empty tuple is false

    • An empty dictionary is false

  • remove only removes the first occurrence in the list

  • pop is an interesting beast as it removes the last element in the list as well as returns the deleted element

  • extend is faster than concatenating the list as the latter creates a new list whereas the former merely extends the list

  • tuples have no methods. They are immutable objects

  • tuples are faster than lists

  • It makes your code safer it you write-protect data and use of tuples can come in handy

  • Dictionary keys should be immutable and hence tuples can be dictionary keys

  • tuples can be converted to lists and vice-versa

  • use tuples to assign multiple values at once

  • An easy way to assign values to day of the week

(Sun,Mon,Tue,Wed,Thu,Fri,Sat) = range(7)

print Sat

6

  • Tuples are used in formating. I never observed this fact even though I worked through a ton of example in LPTHW. I need to be alert about the kind of code that I work on

  • Tuples are used in string concatenation as using a plus operator between string and integer raises an exception

  • One of the most powerful features of Python is the list comprehension, which provides a compact way of mapping a list in to another list by applying a function to each of the elements of the list

  • Every thing is an object. “,” is also an object as one can invoke join method

Chapter 4 - The Power of Introspection

This chapter starts off with a rather complex looking function and explains various components of the function

def info(object, spacing=10, collapse=1):

"""Print methods and doc strings.

Takes module, class, list, dictionary, or string."""

methodList = \[e for e in dir(object) if callable(getattr(object, e))\]

processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)

print "\\n".join(\["%s %s" %

                                 (method.ljust(spacing),

                                  processFunc(str(getattr(object, method).\_\_doc\_\_)))

                                 for method in methodList\])

li = []

print(info(li))

__add__ x.__add__(y) x+y

__class__ list() -> new empty list list(iterable) -> new list initialized from iterable’s items

__contains__ x.__contains__(y) y in x

__delattr__ x.__delattr__(‘name’) del x.name

__delitem__ x.__delitem__(y) del x[y]

__delslice__ x.__delslice__(i, j) del x[i:j] Use of negative indices is not supported.

__eq__ x.__eq__(y) x==y

__format__ default object formatter

__ge__ x.__ge__(y) x>=y

__getattribute__ x.__getattribute__(‘name’) x.name

__getitem__ x.__getitem__(y) x[y]

__getslice__ x.__getslice__(i, j) x[i:j] Use of negative indices is not supported.

__gt__ x.__gt__(y) x>y

__iadd__ x.__iadd__(y) x+=y

__imul__ x.__imul__(y) x*=y

__init__ x.__init__(…) initializes x; see help(type(x)) for signature

__iter__ x.__iter__() iter(x)

__le__ x.__le__(y) x<=y

__len__ x.__len__() len(x)

__lt__ x.__lt__(y) x<y

__mul__ x.__mul__(n) x*n

__ne__ x.__ne__(y) x!=y

__new__ T.__new__(S, …) -> a new object with type S, a subtype of T

__reduce__ helper for pickle

__reduce_ex__ helper for pickle

__repr__ x.__repr__() repr(x)

__reversed__ L.__reversed__() – return a reverse iterator over the list

__rmul__ x.__rmul__(n) n*x

__setattr__ x.__setattr__(‘name’, value) x.name = value

__setitem__ x.__setitem__(i, y) x[i]=y

__setslice__ x.__setslice__(i, j, y) x[i:j]=y Use of negative indices is not supported.

__sizeof__ L.__sizeof__() – size of L in memory, in bytes

__str__ x.__str__() str(x)

__subclasshook__ Abstract classes can override this to customize issubclass(). This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).

append L.append(object) – append object to end

count L.count(value) -> integer – return number of occurrences of value

extend L.extend(iterable) – extend list by appending elements from the iterable

index L.index(value, [start, [stop]]) -> integer – return first index of value. Raises ValueError if the value is not present.

insert L.insert(index, object) – insert object before index

pop L.pop([index]) -> item – remove and return item at index (default last). Raises IndexError if list is empty or index is out of range.

remove L.remove(value) – remove first occurrence of value. Raises ValueError if the value is not present.

reverse L.reverse() – reverse *IN PLACE*

sort L.sort(cmp=None, key=None, reverse=False) – stable sort *IN PLACE*; cmp(x, y) -> -1, 0, 1

None

  • str can be used to convert any thing in to a string

  • dir lists the attributes and methods of any object

  • callable objects include functions, class methods , even classes themselves

  • One can use getattr to invoke a function that is not known until the run time

  • getattr can be used as a dispatcher. Let’s say based on the type of input, you want to do something, you can use the various input types as function names and code the various functions , use getattr to dispatch to various functions

  • You can add a default function , in the getattr method

  • Python has powerful capabilities for mapping lists in to other lists, via list comprehensions.

  • The list filtering syntax [mapping-expression for element in source-list if filter-expression]

li = []

methodList = [e for e in dir(li) if callable(getattr(li, e))]

for item in methodList :

print item

__add__

__class__

__contains__

__delattr__

__delitem__

__delslice__

__eq__

__format__

__ge__

__getattribute__

__getitem__

__getslice__

__gt__

__iadd__

__imul__

__init__

__iter__

__le__

__len__

__lt__

__mul__

__ne__

__new__

__reduce__

__reduce_ex__

__repr__

__reversed__

__rmul__

__setattr__

__setitem__

__setslice__

__sizeof__

__str__

__subclasshook__

append

count

extend

index

insert

pop

remove

reverse

sort

  • Boolean is handled in a peculiar way in Python. 0,'',[],(),{} and None are false in boolean context, everything else is true.

  • In the case of OR statements, the statements are evaluated from left to right.If all the statements are false, then OR returns the last value

  • You can define one-line mini functions on the fly. These are called lambda functions

print (lambda x:x*2)(3)

6

  • There is no return statement. The function has no name. They cannot contain commands

  • If you want to encapsulate specific non-reusable code without littering code, use lambda functions

  • Assigning functions to variables and calling the function by referencing the variable is important to understand properly bya newbie. This mode of thought is vital to advancing your understanding of Python

Chapter 5 - Objects and Object Orientation

Like other chapters in the book, this chapter starts off with a page long code that captures all the important aspects that come in OOPS.

  • Learnt about os.path.splitext(f) a function that split the file name in to 2 parts, one before the dot and one after the dot

  • Another function useful in normalizing the path , os.path.normcase(f)

  • To decide between using from x import y OR import x, it depends on how frequently one is using y function in the code. If there is a possibility if namespace clashes, its better to import specific functions instead of import x

  • Avoid doing a wild import

  • __init__ is like a constructor method but it is not. The object has already been constructed by the time init function is called

  • Subclassing is done easily by merely listing the parent classes in the parenthesis

  • Python support multiple inheritance

  • using self in the class methods is only a convention, but a very strong convention

  • class acts like a dictionary

  • __init__ methods are optional, but when you define one, you must remember to explicitly call the ancestors __init__ method

  • Every class instance has a built-in attribute __class__, __name__, __bases__

  • In Python, simply call a clas as it were a function to create a new instance. There is no explicit new operator like in other languages

  • Memory leaks are rare in Python as it implements reference counting. As soon as something goes out of reference, it is removed immediately

  • In Python, you can forget about memory management and concentrate on other things.

  • There is no functional overloading in Python

  • UserString, UserList and UserDict are wrapper classes that mimic built-in string, list and dict classes

  • You can write special methods like __getitem__ and retrieve from the class instance using a dict syntax.

  • There are ton of special class methods that you can write like comparison, length, etc .

  • The convention for defining special class methods is to prepend and append two underscores to the function name

  • Class attributes are different from data attributes. One can think of class attributes as static attributes that are associated with the class. They are present even before instantiating the class. Class attributes are defined soon after the class definition statement

  • Data variables are defined in __init__ method

  • In Python, there is private or public scope for class method or attribute. There is no protected method like C++

  • __class__ is a built-in attribute of every class instance. It is a reference to the class that self is an instance of