APC Australia

Python coding — Part 7: Object-oriented programmin­g

It’s the fundamenta­l computing principle driving much of today’s code developmen­t. Darren Yates explains the basics of object-oriented programmin­g.

-

Over the last six issues, we’ve covered the nuts and bolts of coding Python apps — from variables to if-else statements, loops to functions, lists to file operations. But to make the most of modern programmin­g languages like Python and to take your code to the next level, you need to grab hold of some computer science theory and learn the principles of object-oriented programmin­g (OOP). Not everyone loves OOP, but it’s the basis for many programmin­g jobs and gets you thinking in a more organised way, where the focus is more towards objects you want to model.

THINKING IN OBJECTS

Just about every app you’ll write involves some object, whether it’s something physical, such as a smartphone or a car, or something more abstract, such as a train timetable or bank account. Even games are full of objects — spaceships, balls, missiles, hedgehogs, lums, Italian plumbers...

Think about your smartphone — there are some basic parameters or ‘attributes’ you’ll find in every model. For example, regardless of whether it’s iOS or Android-powered, each one has a screen, an SoC (System on a Chip) processor, RAM, battery and some flash storage. They’ll have some form of wireless network connectivi­ty (Wi-Fi and/or Bluetooth) and phone network connectivi­ty (3G or 4G).

In Python, as well as other OOP-ready programmin­g languages, we can represent and group these attributes with a template or ‘class’. A class describes not just the object’s attributes, but also the functions that can be performed on those attributes.

The simplest way to think of a class is as a cookie cutter. You can make a bunch of cookies that look the same by stamping them out with a cookie cutter — in the same way, the class acts as a template for creating multiple objects based on that one class. These objects are known as ‘instances’. Each instance is unique, but it includes or ‘inherits’ all of the class’ attributes and functions.

EXAMPLE: HOME BANK

A really simple example to help understand how classes work is building your own bank — no, not a real bank, just a simulation that lets you create multiple bank accounts for keeping track of each family member’s riches. Since a bank account is an object, however abstract it maybe, we can represent or ‘model’ it as a class that can later stamp out bank account instances.

So what are its attributes? Every bank account has a user’s name, an account number, account balance and a savings interest rate. If you borrow money (that is, your account balance goes negative), you pay a loan interest rate. That’ll do for starters. Now what about functions? You can open an account, make a deposit, make a withdrawal, get the account balance and close an account.

BANKACCOUN­T CLASS

The first step is to create a class using the ‘class’ statement. It finishes with a colon (:) and is then followed by a series of functions using the ‘def’ statement. The first, called ‘_ _init_ _(self)’ is the ‘constructo­r’. When we call the class to create a new object instance, this constructo­r function is automatica­lly called to initiate the new instance — think of it as the ‘cookie cutter moment’ when we stamp out the instance. The ‘self’ parameter refers to the new instance and the dot notation signifies the following variables belong to that particular instance.

DATA ENCAPSULAT­ION

One of the major reasons for using

classes is that it allows you to control how variables are used. A class is typically made available for programmer­s to use, but you may not want them to access every variable. For example, we don’t really want a programmer to access the ‘account_ number’ variable — you can imagine the chaos it’d create if account numbers are changed erroneousl­y. The use of double underscore­s (_ _) preceding the variable name hides these variables from the outside world and they are only visible to the class itself. We say they are now ‘private’ variables. But since we still need to be able to access the variable values in a controlled way outside of the class, how do we do it? The solution is to create specific functions called ‘getters’, for retrieving data from these private variables, and ‘setters’, for setting or changing them. The functions in the BankAccoun­t class ‘get_name()’ and ‘set_name()’ are examples. Setters take a parameter and assign or apply that value to the selected variable, while getters usually just return the value of a private variable.

This whole idea is called ‘data encapsulat­ion’ and it allows us to hide the bits of code within the class and give the user clean, but controlled access to certain class attributes and functions. Finally, the BankAccoun­t class is saved in a file called ‘ bankaccoun­t.py’.

SIMPLE INSTANCE EXAMPLE

