Solutions Encaptiolation exercises
Ex 1: Car object
1# car.py (solution)
2
3# 1. Car object
4# Create a Car class.
5# When instanciated the object should be able to take 4 attributes (Make, Model, bhp, mph).
6# They all 4 should be properties.
7
8db = {
9 "Audi": {"A3", "A4", "A6", "Q5", "Q7"},
10 "BMW": {"3 Series", "5 Series", "7 Series", "X3", "X5"},
11 "Mercedes-Benz": {"C-Class", "E-Class", "S-Class", "GLC", "GLE"},
12 "Volkswagen": {"Golf", "Passat", "Polo", "Tiguan", "Arteon"},
13 "Volvo": {"S60", "S90", "V60", "XC60", "XC90"},
14 "Toyota": {"Corolla", "Camry", "RAV4", "Prius", "Hilux"},
15 "Honda": {"Civic", "Accord", "CR-V", "Fit", "HR-V"},
16 "Ford": {"Focus", "Fiesta", "Mustang", "Escape", "Explorer"},
17 "Nissan": {"Altima", "Rogue", "Sentra", "Maxima", "Murano"},
18 "Mazda": {"Mazda3", "Mazda6", "CX-5", "CX-9", "MX-5"}
19}
20
21
22class Car:
23 def __init__(self, make, model, bhp, mph):
24 self.make = make
25 self.model = model
26 self.bhp = bhp
27 self.mph = mph
28
29 # make
30 @property
31 def make(self):
32 return self._make
33
34 @make.setter
35 def make(self, make):
36 if make not in db.keys():
37 raise ValueError('Make is not in valid list')
38 self._make = make
39
40 # model
41 @property
42 def model(self):
43 return self._model
44
45 @model.setter
46 def model(self, model):
47 if model not in db[self.make]:
48 raise ValueError(f'No model named {model} belongs to {self.make}')
49 self._model = model
50
51 # bhp
52 @property
53 def bhp(self):
54 return self._bhp
55
56 @bhp.setter
57 def bhp(self, bhp):
58 if bhp < 0:
59 raise ValueError('bhp can not be negative')
60 self._bhp = bhp
61
62 # mph
63 @property
64 def mph(self):
65 return self._mph
66
67 @mph.setter
68 def mph(self, mph):
69 if mph < 0:
70 raise ValueError('mph can not be negative')
71 self._mph = mph
72
Ex 2: Bank
1"""
22. Bank
3In the exercise from last monday with the bank, account and customer, change the code to use properties instead of the public variables.
4The 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).
5Somewhere you should change the code so that a customer only can create one account.
6The Customer class should make sure that the customer is over 18 year of age.
7
8"""
9
10class Bank:
11 def __init__(self):
12 self._accounts = [] # When bank is initialized it has the abillity to hold many accounts
13
14 @property
15 def accounts(self):
16 return self._accounts
17
18 @accounts.setter
19 def accounts(self, acc):
20 if type(acc) in [list, tuple, set]:
21 for i in acc:
22 self._has_account(i)
23 self._accounts.append(i)
24 else:
25 self._has_account(acc)
26 self._accounts.append(acc)
27
28 def _has_account(self, acc):
29 for i in self._accounts:
30 if acc.cust.name == i.cust.name:
31 raise ValueError('Customer aleready has an account!')
32 return False
33
34 def __repr__(self):
35 return str(self.__dict__)
36
37class Account:
38 def __init__(self, no, cust):
39 self.no = no
40 self.cust = cust
41
42 def __repr__(self):
43 return str(self.__dict__)
44
45
46class Customer:
47 def __init__(self, name, age):
48 self.name = name
49 self.age = age
50
51 @property
52 def age(self):
53 return self._age
54
55 @age.setter
56 def age(self, age):
57 if age < 18:
58 raise ValueError('You must be 18 or above to create an account')
59
60 self._age = age # create a variable with the name _age
61
62 def __repr__(self):
63 return str(self.__dict__)
Ex 3: Machine -> printer
1# printer.py (solution)
2
3"""
4 3. Machine -> printer
5 Create a Machine class that takes care of powering on and off a the machine.
6 Create a printer class that is a subclass of the Machine super class.
7 The printer should be able to print to console.
8 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 and load new paper in the tray if empty.
9"""
10
11class Machine:
12 """ takes care of turning on and off """
13
14 def __init__(self):
15 self._is_on = False # one _ = protected (to be used only in subclasses)
16
17 def power(self):
18 self._is_on = not self._is_on
19
20class Printer(Machine):
21 def __init__(self):
22 Machine.__init__(self)
23 self._pt = Papertray()
24
25 def print(self, text):
26 if self._pt.paper == 0:
27 print('Papertray is empty')
28 else:
29 if self._is_on:
30 print(text)
31 self._pt.paper = self._pt.paper - 1
32 else:
33 print('Printer is off')
34
35 @property
36 def load(self):
37 return self._pt.paper
38
39 @load.setter
40 def load(self, no):
41 self._pt.paper = no
42
43class Papertray:
44 def __init__(self):
45 self.paper = 2
46
47 @property
48 def paper(self):
49 return self._paper
50
51 @paper.setter
52 def paper(self, paper):
53 self._paper = paper
54
55
56
57
58
59
60
61
62
Ex 4: Rectangle
1# Your code should include:
2# A class called Rectangle
3# width and height attributes with property decorators
4# A get_area method that calculates the area of the rectangle
5# Appropriate error handling for non-positive width and height values
6
7class Rectangle:
8 def __init__(self, width, height):
9 self.width = width
10 self.height = height
11
12 @property
13 def width(self):
14 return self._width
15
16 @width.setter
17 def width(self, width):
18 if width < 0:
19 raise ValueError('Witdh can not be negative')
20 self._width = width
21
22 @property
23 def height(self):
24 return self._height
25
26 @height.setter
27 def height(self, height):
28 if height < 0:
29 raise ValueError('Height can not be negative')
30 self._height = height
31
32 @property
33 def area(self):
34 return (self.height + self.width)**2
Ex 5: Color converter
1class Color:
2 def __init__(self, r, g, b):
3 self.r = r
4 self.g = g
5 self.b = b
6
7 @property
8 def hex(self):
9 return f'#{hex(self.r)[2:]}{hex(self.g)[2:]}{hex(self.b)[2:]}'
10