Math 480: Python Classes and Object Oriented Programming

William Stein, 2010-04-22

 

Classes provide an elegant way to define your own new types in Python (hence Sage). 

First, a quick example:

{{{id=1| class Matrix2: def __init__(self, a, b, c, d): self.a = a; self.b = b; self.c = c; self.d = d def __repr__(self): return "[%s %s]\n[%s %s]"%(self.a, self.b, self.c, self.d) def determinant(self): return self.a*self.d - self.b*self.c def __add__(self, other): return Matrix2(self.a+other.a, self.b+other.b, self.c+other.c, self.d+other.d) /// }}}
  1. The class statement starts the definition of a new Python class.  
  2. The __init__ method gets called with inputs self,1,2,3,4 when we type Matrix2(1,2,3,4) below.  Here self is an instance of the class Matrix2.
  3. The __repr__ method gets called when we print out M.
  4. The determinant method computes the determinant of a given Matrix2 object.  You call it by typing M.determinant().
  5. The __add__ method gets called when you write M + something, whenever M is an instance of the class Matrix2.

Let's try it out!

{{{id=3| M = Matrix2(1,2,3,4); M /// [1 2] [3 4] }}} {{{id=4| print M.a, M.b, M.c, M.d /// 1 2 3 4 }}} {{{id=7| A = M + Matrix2(-1,3,7/2,pi); A /// [0 5] [13/2 pi + 4] }}} {{{id=13| A.determinant() /// -65/2 }}}

NOTE: The class Matrix2 itself is an object too, which you can pass around, etc.

{{{id=5| Matrix2 /// }}} {{{id=19| def f(C): return C(1,2,7,3) /// }}} {{{id=9| f(Matrix2) /// [1 2] [7 3] }}} {{{id=20| /// }}} {{{id=21| /// }}}

Object Oriented Programming (OOP)

http://www.mathworks.com/matlabcentral/fx_files/18972/12/content/comparelanguages.html

How to: Object-Oriented Programming

Object = Data + Methods

 

  1. Define classes for different sorts of mathematical objects of interest to you: matrices, fractions, sundials, etc.
  2. Define inheritance relationships between them, e.g., square copper sundials are a special kind of sundial.
  3. Implement behavior (methods).
{{{id=18| class Sundial: def __init__(self, size): self.size = size def __repr__(self): return "A sundial of size %s made of %s"%(self.size, self.material()) def material(self): return "stuff" class CopperSundial(Sundial): def material(self): return "copper" S = Sundial(2); print S C = CopperSundial(3); print C /// A sundial of size 2 made of stuff A sundial of size 3 made of copper }}}

What just happend?

  1. We define a class Sundial, which knows how to print itself, and also has a "material" method, which tells what it is made of. 
  2. We define another class CopperSundial, which derives from Sundial.  It can do everything a Sundial instance can do.  Moreover, we redefine the material method to return "copper".  
  3. We create an instance of the Sundial class.  The notation Python uses is calling the Sundial class: Sundial(2) means "make an instance self of the Sundial class and initialize it by calling the __init__ method with input self and size=2.
  4. We create an instance of CopperSundial, which redefines the material method to return "copper" instead of "stuff". 
{{{id=17| /// }}}

Conclusion: Being able to define your own new types of objects so easily in Python is really, really awesome.   And for mathematical programming, it is conceptually very useful. 

Read more about classes and object programming in the Python Tutorial (section 9), Dive Into Python, etc.  The book "Python in a Nutshell" has some nice tables of the "dunder" methods, such as __add__, which allow you to overload operators like +, *, /,  etc. 

{{{id=16| /// }}}