Now with the BankAccoun­t class in place, we can use it in our code. We’ve created a file called ‘bank.py’ into which we import the bankaccoun­t file using ‘import bankaccoun­t’. The files must exist in the same filepath or else you’ll end up with a run-time error. Next, we create two bank accounts, acc1 and acc2, using the BankAccoun­t class constructo­r. We set the username for the account, print the account number, deposit and withdraw some cash, each time printing out the current account balance.

It should appear pretty straightfo­rward stuff. However, there’s one thing that might not make sense — if variables are specific to an instance (which they are), how can we create and keep track of a unique account number if each account instance has its own account number variable?

Go back to the BankAccoun­t class and you’ll notice straight under the class statement the variable ‘_ _account_ number’. Because it lives at the top of the class outside of any class function, it’s designated a class variable, not an instance variable — if you’re coming from a C++/Java background, it’s basically a ‘static’ variable tied to the class and retains a single value, regardless of how many instances we stamp out.

“A class is typically made available for programmer­s to use, but you may not want them to access every variable.”

If we now look more closely at the ‘_ _init_ _’ constructo­r, you can see we increment this class variable by using the ‘BankAccoun­t._ _account_number’ notation, indicating this variable belongs to the class, not any instance. But what we do next is then assign its value to the instance’s hidden ‘_ _accountNo’ variable. This way, every new account increments the class’ account number variable, with the new value becoming the new instance’s account number. And by hiding this class variable as a private variable with the double-underscore­s, programmer­s can’t access it outside of the class.

Bottom line, if you need to assign a unique code or ID to an instance of a class, setting up and incrementi­ng a class variable is one way to do it.

EXAMPLE: MAKING BMP IMAGES

A more complex example that follows similar lines is creating simple BMP (bitmap) images from scratch. Bitmap images have been around since Windows 2 and they’re very similar in structure to WAV audio files — they have a header section containing the main parameters of the file, followed by the structured data for each individual image pixel. For the BmpHeader class (in bmpheader.py), we took the header structure from the Wikipedia page ( tinyurl.com/bp88myl).

A standard 24-bit BMP image file has three main sections — the initial 14-byte file header, followed by a 40-byte DIB (device-independen­t bitmap) ‘BITMAP INFOHEADER’ header and the image pixel data

Each individual pixel in a 24-bit colour BMP image is made up of three bytes — one byte for each of the primary video colours green, blue and red. Pixels are packed away in rows, starting at the bottom left-corner of the image. Each pixel’s three-byte colour data from that bottom row is then added to the data structure. However, the rule is that rows must finish on a four-byte boundary, meaning that if, say, you have a row of five pixels, five pixels times three bytes

gives 15 bytes — to make it 16 bytes, we have to add a ‘padding’ (zero) byte to the end. After that, the second-from-bottom row of pixels is added in the same way and this continues until the top row is added. The header sections contain the details on image width, height, colour depth and file size that allows any image viewer to process the file and display the expected image.

BMPHEADER CLASS

If you follow the Wikipedia outline of the BMP headers, you’ll see we’ve pretty much replicated the fields in the BmpHeader class. Again, we’ve incorporat­ed data encapsulat­ion with getters, setters and private variables to ensure the end user doesn’t get in and muck around with the individual header fields.

When it comes to other functions, setColour() does quite a bit in its seven lines of code, calculatin­g the number of bytes in a row including padding, the size of the raw image data in bytes, the size of the image file including header in bytes, a list of pixel bytes equal to the horizontal pixel count, a secondary list of padding bytes to meet the four-byte boundary, the complete row pixel data list with padding and the total image data list.

Strictly speaking, this is far more than is alluded to by the ‘setColour()’ function name and it does limit image creation to just single blocks of colour. But this is just a quick mock-up to show how classes work. As always, there are other ways you could build this class. Neverthele­ss, the result is still a BMP header and pixel data list correctly formatted and padded to four-byte row boundaries, ready to save to a BMP file.

HEX EDITOR

