Top five things to improve your coding (in no particular order):
1. Document your code (automatically)
2. Write Object Oriented code (This post)
3. Get acquainted with useful packages
4. Write tests for your code
5. Use a version control system
This is the second post in this series, and we’re going to take a look at Object Oriented programming. Or in fact, I’m going to refer you to Arjan Codes YouTube video. (link updated, older blog post was dead link)
If you’re mainly using python interactively you probably won’t have come across objects and classes, but if you’re writing code of more than just a simply script to run non-interactively then you’ll most likely need to define at least one class. The times I’ve found myself using writing my own class is when I’ve been making a python wrapper for a web API which I can then reuse in other projects.
Let’s look at an example:
There are many web API’s which already have a python wrapper written for them, but a number of others you may want to use do not, and the documentation may just give examples of how to access the API over the webs using the command line curl – such as the postcard sending service stannp. Let’s walk through using getting your stannp account balance as an example.
The non-object oriented way
The stannp API documentation shows us the how to get your balance:
curl https://dash.stannp.com/api/v1/accounts/balance?api_key={API_KEY}
.
If we want to do this in python you can use the requests
module:
import requests
response = requests.get("https://dash.stannp.com/api/v1/accounts/balance", auth=(API_KEY, ""))
print(response)
That’s easy for one single request, but what happens when we want to send a postcard? Send a letter? Add a recipient? and after each check the balance? We’d end up having to repeat the API url, the API key as well as all the other information.
The Object Oriented way
Instead of using the requests directly it would be much better if we could simply do:
stannpaccount.get_balance()
We can do this if we create a Class (a blueprint), and then use this Class to initialize an object which we can use (stannpaccount).
In a separate file (stannp.py) we can create a Class with a method (function) for performing generic requests, and then add as many methods as our API has.
class StannpClient(): def __init__(self, api_key): ''' Sets the API key for the instance ''' self.api_key = api_key def perform_request(self, endpoint_url, payload, files, typeofr): ''' Performs a generic API request and returns the JSON response ''' if (typeofr == "get"): r = requests.get(endpoint_url, auth=(self.api_key, "")) return r.json() def get_balance(self): ''' Returns the Stannp Account balance in JSON format ''' return self.perform_request("https://dash.stannp.com/api/v1/accounts/balance", typeofr="get", files=None, payload=None)
Now we can create a new python file and import
from stannp import StannpClient
Create an instance of the StannpClient (the obejct), and initialize it with the API key:
API_KEY="XXXXXXXXXXXX"
stannpaccount=StannpClient(API_KEY)
and then call the method get_balance() using our stannpaccount object:
stannpaccount.get_balance()
If we want to send a letter, we need to setup a new method inside our class:
def send_letter(self, test, template, recipient, background, pages, pdforhtml): payload = {} payload = self.add_recipient_to_payload(recipient) if pdforhtml == "pdf": files = {'pages': ('pages.pdf', open(pages, 'rb'), 'application/pdf')} else: files = None payload['pages'] = pages payload['test'] = test if background is not None: payload['background'] = self.base64_encode_file(background) if template is not None: payload['template'] = template return self.perform_request("https://dash.stannp.com/api/v1/letters/create", payload, files=files, typeofr="post")
But we can use the same object and simple Python syntax without needing to enter the API key, url or delving into the detail of making the requested and parsing the output:
stannpaccount.send_letter(test=False, template=None, recipient=recipient, background=None, pages="test.pdf", pdforhtml="pdf")
(Of course we need to pass it a recipient and a pdf filename)
Our object is reusable within our own code, and even better the Class can be shared and imported by other people (see my full stannp API wrapper on github). This makes use of the API much easier for other Python coders. I’ve benefited loads from APIs which already have a pre-made python wrappers so its nice to be able to share ones I’ve made to help out some others.
EDIT: Feb 2018
After writing this post and reviewing a project I did last year, I realised now the code was very unwieldy and basically just composed of a list of 20 or more functions. Struggling to get my head around how to refactor the code in an object oriented way using classes, I came across this very simple step by step method (from Beginning Python – From Novice to Professional, Second Edition- 2008).
1. Write down a description of your problem (what should the program do?). Underline all
the nouns, verbs, and adjectives.
2. Go through the nouns, looking for potential classes.
3. Go through the verbs, looking for potential methods.
4. Go through the adjectives, looking for potential attributes.
5. Allocate methods and attributes to your classes.
Watch out for a future post on this!
END EDIT
Although object oriented programming sounds complex at first, once you see it working it makes a lot of sense. Apart from reading the blog post above,I’d recommend just paying attention to any code you find online that you use in your own projects. See if you can spot an object, where it has been onitialised from a Class. You can then go and find where that Class (blueprint) is defined (probably in another file), and thus see what methods (functions) those objects have available to them to use.
Leave a Reply