Object-Oriented Programming With Python : Encapsulation (1/3)
Justification For Learning OOP
Since 1995, I have written some form of code, but over the years my career has never taken shape with a primary focus on development. Instead in my various roles of Systems, Network, Application and Datacenter engineering & architecture, I have found excuses to let the inner code hacker in me, out. Allowing me to consistently pursue my passion for coding and automation within the scope of my daily duties. However, this approach has never allowed me to work on a development team and thus the necessity for using object oriented programming rarely has occurred.
Sure I’ve written classes and modules for re-use, but I have never had to place a tremendous amount of forethought into the design for flexibility or inflexibility of the interfaces those classes provide because I was the only one using them. This hasn’t change, but as of late, I find myself realizing my career may be ready for a change. It is likely the next step for me in my career is a full blown software development role. This is partly because of boredom and mastery in my existing field after decades of experience, but mostly because of my own career planning and the apparent industry trends.
Simply put more jobs are moving to software development, and Systems Engineering is on a steady decline due to the advent of Cloud computing, Containers and more. Due to the amazing products, platforms and tools that are now available less and less Systems Engineers are required and I would say Systems Engineers that don’t code are already obsolete, whether they realize it yet or not.
In todays world if you are or are going to be a developer, knowing how to write object oriented code is a requirement and more importantly thinking ahead about who and how your code will be used becomes paramount when designing effective software. This article is intended to help you get a better understanding of how to write object oriented programming using Python.
Procedural Programming vs. Object Oriented Programming
Procedural programming is a more antiquated paradigm for software design that can be described as:
- Code that processes data
- The data we process is stored in variables
- Then we create functions to process the data in those variables
In the object oriented programming paradigm:
- We organize data into Objects
- Functions become Methods
- And The design of these objects & methods is specified in a Class, which is essentially a blue print.
Object oriented programming is the primary software design paradigm in existence today because it provides programmers with a way to effectively organize and share code for re-use while to protecting the integrity of the existing code. To understand how this works we need to jump right into it with The Three Pillars of Object Oriented Programming.
The Three Pillars (Encapsulation, Inheritance, and Polymorphism)
Encapsulation
Encapsulation is about ensuring the safe storage of data as attributes in an instance.
Encapsulation tells us that :
- Data should only be accessed through instance methods.
- Data should always be correct based on the validation requirement set in the class methods.
- And Data should be safe from changes by external processes.
Great so what does that mean 🙂 It means we should be using ‘setter’ and ‘getter’ methods to access object attribute values. Here’s an example of a class that uses a setter and getter method (note the name setter & getter is not actually required) to set and get the variable/attribute value.
#!/usr/bin/env python class Tuxlabs(object): def setter(self, website): self.website = website def getter(self): return self.website tuxlabs = Tuxlabs() tuxlabs.setter('http://www.tuxlabs.com') print (tuxlabs.getter()) tuxlabs.setter('http://www.google.com') print (tuxlabs.getter())
The output of this code is:
➜ tuxlabs python example.py http://www.tuxlabs.com http://www.google.com ➜ tuxlabs
It’s important to recognize that encapsulation is not enforced by Python. So a programmer using a class is not required to access the data through the getter and setter methods. For example, in the class above someone could set website, without ever interacting with the defined setter and getter classes. This is called breaking encapsulation, and it’s bad form / practice for a programmer to this because the class author & maintainer can no longer validate the data that is being accessed and this can cause unforeseen problems with a program that is dependent on the class it is inheriting from. Here’s a modified example where we are breaking encapsulation.
#!/usr/bin/env python class Tuxlabs(object): def setter(self, website): if 'http' in website: self.website = website else: print 'ERROR: Unable to set website to %s.\nRequired format is: http://www.example.com' % (website) def getter(self): output = 'Website is set to: ' + str(self.website) + '\n' return output tuxlabs = Tuxlabs() website = 'http://www.tuxlabs.com' print "Attempting to set website to: \"%s\"" % (website) tuxlabs.setter(website) print (tuxlabs.getter()) website = 'http://www.google.com' print "Attempting to set website to: \"%s\"" % (website) tuxlabs.setter(website) print (tuxlabs.getter()) website = 'I should not be accessing website in the class directly!, but since I am breaking encapsulation it does still work, it\'s just naughty!' print "Attempting to set website to: \"%s\"" % (website) tuxlabs.website = website print tuxlabs.website ## Printing without the getter doh ! print "" website = 'This is not a website, so an error is thrown!' print "Attempting to set website to: \"%s\"" % (website) tuxlabs.setter(website)
Here is the output of the above example:
➜ tuxlabs python example.py Attempting to set website to: "http://www.tuxlabs.com" Website is set to: http://www.tuxlabs.com Attempting to set website to: "http://www.google.com" Website is set to: http://www.google.com Attempting to set website to: "I should not be accessing website in the class directly!, but since I am breaking encapsulation it does still work, it's just naughty!" I should not be accessing website in the class directly!, but since I am breaking encapsulation it does still work, it's just naughty! Attempting to set website to: "This is not a website, so an error is thrown!" ERROR: Unable to set website to This is not a website, so an error is thrown!. Required format is: http://www.example.com ➜ tuxlabs
A number of things have changed.
- We added a variable website to make the example more clear and easy to follow.
- We added validation to our setter() method, it now checks to make sure ‘http’ is contained in the value that we are setting for website.
- If ‘http’ is not in website the setter() method will throw an error and will not set website!
- We added some additional formatting to our getter() method so we can tell when it is being used verses when encapsulation is being broken. getter() now pre-pends any website passed with ‘Website is now set to:’
So let’s walk thru how these changes effected the program and what actually happened. First, we tried to set website to ‘http://www.tuxlabs.com’ and then we changed it to ‘http://www.google.com’. In both of these examples we followed the rules of encapsulation, setting and getting the attribute value through methods in the class. These examples are correct and set website to the value passed and outputed them with the correct formatting we implemented in getter().
Next, we tried setting website to a really long string, without using setter() ! So we did tuxlabs.website = website directly on the instance of our class ! We also circumvented using getter() and just printed in exactly the same, broken way print tuxlabs.website. Unfortunately, as previously mentioned nothing requires the programmer to use our setter and getter methods directly, and thus website is not being checked for containing ‘http’ here and so it can printed our very long string (“I should not be accessing website in the class directly!, but since I am breaking encapsulation it does still work, it\’s just naughty!”).
The last and final example, is an example of encapsulations value proposition. We try to set website to something that does not contain ‘http’ and therefore is not a website. An error is thrown and website is not set, which is exactly what we want.
Encapsulation is simple, easy to follow and powerful when your programming on or with a team of developers that are going to share code amongst each other. In these scenarios encapsulation is obviously a must promoting collaboration through protecting programmers from potentially mis-using each others code. It should be easy to see now that breaking encapsulation is bad and very poor practice because code that perfectly functions one day, could be broken the next without any changes from you, because you are violating the contract that encapsulation methods of the class provide.
This concludes our learning about encapsulation. Still to come, Inheritance, Polymorphism, and some real world examples!
Until next time…Keep learning,
Jason Riedel
Object-Oriented Programming With Python : Encapsulation (1/3) Read More »