### Python classes: basics beyond the absolute basics

#### by Amit

In this article, I will discuss a couple of things about Python’s classes assuming you know what the following does:

class Point(): def __init__(self, point): self.point = point

To refresh, we define a class `Point` which we will use to represent the co-ordinates of a point in space. We can create an instance of this class representing a point as follows:

p1 = Point((1,2,3))

There are two things which you must note:

- I assume that that the point is in a three dimensional space
- You describe the point as a tuple (no particular reason)

And you can define methods to do stuff with these points (such as finding the euclidean distance between two points, and such), etc. You know all of that. Let’s start with the things you may not know.

I am using a Python 3 interactive session. The final program will however work on both Python 2 and Python 3.

## Informative representation of your point

Let’s get back to creating the representation of a point using the above class: `p1=Point((1,2,3))`. Let’s see what `print(p1)` gives us:

>>> print(p1) <__main__.Point object at 0x7fb123e67dd0>

So it tells us that `p1` is a Point object and few other things which you can ignore. This is exactly what is, an object of `Point` class, but *to*Python. What is it to you or your program’s user? It is a point in space. Can we tell the user something more useful? We sure can. We will have to define a special method, `__str__()` in our class. This is how it will look after adding the method to `class Point`:

class Point(): def __init__(self, point): self.point = point def __str__(self): return 'Point: {0}'.format(str(self.point))

The `__str__()` method above returns a string consisting of a string representing the point (`str(self.point)`) and a word saying that it’s a point. You may include any other helpful information you may find relevant here. The only thing you have to keep in mind is that the return value should be a string. Let’s try printing a point object now:

>>> print(p1) Point: (1, 2, 3)

Much better isn’t it? Now your program’s user will have no problem in understanding what `p1` is and also makes it easy for you to display points in your program’s output.

## Definining custom operators

One of the basic things that you may want to do when you are working with points in space is find what is usually known as the euclidean distance. To refresh, for two points, p1 and p2 having co-ordinates (x1,y1,z1) and (x2,y2,z2), the distance is calculated as follows (in Python speak) math.sqrt((x1-x2)**2 + (y1-y2)**2 + (z1-z2)**2) (where `math.sqrt` is the square root function defined in the math module). For our `Point` class, you could define a method to do this. But, how about being able to do something like `print(p1-p2)` to print the distance between the two? This also plays well with our intuition of distance in 1 dimension (How far is 5 from 2? 5-2 = 3). Let’s try doing that with our current code:

>>> p1=Point((1,2,3)) >>> p2=Point((1,2,3)) >>> print(p1-p2) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for -: 'Point' and 'Point'

Of course, Python doesn’t have any idea what you want it do when you ask it to subtract p2 from p1. However, we can tell Python what to do by adding a new method, `__sub__()`. After adding this method, the class looks like this:

import math class Point(): def __init__(self, point): self.point = point def __str__(self): return 'Point: {0}'.format(str(self.point)) def __sub__(self, other): s=0 for x1,x2 in zip(self.point, other.point): s = s + (x1-x2)**2 return math.sqrt(s)

The `_sub__` method basically calculates the euclidean distance and returns it. The speciality of this method is that when you ask Python to subtract something from an object of `Point` class, it calls this method and the return value of this method is returned as the result of the subtraction operation. If you are curious as to which is `self` and which is `other` in `__sub__()` when you ask Python to evaluate: `p1-p2`,`self` refers to `p1` and other refers to `p2`.

Let’s now try subtracting `p2` from `p1` again:

>>> p1=Point((1,2,3)) >>> p2=Point((1,2,3)) >>> p1-p2 0.0 >>> p2=Point((1,2,4)) >>> p1-p2 1.0

So, you have basically defined the subtraction operator for objects of your `Point` class. Can you define other mathematical operators in such a fashion? Sure. Learn all about it here.

Here is the complete program (works with both Python 2 and 3):

from __future__ import print_function import math class Point(): def __init__(self, point): self.point = point def __str__(self): return 'Point: {0}'.format(str(self.point)) def __sub__(self, other): s=0 for x1,x2 in zip(self.point, other.point): s = s + (x1-x2)**2 return math.sqrt(s)

You may want to add the logic to your `__sub__()` method so that it checks if the points are of the same dimension. If not, then print a nice error message instead of printing a traceback. That’s it.

Also published here

I would suggest to consider the following:

if p1=Point((1,2,3)) and p2=Point((1,2,4)) then

p1-p2=Point((0,0,-1))

What do think about it? So it is not the distance? Right?

Hi Vladimir,

I think you are talking about vector subtraction there?

Right. If you are talking about the space then p1-p2 has a diraction. But any distance has no diraction. This is my point of view. In space we can define the class Point as:

class Point():

def __init__(self, (x, y, z)):

self.x = x

self.y = y

self.z = z

def __sub__(self, other):

p = Point((self.x – other.x, self.y – other.y, self.z – other.z))

return p

def __abs__(self):

s = 0.0

return math.sqrt(s + self.x ** 2 + self.y ** 2 + self.z ** 2)

def __str__(self):

return ‘Point: {0}’.format((self.x, self.y, self.z))

And abs function may be considered as a distance in this case.

Hi Vladmir,

Yes, absolutely. I see what you mean. Initially I was thinking of making this example a Vector instead, but just resorted to using a Point.

But your example should be helpful to the readers as well. Thank you.