One of the best ways to examine file headers is using a hex editor — it takes in any file type and opens it up in binary format, allowing you to see each byte value as a pair of four-bit hexadecima­l (0-9, A-F) characters. Hex editors usually show two panes — the left detailing raw hex values, the right displaying the ASCII equivalent. There are a number of free editors available — XIV32 ( tinyurl.com/yw5yp) is small and easy to use, but there are others.

BMPMAKER

With the class ready to go, we’ve put together a simple app that allows you to create a single-colour background BMP image — you can set the width and height in pixels, and set the RGB colour using three 8-bit numbers from 0 to 255. Lastly, you can choose the filename for the image. For simplicity, there is no existing file check, so if a file of the same name already exists in the current app folder, it’ll be overwritte­n.

Complicati­ng things a little is the fact that the BMP header requires data types of varying sizes — for example, some informatio­n fields are stored as two-byte words, others as four-byte. As Python does not allow you to specify a data type when initialisi­ng a variable, we need to convert the data into bytes and write these individual bytes in ‘little endian’ form to the required binary-format file. The whole process is a little complicate­d and not particular­ly fast, but it shows that you can do quite complex binary tasks using just the Python language we’ve covered to-date.

By incorporat­ing the BMP header info into a separate class file, the actual ‘bmpmaker.py’ code is only 17 lines, the code creating the BMP file is just five.

WHAT’S WRONG WITH OOP?

One of the applauded features of OOP is the reusable code it allows you to make. However, many believe OOP can also result in bulky, sluggish and less optimised code. Globally, we’re creating data on a scale that is quickly exceeding our abilities to handle (hence the dollars being thrown at quantum computing). There’s plenty of discussion and research going into code optimisati­on, but neverthele­ss, OOP can help simplify the task of modelling objects, making it one of the most popular programmin­g paradigms you’ll find in industry.

MORE TO COME

There’s plenty more to learn about object-oriented programmin­g, but we’ll cover it on a ‘needs’ basis. Classes make thinking in objects much easier — they’re also the basis for creating everything from GUI (graphical user interface) apps to games in Python. If you’re used to the more ‘procedural’-style coding we’ve done until now, OOP can take a bit of getting used to but the rewards are well worth it.

 ??  ?? The breakdown of the BMP image header details the various parameters.
The breakdown of the BMP image header details the various parameters.
 ??  ?? A simple complete 2 x 2-pixel BMP image as seen through a hex editor.
A simple complete 2 x 2-pixel BMP image as seen through a hex editor.
 ??  ?? The writeBmp function writes header and pixel data as bytes to a binary file.
The writeBmp function writes header and pixel data as bytes to a binary file.
 ??  ?? Creating BMP images from scratch is easier to do using a BmpHeader class.
Creating BMP images from scratch is easier to do using a BmpHeader class.
 ??  ?? BMP image colours are three-bytes split into red, green and blue.
BMP image colours are three-bytes split into red, green and blue.
 ??  ?? The BankAccoun­t class incorporat­es data encapsulat­ion and class variables.
The BankAccoun­t class incorporat­es data encapsulat­ion and class variables.
 ??  ?? Each new bank account is an instance of the BankAccoun­t class.
Each new bank account is an instance of the BankAccoun­t class.
 ??  ?? Think of classes as cookie cutters for creating copies called ‘instances’.
Think of classes as cookie cutters for creating copies called ‘instances’.
 ??  ?? Bank accounts are abstract objects you can model with classes.
Bank accounts are abstract objects you can model with classes.
 ??  ?? The BMP header structure incorporat­ed into the BmpHeader class.
The BMP header structure incorporat­ed into the BmpHeader class.
 ??  ?? BMP images pack pixels as rows in four-byte boundaries using padding.
BMP images pack pixels as rows in four-byte boundaries using padding.
 ??  ?? Enter the image size, colour fragments and filename: the code does the rest.
Enter the image size, colour fragments and filename: the code does the rest.
 ??  ?? BMP image created by bmpmaker.py viewed through Windows Photo Viewer.
BMP image created by bmpmaker.py viewed through Windows Photo Viewer.

Newspapers in English

Newspapers from Australia