Everything is an Object in Python
Aims
- Understand what an object is in Python
- Familiarise with the notion of object, instances, attributes and methods
Learning outcomes
- Creating basic classes in Python
Objects
In C/C++ you have seen many kinds of data structures: arrays, structs, pointers, linked lists, etc. They are fundamentally different ways to organise data in memory.
In Python, instead, any structure is fundamentally the same: it is an abstract entity called an object.
Objects in Python can be specialised, and so we can have objects of different types (which we can check with the type() function). But fundamentally everything is an object.
What are the characteristics of an object?
Objects are simple. They contain:
- Attributes: pieces of data that describe the object
- Methods: functions that operate on the object
And that’s it!
Syntactically this means one thing: that given a variable in python, we can always check its attributes and methods using the . operator (something that we insisted on the first year).
Try this in any python shell.
A full list of methods and attributes can also be obtained with the dir() function:
This will print a long list of methods and attributes that you can use with the variable a_number.
Attributes
Attributes are pieces of data that describe the object. For example, a string object has an attribute length, which tells you how many characters are in the string. You can access attributes using the . operator:
Methods
Methods are functions that operate on the object. For example, a list object has a method append(), which adds an element to the end of the list. You can call methods using the . operator followed by parentheses:
Custom Classes
The above examples are trivial and based on bult-in types. But we have the same for objects imported from modules (e.g. numpy arrays). This is because modules define custom classes.
Since in Python everything is an object, its syntax makes it very easy to define our own custom classes.
Example: A Particle Class
Let’s define a simple class to represent a particle in 2D space. The particle will have attributes for its position and velocity, and methods to update its position based on its velocity.
To define classes in Python we need a few syntactical conventions:
- a new keyword to define a class:
class - indentation to define the scope of the class and its methods (no curly braces)
- a special method called
__init__to define the constructor of the class, i.e. the function that actually creates the object in memory when needed.
This is a very minimal class definition. The name of the class is Particle. The constructor __init__ is a function that takes at least one input: self. This is a reference to the object itself, and it is used to define attributes and methods that belong to the object.
Encapsulation
Why do we need self? The idea is that we will create a variable of class Particle in the following way:
here the syntax Particle() calls the __init__ method (i.e. function) of the class Particle, and p is the variable that will hold the object in memory. It will be run only when the interpreter reaches that line. When it is run, the object p exists and needs to store all its attributes/ How can we refer to p and p only in our class definition? The answer is self: when the constructor is called, self will be a reference to p.
Why do we need a reference to p? because we want all the properties of p to be stored inside the object itself. This is called encapsulation.
So, in the rest of this workshop, you will try and create your own classes in Python to familiarise with the idea.
For this purpose, working inside a Jupyter notebook (or VSCode with Jupyter extension) is probably the best way to go, since you can test your code interactively.
Instances
Our initial example is trivial: the initial position are always (0,0). Let’s make it more interesting by allowing the user to specify the initial position when creating the object.
Now we can create two particles with different initial positions:
And we can access their attributes:
So, while p1 and p2 are both objects of class Particle, they are different objects with their own attributes. These are different instances of the same class.
More methods
At the moment our class only has a constructor that takes some attributes, but it doesn;t do much more. Let’s add a method to update the position of the particle based on a velocity.
Now we can create a particle and move it:
This will update the position of the particle p by adding the velocity components to its current position.
Combining objects together
Given Python’s simplicity it is then immediate to create objects together to create more complex structures. For example, we can readily create many particles using a for loop and store them in a list:
Notice that here we used the methods of the built-in object list together with our custom class Particle.