Monday 10 September 2012

Python Decorators

Python Decorator is a strategic use of functional programing facilities. Decoration stands for some kind of modifications. Let us consider one example. Consider , we have some function takes one integer and maps to some other integer, take a squaring function for now.
>>> def square(x):
...     return x*x
and we have to make a generalized function which accepts functions of the above kind as arguments and produce new function which do some further maping. take a doubling method for now.
>>> def double(x):
...     return x*2
Now let us make a function mofifier function
>>> def modify(f):
...     def g(x):
...             return double(f(x))
...     return g
now we can have a new function which performs the two mappings squaring and doubling together

command
>>> newFun=modify(square)
>>> newFun(2)
8
we can generalize the use of such function modifying functions with concept of decorators as
>>> @modify
... def square(x):
...     return x*x
 now we have a modified version of function square(x)
>>> square
<function g at 0x93dc64c>
>>> square(2)
8
Just after defining the function square, it is passed to modify() and the result returned is used instead of square().
>>> def decGenerate(mapping):
...     def modify(f):
...             def g(x):
...                     return mapping(f(x))
...             return g
...     return modify
... 
>>> @decGenerate(double)
... def square(x):
...     return x*x
... 
>>> square(2)
8
Here function decGenerator(mappingFunction) returns a function makung functio modify(f) which can be used as decorator



Sunday 9 September 2012

some magic with python

Here I am trying to discuss about some special method attributes in python.

we define a class like
>>> class myClass:
...     def __init__(self,value):
...             self.value=value
...             print 'object initialized'
And an object instantiation is done by
>>> a=myClass(10)
object initialized
>>> b=myClass(20)
object initialized
This seems usual but the magic is in evaluating the function myClass(value). an expression in the formmyClass(args) causes a call to __init__(self,args) defined inside class myClass.

let us make a new object c with its value attribute as sum of those of objects a and b.
>>> c=myClass(a.value+b.value)
object initialized
>>> c.value
30
It will be awesome if we can perform
>>> c=a+b
object initialized
>>> c.value
30
 We can make this possible by including a magic function __add__ to the class definition of myClass.
>>> class myClass:
...     def __init__(self,value):
...             self.value=value
...             print 'object initialized'
...     def __add__(self,obj):
...             c=myClass(self.value+obj.value)
...             return c
 Here c=a+b is evaluated as c=a.__add__(b)
There are more such methods enables operator overloading for arithmetic operators

Operator Special method
- __sub__(self, other)
// __floordiv__(self, other)
/ __div__(self, other)
% __mod_(self, other)
** __pow__
<< __lshift__(self, other)
& __and__(self, other)
| __or__(self, other)
^ __xor__(self, other)

There are corresponding reflected arithmetic operators too. If we use __radd__ instead of __add__ in above example, c=a+b will be evaluated as c=b.__radd__(a). We can define custom behavior for a lot of operations other than these arithmetic operators, like attribute assignments, comparisons, unary arithmetic operations like '+', '-' etc

Now let us look on some awesome special methods which enables creation of sequence types.

We have a class mySequence
>>> class mysequance:
...     def __init__(self,list):
...             self.value=list
...     def __iter__(self):
...             return iter(self.value)
...     def __getitem__(self,index):
...             return self.value[index]
...     def __len__(self):
...             return len(self.value)
... 
>>> s=mysequance([1,2,3,4,5,6])
 

Now we can perform some  list operations as follows
>>> len(s)
6
>>> s[1]
2
>>> it=iter(s)
>>> for i in it:
...     print i
... 
1
2
3
4
5
6





















Saturday 1 September 2012

Python iterators, generators and list comprehension

Iterators

Iterators are objects which enables traversal of python sequence data structures like strings, tuples and lists which are so called iterable.
>>> list=[1,2,3,4]
>>> lit=iter(list)
>>> lit
<listiterator object at 0x96abd2c>
 we can use this iterator object to extract elements on the list one by one
>>> lit.next()
1
>>> lit.next()
2
>>> lit.next()
3
>>> lit.next()
4
>>> lit.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
Function next() raise Stopiteration exception when there is no more element in list to traverse.

 we can use iterator object instead of corresponding sequence variables in construct.
>>> tit=iter((1,2,3,4))
>>> tit
<tupleiterator object at 0x96abfcc>
>>> 3 in tit
True 

generators

>>> def listgen(n):
...     for i in range(n):
...             yield i
... 
Python interpret functions like above containing a yield statement in a special way unlike to other functions. When we call the function listgen(n)
>>> g=listgen(5)
>>> g
<generator object listgen at 0xb786af7c>
Instead of executing the function and returning the result, a generator object  corresponding to listgen() is returned. The use of generator object is similar to iterator object.
>>> g=listgen(3)
>>> g.next()
0
>>> g.next()
1
>>> g.next()
2
>>> g.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration 

List comprehension

squares=[i*i for i in range(10)  if i%2==1]
>>> squares
[1, 9, 25, 49, 81]
A list comprehension consists of brackets containing an expression followed by a for clause, then zero or more if clauses. This special construct returns a list. The above list comprehension statement gives same result as
>>> squares=[]
>>> for i in range(10):
...     if i%2==1:
...             squares.append(i*i)
... 
 or
>>>squares=map((lambda x: x*x),filter((lambda x:x%2==1), range(10)))

We can perform nested list comprehension like follows,
>>> matrix=[[1,2,3],[4,5,6],[7,8,9]]
>>> transpose=[[matrix[i][j] for i in range(len(matrix))] for j in range(len(matrix[0]))]
>>> transpose
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]