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





















3 comments:

  1. Nice post Dileep.

    Could you please elaborate what is the difference while executing the above snippet and below.


    >>> class myClass:
    ... def __init__(self,value):
    ... self.value=value
    ... print 'object initialized'
    ... def __add__(self,obj):
    ... return self.value + obj.value
    ...
    >>> a=myClass(10)
    object initialized
    >>> b=myClass(20)
    object initialized
    >>> print a+b
    30

    ReplyDelete
    Replies
    1. On changing the __add__ method of myClass, the behavior of binary + operator associated with objects of myClass is changed in such a way that two objects of myClass, on addition, gives a new object which is having type of value attribute of myClass.
      So it simply violates closure property of + over myClass objects :-).

      As a result, we cant perform

      >>> a=myClass(10)
      object initialized
      >>> b=myClass(20)
      object initialized
      >>> c=myClass(10)
      object initialized
      >>> d=a+b+c

      or something like

      >>> d=(a+b)+c+a

      which is possible in above snippet.

      Delete
    2. Thank you Dileep for the detailed Explanation.:-)

      Delete