Object orientation is one of the most essential aspects of modern programming. It’s a very broad field, so don’t expect to know everything there is to know about it by the end of this session. Our goal today is to learn the very basics of why most software developers tend to prefer object oriented programming and how to apply it within our own work.
Take a look at the featured picture of a farm vehicle made out of legos. One way of looking at that picture would be to see lots of individual legos. Another way of looking at it would show wheels, a transmission, a cockpit and a furrower. Each of these things put together form the tractor that you see.
Seeing the entire thing at a more abstract level – a tractor rather than a collection of legos – has many advantages. First of all, it’s simpler. Also, if parts break – for example the furrower – you can work on fixing them as individual parts, rather than thinking that you have to fix or redesign the whole tractor. Finally, in order to use the tractor, you don’t need to understand how every individual lego fits together. You can use an abstract interface – in the case of a real tractor, a steering wheel, pedals and a gearshift – in order to control the engine, transmission and several different regulating subsystems without having to deal with them directly.
Bundling ideas and data about the tractor is a way of abstracting away different details at different moments so that at any given time, you’re looking at what’s relevant and only dealing with that. Finding and fixing problems is easier, and extending the design also is less complex than if you were to redesign everything from scratch. When applied to software development, this concept is called object orientation. Just as every part of the tractor composes the tractor as a whole, but is also an independent part unto itself, in software development these concepts would be individual objects.
What are objects?
An object, in the world of programming, is a construct which holds data and behavior. If we’re talking about data or behavior associated with objects, we refer to it as an attribute, whereas behavior that an object is capable of is referred to as a method.
Objects are instances of classes. A class can be understood as a blueprint of an object – it describes how all objects of that class are designed, whereas an object which is instantiated from that class might be modified throughout its lifecycle, or it might need to keep track of assets which belong only to that specific object and not the entire class.
An easy example might be a sensor. A sensor can contain data, e.g. the distance to a detected object, as well as the pulse width used to control the sensor. In Python, this would be written like this:
class Sensor(object): # Create a class named Sensor # This class contains neither attributes nor methods pass s = Sensor() # Instantiate an object named s from class Sensor s.distance = 30 # Store attribute distance on object s with value 30 s.pulse_width = 100
The most obvious advantage of what we’ve done above is that the distance and pulse width belonging to this sensor now are obviously part of the sensor. That data is encapsulated within the object, so that these variables do not pollute the global namespace.
So now we’ve stored data – attributes – on our object. How does it work with behavior? Here’s an example:
class Sensor(object): def report_distance(self): print("The distance to the nearest object is " + str(self.distance) + " cm.") ... s = Sensor() # This would call s's report_distance method s.report_distance()
This incomplete implementation of the
Sensor class contains a method – behavior that the object can carry out. In this case, the
Sensor class would look up the distance it contains and report it using the
An interesting side note here: in Python, the first argument of any method is the object whose method is being called. This argument is passed implicitly into the method when it is called. By convention, it is named
self and it’s a good idea to follow this convention, but the language doesn’t enforce this. The point of this is that
self allows access to the methods and attributes stored in the object performing the method.
Why does this matter? It might be that two different
Sensors exist, and they both store their own
distance. By calling the
distance stored on
self, the objects only access the data which is relevant to that specific method call:
>>> s1, s2 = Sensor(), Sensor() >>> s1.distance = 30 >>> s2.distance = 80 >>> s1.report_distance() The distance to the nearest object is 30 cm. >>> s2.report_distance() The distance to the nearest object is 80 cm.
Back to abstraction
Think of the advantages of this approach when doing complex things with our sensor. You’ve already written some code that interacts with hardware and have certainly noted that it can be tedious to repeat the same lines of code over and over again to accomplish the same thing. With object orientation, you can reduce this so that your code more clearly reflects your intent. The advantages increase greatly with the complexity of the application, because attributes of objects can also be other objects, allowing you to encapsulate varying levels of complexity. Imagine programming a humanoid robot. If you want it to walk, you might program this:
while internally the robot would perhaps execute
if not self.eyes.obstacle_detected: self.legs.walk(5)
This might produce all manner of other calls to the eyes, which would detect obstacles, and to the legs, which would produce the actual steps and ensure that the robot doesn’t overbalance and fall down. With object orientation, all of that logic becomes a single method call!
Now it’s your turn to get your hands dirty.
Create a class
Friend with the attributes
weight. Write a method
introduce which causes an instance of
Friend to report these attributes.
Some polite conversation
Friend class with a method
greet which takes another
Friend as an argument, like this:
>>> freddy, daniel = Friend(), Friend() >>> freddy.name = "Frederic" >>> freddy.height = 190 >>> freddy.weight = 70 >>> daniel.name = "Daniel" >>> daniel.height = 170 >>> daniel.weight = 60 >>> daniel.introduce() Hi, my name is Daniel. I'm 170 cm tall and weigh 60 kg. >>> freddy.greet(daniel) Hi Daniel, I'm Frederic. Nice to meet you.
- Introduction to Object Oriented Programming with Python
- Special method names – ways to make your objects behave more like native data types