by Mauricio J. Del Razo S. 2014
In [1]:
class alien:
# A property of all aliens
appearance = 'ugly'
Each of our aliens is an object that belongs to the class alien (Yes, I'm saying Aliens are objects)
In [2]:
ET = alien()
Alf = alien()
Yoda = alien()
Every one of our buddies will have the same appearance
In [3]:
print(ET.appearance, Alf.appearance, Yoda.appearance)
In [4]:
ET.color = 'red'
ET.head = 'giant'
ET.planet = 'Mars?'
Alf.color = 'yellow'
Alf.head = 'funny with an elephant trompe'
Alf.planet = 'Melmac'
Yoda.color = 'green'
Yoda.head = 'wrinkled with long hairy ears'
Yoda.planet = 'Jupitron'
In [5]:
print('ET:',ET.appearance,ET.color, ET.planet, ET.head)
print('Alf:',Alf.appearance,Alf.color, Alf.planet, Alf.head)
print('Yoda:',Yoda.appearance,Yoda.color, Yoda.planet, Yoda.head)
Class variables are usually shared among all the objects of that class; they are more "global", like appearance.
Instance variables are those unique to each object, like color, planet and head.
If we are not careful, we might end up messing up:
In [6]:
alien.appearance = 'handsome stallion'
print(ET.appearance,Alf.appearance,Yoda.appearance)
We call an object an instance of a certain class .
Each class (alien) has its class variables (appearance) that everyone in their class share with the same value.
Each instance of a class (an object like ET,Alf or Yoda) has unique values for their instance variables (color, planet and head)
It is better to define the variables when creating the class to avoid a mess. Whenever we define a new object using a class, the function "def init" is called. We use the variable "self" to make sure we are refering to the instance variables specific to each object.
In [7]:
# Second version of the alien class
class alienV2(object):
# Class variable
number = 0
# Initialization function
def __init__(self, name, color, planet, head):
# Instance variables
self.name = name
self.color = color
self.planet = planet
self.head = head
alienV2.number += 1
# A class function
def speak(self):
print('My name is ' + self.name + ' from the planet ' + self.planet + '; my head is '
+ self.head + ', and my skin gets more and more ' + self.color +
' when I tan in the sun. There are other ' + str(alienV2.number -1) + ' aliens like me hiding in this code.')
print(' ')
We can also define all the instance variables at the moment we create the object:
In [8]:
alien_1 = alienV2('ET','red','Mars','big')
alien_2 = alienV2('Alf','yellow','Melmac','funny with an elephant trompe')
alien_3 = alienV2('Yoda','green','Jupitron','wrinkled with long hairy ears')
We can also define actions or functions within the class. For instance, we can make our aliens introduce themselves:
In [9]:
alien_3.speak()
In [10]:
alienV2.number = 0
alien_list = []
alien_list.append(alienV2('ET','red','Mars','big'))
alien_list.append(alienV2('Alf','yellow','Melmac','funny with like an elephant trompe'))
alien_list.append(alienV2('Yoda','green','Jupitron','wrinkled with long hairy ears'))
In [11]:
for i in range(len(alien_list)):
alien_list[i].speak()
In [12]:
class your_class(object):
# Class variables here
def __init__(self,instance_var):
# Instance variables here (and in the init function)
self.instance_var = instance_var
# Define a functon or action for your object
def action(self):
# Do something, like:
self.instance_var = 0
If we want to extend the functionality of a class, we have a three possibilities: modify the class, rewrite the class or use class inheritance. If we modify the class, we will have to modify all the code that calls this class; rewriting the class seems to be a waste of time, since most of the functionality might already be there. The best choice is to use clas inheritance, which follows this structure:
In [13]:
# Define a child class that has alienV2 as parent class
%pylab inline
from IPython.display import Image
class alien_interactive(alienV2):
# Initialize child class function
def __init__(self, imgsrc, name, color, planet, head):
super(alien_interactive, self).__init__(name, color, planet, head)
self.imgsrc = imgsrc
def show_yourself(self):
img = Image(filename=self.imgsrc)
display(img)
self.speak()
In [14]:
alien_list = []
alienV2.number = 0 # Note it's not alien_interactive.number
alien_list.append(alien_interactive('images/ET.jpg','ET','red','Mars','big'))
alien_list.append(alien_interactive('images/Alf.jpg','Alf','yellow','Melmac','funny with like an elephant trompe'))
alien_list.append(alien_interactive('images/yoda.jpg','Yoda','green','Jupitron','wrinkled with long hairy ears'))
In [15]:
alien_list[1].show_yourself()
In [16]:
from IPython.html.widgets import interact
def show_interactive(alien_number):
alien_list[alien_number].show_yourself()
interact(show_interactive, alien_number=(0,2));
In [17]:
class your_class_child(your_class):
# Initialize child class function
def __init__(self, child_instance_variable, parent_instance_variable):
super(your_class_child, self).__init__(parent_instance_variable)
# Define child instance variables
self.child_instance_variable = child_instance_variable
# Add an action unique to the child class
def child_action(self):
# Do something, like
self.child_instance_variable = 0
This two commands are very useful when it comes to object oriented programming; however, they don't have to be neccesarily used in the context of object oriented programming. We can also used them when calling a function or other situations. Here we will cover a couple of examples in object oriented programming.
The argument *args let you pass an arbitrary number of arguments to your function. This is particularly useful, when you want to inherit from a parent class without knowing too much about it. For instance, lets make another child class of alienV2 with the same functionality as before, bu this time we will use *args.
In [18]:
# Define a child class that has alienV2 as parent class
class alien_interactiveV2(alienV2):
# Initialize child class function
def __init__(self, imgsrc,*args):
super(alien_interactiveV2, self).__init__(*args)
self.imgsrc = imgsrc
def show_yourself(self):
try:
img = Image(filename=self.imgsrc)
except:
img = Image(url=self.imgsrc)
display(img)
self.speak()
In [19]:
alien_list.append(alien_interactiveV2('http://tinyurl.com/mnwj7wj','Ridley Scott','white','LV223','voluptuous'))
interact(show_interactive, alien_number=(0,3));
The argument **kwargs let you pass a dictionary to your function. This is particularly useful, when you want to write into specific instance variables of your parent class without knowing too much about it, nor the order you have to pass them. For instance, lets make another child class of alienV2 with the same functionality as before, bu this time we will use **kwargs and *args.
In [20]:
# Define a child class that has alienV2 as parent class
class alien_interactiveV3(alienV2):
# Initialize child class function
def __init__(self, *args,**kwargs):
super(alien_interactiveV3, self).__init__(**kwargs)
self.imgsrc = args[0]
def show_yourself(self):
try:
img = Image(filename=self.imgsrc)
except:
img = Image(url=self.imgsrc)
display(img)
self.speak()
In [21]:
characteristics = {'head':"like Homer Simpson's with tentacles",
'name':'Zoidberg',
'color':'pink',
'planet':' Decapod 10'}
alien_list.append(alien_interactiveV3('http://tinyurl.com/ngdd6ul',**characteristics))
interact(show_interactive, alien_number=(0,4));
In [22]:
txt = 'my name is Zoidberg'
In [23]:
txt
Out[23]:
In [24]:
txt.upper()
Out[24]:
Loades modules like numpy, scipy, matplotlib, etc... are objets...
In [25]:
import numpy as np
In [26]:
np.__name__
Out[26]:
In [27]:
np.__class__
Out[27]:
Write np. and then press tab...
In [28]:
np.
For some more advance applications, also check "polymorphism".
Although, the examples presented in this notebook seem dumb; they provide all the core understanding of object oriented programming required to do scientific computing.
Some ideas of interesting applications in scientific computing:
1 Create a function func for the function $f(x) = sin(x)$.
2 A template of the parent class integrator is provided. This class will have all the common functionality to integrate a function f in the interval [a,b]. However, the method of integration is not yet providednor the integration function. Read carefully the template, note the method of integration is not defined:
In [ ]:
class Integrator:
def __init__(self, a, b, n):
self.a, self.b, self.n = a, b, n
self.points, self.weights = self.method()
def method(self):
raise NotImplementedError('no rule in class %s' %self.__class__.__name__)
3 Add an additional function called integrate(self,func) inside the class Integrator, which calculates the integral from the weigths $w_i$: self.weights at different points x_i:self.points. Note this should be arrays. The integral is calculated as
$$ \int_a^b f(x) dx = \sum_{i=0}^{n-1} w_i f(x_i) $$4 Create a child class of Integrator called Trapezoidal, where you define a function called method(self). This function should return two arrays: x and w corresponding to the points and their current weights.This should be the values correponding to the trapezoidal rule for integration. If you are not familiar with it, you can look for it online
5 Create a child class of Integrator called Midpoint. It should do the same as Trapezoidal but employing the midpoint method for numerical integration.
6 Create a separate function of x that plots $ \int_0^x sin(x) dx = 1 - cos(x), $ using any of the two methods you developed.
In [ ]: