Session 8 - Encapsulation
In Python, it is generally considered best practice to make all attributes public unless there is a specific need to make them private. This is in contrast to languages like Java, where private attributes and accompanying getters and setters are the norm.
When we need to encapsulate data (e.g if we need to validate the data) we can use different methods. We will look at one approaches: propertie.
A property is a build in decorator function and is using the syntax @property
. Just like you learned in the session about decorator functions. Descriptor classes is a class with the __get__(), __set__() and __deleter__()
methods implemened.
This approach is considered best practice or ‘Pythonic’ and this is what we will look at in todays session.
from wikipedia: A property, in some object-oriented programming languages, is a special sort of class member, intermediate in functionality between a field (or data member) and a method. The syntax for reading and writing of properties is like for fields, but property reads and writes are (usually) translated to ‘getter’ and ‘setter’ method calls. The field-like syntax is easier to read and write than many method calls, yet the interposition of method calls “under the hood” allows for data validation, active updating, or implementation of what may be called “read-only fields”.
Learning goals
After this week you will be able to:
Understand the pythonic approach to encapsulation.
Use public and non-public attributes in your code
Work with properties to use encapsulation.
And explain the pros and cons of properties and public attributes compared to Java´s private attributes with getters and setters.
Materials
Exercises
Encaptiolation & Propeties exercises
All following exercises should be done by using Properties when needed (Ex 1 should have also properties every where even though its not needed). The focus should be on encapsulation.
Ex 1: Car object
Create a Car class. When instanciated the object should be able to take 4 attributes (Make, Model, bhp, mph). They all 4 should be properties. (Even though this is not nessary here, you should create properties in order just to try it out).
Ex 2: Bank
In the exercise from last monday with the bank, account and customer, change the code to use properties instead of the public variables.
1 2 3 4 5 6 7 8 9 10 11 12 | class Bank:
def __init__(self):
self.accounts = []
class Account:
def __init__(self, no, cust):
self.no = no
self.cust = cust
class Customer:
def __init__(self, name):
self.name = name
|
The bank class should futher be change into not taking any accounts as parameters at initialization.
The accouts should be added afterwards, eithers as a single account one at a time, or as a collection of accounts (many at the sametime).
Somewhere you should change the code so that a customer only can create one account.
The Customer class should make sure that the customer is over 18 year of age.
Ex 2a: Debugging
What is wrong with this code?
1 2 3 4 5 6 7 8 9 10 11 12 | class C:
def __init__(self, value):
self._x = value
@property
def x(self):
return self._x
@x.setter
def x(self, value):
if type(value) not in (int, ):
self._x = value
|
Ex 3: Machine -> printer
Create a Machine class that takes care of powering on and off a the machine.
Create a printer class that is a subclass of the Machine super class.
The printer should be able to print to console.
The printer should have a papertray, which should be in its own class. The papertray class should keep track of the paper, it should have the abillity to use paper and load new paper in the tray if empty.
Ex 4: Rectangle
Write a Python class called Rectangle with width and height attributes. Add a get_area method which calculates the area of the rectangle. Then add property decorators to the width and height attributes, so that they can be accessed and set like regular public attributes, but also validate that the input values are positive. If a non-positive value is assigned to either width or height, raise a ValueError with an appropriate error message.
Your code should include:
A class called Rectangle
width and height attributes with property decorators
A get_area method that calculates the area of the rectangle
Appropriate error handling for non-positive width and height values