Author: Florent Hivert <florent.hivert@univ-rouen.fr>
This tutorial is an introduction to object oriented programming in Python and Sage. It requires basic knowledges on imperative/procedural programming (the most common programming style) that is conditional instructions, loops, functions (see Tutorial: Programming in Python and Sage), but now further knowledge about objects and classes is assumed. It is designed as an alternating sequence of formal introduction and exercises. Solutions to the exercises are given at the end.
As an object oriented, language, Python’s ‘’variables’’ behavior may be surprising for people used to imperative language like C or Maple. The reason is because they are not variables but names.
The following explanation is borrowed from David Goodger.
int a = 1;
|
![]() |
Box “a” now contains an integer 1.
Assigning another value to the same variable replaces the contents of the box:
a = 2;
|
![]() |
Now box “a” contains an integer 2.
Assigning one variable to another makes a copy of the value and puts it in the new box:
int b = a;
|
![]() |
![]() |
a = 1
|
![]() |
Here, an integer 1 object has a tag labelled “a”.
If we reassign to “a”, we just move the tag to another object:
a = 2
|
![]() |
![]() |
Now the name “a” is attached to an integer 2 object.
The original integer 1 object no longer has a tag “a”. It may live on, but we can’t get to it through the name “a”. (When an object has no more references or tags, it is removed from memory.)
If we assign one name to another, we’re just attaching another nametag to an existing object:
b = a
|
![]() |
The name “b” is just a second tag bound to the same object as “a”.
Although we commonly refer to “variables” even in Python (because it’s common terminology), we really mean “names” or “identifiers”. In Python, “variables” are nametags for values, not labelled boxes.
As a consequence:
The object oriented programming paradigm relies on the two following fundamental rules:
At this point, those two rules are a little meaningless, so let’s give some more or less precise definition of the terms:
Let’s start with some examples: We consider the vector space over whose
basis is indexed by permutations, and a particular element in it:
In python, everything is an object so there isn’t any difference between types and classes. On can get the class of the object el by:
As such, this is not very informative. We’ll go back to it later. The data associated to objects are stored in so called attributes. They are accessed through the syntax obj.attributes_name:
Modifying the attribute modifies the objects:
Warning
as a user, you are not supposed to do that by yourself (see note on private attributes below).
As an element of a vector space el has a particular behavior:
The behavior is defined through methods (support, coefficient). Note that this is true, even for equality, printing or mathematical operations. For example the call a == b actually is translated to the method call a.__eq__(b). The names of those special methods which are usually called through operators are fixed by the Python language and are of the form __name__. Example include __eq__, __le__ for operators == and <=, __repr__ (see Sage specifics about classes) for printing, __add__ and __mult__ for operators + and * (see http://docs.python.org/library/) for a complete list:
Some particular actions allows to modify the data structure of el:
Note
The class is stored in a particular attribute called __class__ the normal attribute are stored in a dictionary called __dict__:
Lots of sage objects are not Python objects but compiled Cython objects. Python sees them as builtin objects and you don’t have access to the data structure. Examples include integers and permutation group elements:
Note
Each objects corresponds to a portion of memory called its identity in python. You can get the identity using id:
This is different from mathematical identity:
To define some object, you first have to write a class. The class will defines the methods and the attributes of the object.
Let’s write a small class about glasses in a restaurant:
Let’s create a small glass:
Some comments:
Note
Private Attributes
The problem: object of different classes may share a common behavior.
For example, if one wants to deal now with different dishes (forks, spoons ...) then there is common behavior (becoming dirty and being washed). So the different classes associated to the different kinds of dishes should have the same clean, is_clean and wash methods. But copying and pasting code is very bad for maintenance: mistake are copied, and to change anything one has to remember the location of all the copy ! So there is a need for a mechanism which allows to factorizes the common behavior. It is called inheritance or sub-classing: one write a base class which factorizes the common behavior and reuse the methods from this class.
We first write a small class ‘’AbstractDish’’ which implement the “clean-dirty-wash” behavior:
Now one can reuse this behavior within a class Spoon:
Let’s tests it:
Any class can reuse the behavior of another class. One says that the subclass inherits from the superclass or that it derives from it.
Any instance of the subclass is also an instance its superclass:
If a subclass redefines a method, then it replaces the former one. One says that the subclass overloads the method. One can nevertheless explicitly call the hidden superclass method.
Note
Advanced superclass method call
Sometimes one wants to call an overloaded method without knowing in which class it is defined. On use the super operator:
A very common usage of this construct is to call the __init__ method of the super classes:
Compared to Python, Sage has its particular way to handles objects:
Here is a solution to the first exercise:
Let’s check that everything is working as expected:
Here is the solution to the second exercice:
Todo
Write demo and tests
That all folks !