OOP in Python - Part 1
OOP in Python - Part 1
Join the DZone community and get the full member experience.Join For Free
DevOps involves integrating development, testing, deployment and release cycles into a collaborative process. Learn more about the 4 steps to an effective DevSecOps infrastructure.
What is OOP (Object Oriented Programming) ?
Object Oriented Programming is a programming paradigm which creates “objects” during the phase of programming, by this trying to model the entities from the problem which is need to be solved.
The “objects” contain data as form of fields (also called attributes) and have operations defined (called methods). The “objects” have a type definitions, these are called classes in the programming terminology. An “object” is an instance of a class.
There are 3 key things to talk about when we discuss OOP (also called three pillars of OOP):
- Encapsulation – means locking into one unit the data and the methods which interact with the data within the class. This is useful because the internal structure of a model can only be changed through the methods which it exposes, other entities (objects) cannot modify the internal state of another.
- Inheritance – usually when we build models about real world problems we end up with large object hierarchies. These models (classes) have relationships among each other. The “is a” relationship in the model hierarchy is implemented using inheritance within OOP, this means features existing in one model (or object) will also exist in the derived one.
Example: Lets assume you want to build your own web shop and you want to sell gadgets. Gadgets have properties, like battery capacity, weight, amount of memory, operating system and so on. If you want to sell a Tablet in your web shop, you can say,the Tablet is a Gadget, and when implementing these in code you can use inheritance to pass all the attributes and functionalities of the Gadget class to the Tablet class.
- Polymorphism – is called the possibility of an object to behave in a different way based on the subtype it has. Polymorphism is related to inheritance.
Example: Lets assume you want to sell smart watches too in your web shop. A Smart Watch is a Gadget. All the gadgets can be restarted, this can be an operation (or method) of a gadget. Since both (Tablet and Smart Watch) inherit from Gadget (they have an is a relationship) they also inherit the restart operation, BUT the restart operation is different on a Smart Watch then in case of a Tablet. So, if we restart both the Smart Watch and the Tablet, we used the common operation (restart) but each of the models executes the operation in its own way, basically, looking at it from a more abstract level we have 2 Gadgets which have a polymorphic behavior (based on their type) when executing the restart operation.
What is Python ?
Python is a dynamic typed, general purpose, high-level programming language. It was designed and developed by Guido van Rossum and released to public in 1991. Nowadays it is very popular and is mostly used in web development along with widespread web frameworks like django, flask, bottlepy and pyramid. The name of the language originates from the Monty Python’s Flying Circus which Guido was big fan of.
Which version should I use, 2.x or 3.x ?
The 2.7.x release of Python will be officialy supported till 2020. The core development team of the language confirmed there will not be 2.8 version of the language. They will only ship security updates and bug fixes for the 2.x branch. The 3.x branch was released in 2000, it had issues in the beginning, but its very good now. The transition to the new version is hard since most of the linux distributions are still shipped with version 2.x. The main reason behind this is backward compatibility; there are a lot of applications written using branch 2.x and people do not want to break existing applications. The branch 3.x can be easily installed besides 2.x and can be used without any issue.
For a more detailed explanation about differences, pros and cons of Python 2.x and 3.x branches please read these 2 articles:
- Python.org – Should I use Python 2 or Python 3 for my development activity ?
- The Treehouse blog – Python 2 VS Python 3
Classes in Python
As mentioned above, classes are type definitions of objects. The declaration of a class in Python is done using the class keyword. There is a coding convention in python, usually a .pyfile only contains one class definition. There can be exceptions but this is a good practice to follow. Here is an example of the Gadget class which I talked about earlier:
class Gadget: weight = 100 operating_system = None battery_capacity = 2000 screen_size = 1 my_iphone = Gadget()
The Gadget class has 4 attributes (weight, battery_capacity, operating_system andscreen_size). We can create new instances of the class using the class name and parenthesis – Gadget(). If take a look at the default values of the class these do not seem to be correct if take into account an iPhone’s technical parameters. We would need a method or a function which would let us specify what are the values for the given instance of the class. The methods which help in creating a new instance of a class are called constructors. Below you can see an implementation of a constructor (__init__) in Python. The __init__ method gets invoked right after the new instance is created. The first parameter of the constructor is called self. This is another code convention. The first parameter represents the object which is newly created new creating the new instance. As you can see we set the attributes of self inside the constructor.
class Gadget: weight = 100 operating_system = None battery_capacity = 2000 screen_size = 1 def __init__(self, weight, operating_system, battery_capacity, screen_size): self.weight = weight self.operating_system = operating_system self.battery_capacity = battery_capacity self.screen_size = screen_size my_iphone = Gadget(weight = 128, operating_system="iOS", battery_capacity=2800, screen_size=4)
If we want to see what values does our new object have we can print the values:
my_iphone = Gadget(weight = 128, operating_system="iOS", battery_capacity=2800, screen_size=4) print(my_iphone.weight) print(my_iphone.operating_system) print(my_iphone.battery_capacity) print(my_iphone.screen_size)
There is one problem with this approach, we are violating the Encapsulation rule. We have direct access to the internal state of the my_iphone object, we can simply assign new values to the screen_size or operating_system attributes. The current implementation of the model allows this. We should change these by using properties and hiding the current class members from public access.
class Gadget: """A class used for modelling Gadgets in a web shop.""" __weight = 100 __operating_system = None __battery_capacity = 2000 __screen_size = 1 def __init__(self, weight, operating_system, battery_capacity, screen_size): self.__weight = weight self.__operating_system = operating_system self.__battery_capacity = battery_capacity self.__screen_size = screen_size def get_weight(self): return self.__weight def set_weight(self, weight): self.__weight = weight weight = property(get_weight, set_weight) @property def operating_system(self): return self.__operating_system @operating_system.setter def operating_system(selg, new_os): self.__operating_system = new_os
We can hide the attributes(make them private) if we declare them using __
When implementing the property for weight, I used the weight = property(get_weight, set_weight) method to create the weight property. This syntax can be easily applied to python classes where the Java-like get/set method approach was implemented in the first place and using the property(get…, set…) method we can extend the class with properties.
When implementing the property for the operating_system I used another approach, a so called annotation/decorator based. Here, first I defined the get method, but I omitted the get keyword (please note the method operating_system decorated with @property has only one parameter, self); after that I created the setter, which has the same method name (operating_system) but has 2 parameters, the value of self and the new value which needs to be set (called new_os).
>>> from Gadget import Gadget >>> my_iphone = Gadget(240,'iOS',1980,4) >>> my_iphone.weight 240 >>> my_iphone.weight = 255 >>> my_iphone.weight 255 >>> >>> >>> my_iphone.operating_system 'iOS' >>> my_iphone.operating_system = 'iOS 8.1' >>> my_iphone.operating_system 'iOS 8.1' >>>
Using the properties is fairly easy, here are some examples. Basically properties behave the same way as public members, BUT through the getters and setters we have the option to validate the newly set values (I did not make any validation in this case, but it can be done without any issue).
OOP in Python (2) will come shortly.
Published at DZone with permission of Gergo Bogdan . See the original article here.
Opinions expressed by DZone contributors are their own.