1
00:00:05,100 --> 00:00:06,980
So in the last few videos,

2
00:00:06,980 --> 00:00:09,350
I've digressed to look at exceptions

3
00:00:09,350 --> 00:00:11,340
and exception handling in Python,

4
00:00:11,340 --> 00:00:13,910
but now it's time to get back to databases.

5
00:00:13,910 --> 00:00:15,510
Now what we're going to do is have a look at

6
00:00:15,510 --> 00:00:18,980
rolling back transactions in situations

7
00:00:18,980 --> 00:00:22,520
where it's important that all transactions are successful.

8
00:00:22,520 --> 00:00:23,420
Now if you recall,

9
00:00:23,420 --> 00:00:25,640
we discussed one example of that earlier

10
00:00:25,640 --> 00:00:28,640
and that was transferring money between bank accounts.

11
00:00:28,640 --> 00:00:29,730
In that scenario,

12
00:00:29,730 --> 00:00:32,049
we really don't wanna end up in a situation

13
00:00:32,049 --> 00:00:33,700
where one account is debited

14
00:00:33,700 --> 00:00:36,240
without the corresponding amount also being stored

15
00:00:36,240 --> 00:00:37,810
in the other account.

16
00:00:37,810 --> 00:00:41,390
So what we're going to do is use a simple account class,

17
00:00:41,390 --> 00:00:44,900
basically very similar to what we did in an earlier video,

18
00:00:44,900 --> 00:00:47,870
to see how to ensure that both transactions occur

19
00:00:47,870 --> 00:00:49,370
or neither of them do.

20
00:00:49,370 --> 00:00:50,230
Now in the process,

21
00:00:50,230 --> 00:00:52,000
we're also gonna look at a neat way

22
00:00:52,000 --> 00:00:55,360
to do the contents of our database from IntelliJ.

23
00:00:55,360 --> 00:00:56,820
So what I've done is I've created

24
00:00:56,820 --> 00:01:00,900
a new IntelliJ Python project calling it rolling back

25
00:01:00,900 --> 00:01:05,220
and I've created a new Python file called rollback.py

26
00:01:05,220 --> 00:01:08,320
and we're just gonna quickly type in the account class

27
00:01:08,320 --> 00:01:10,340
that we're gonna be working with.

28
00:01:10,340 --> 00:01:14,500
So it's gonna be class Account(object):

29
00:01:16,110 --> 00:01:20,190
and we're gonna start by defining the init method

30
00:01:21,400 --> 00:01:24,810
and that's going to have also a name: str

31
00:01:26,210 --> 00:01:28,460
and also an opening balance

32
00:01:30,660 --> 00:01:33,820
which is a float the default value 0.0

33
00:01:35,640 --> 00:01:38,570
and we're going to assign the parameter

34
00:01:38,570 --> 00:01:41,400
so self.name = name,

35
00:01:41,400 --> 00:01:44,400
self._balance = opening_balance

36
00:01:50,560 --> 00:01:53,120
and then we'll just print something to the console

37
00:01:53,120 --> 00:01:57,280
Account created for two curly braces dot and a space

38
00:01:59,490 --> 00:02:01,720
and it's gonna be .format

39
00:02:01,720 --> 00:02:03,720
and then we do self.name

40
00:02:06,350 --> 00:02:09,009
and end equals two single quotes

41
00:02:10,150 --> 00:02:11,980
then self.show_balance

42
00:02:13,940 --> 00:02:17,500
which we obviously need to write.

43
00:02:17,500 --> 00:02:19,700
All right, next we're going to start off with our

44
00:02:19,700 --> 00:02:23,770
or start with the deposit method so def deposit

45
00:02:23,770 --> 00:02:25,150
self is automatic

46
00:02:25,150 --> 00:02:28,450
and then amount which is gonna be a float.

47
00:02:28,450 --> 00:02:31,070
We can also add an annotation here for the return type

48
00:02:31,070 --> 00:02:33,450
which we've talked about

49
00:02:33,450 --> 00:02:35,300
to be a float.

50
00:02:35,300 --> 00:02:38,960
Then the code is going to be if amount > 0.0

51
00:02:41,210 --> 00:02:45,380
then we're going to do self._balance += amount

52
00:02:49,360 --> 00:02:51,260
and then we're gonna print a message as well

53
00:02:51,260 --> 00:02:55,420
two curly braces deposited.format(amount)

54
00:03:00,710 --> 00:03:01,580
and then in either case

55
00:03:01,580 --> 00:03:04,250
we're gonna return self._balance

56
00:03:05,410 --> 00:03:07,180
and that's our deposit method.

57
00:03:07,180 --> 00:03:08,760
Now the withdraw method,

58
00:03:08,760 --> 00:03:09,760
def withdraw

59
00:03:11,840 --> 00:03:13,040
it's gonna have a self obviously

60
00:03:13,040 --> 00:03:16,660
and then it's going to be amount: float

61
00:03:16,660 --> 00:03:19,140
and another annotation for this for the return type

62
00:03:19,140 --> 00:03:21,470
which is going to be a float

63
00:03:22,460 --> 00:03:24,180
and then the code is going to be

64
00:03:24,180 --> 00:03:27,340
if 0 < amount <= to self._balance

65
00:03:32,070 --> 00:03:35,740
and we wanna do self._balance -= amount

66
00:03:38,560 --> 00:03:40,510
then print something to the console

67
00:03:40,510 --> 00:03:44,680
so print two curly braces withdrawn.format(amount)

68
00:03:51,640 --> 00:03:52,720
return amount

69
00:03:54,590 --> 00:03:55,420
else:

70
00:03:56,520 --> 00:03:59,520
we're going to print a message basically saying

71
00:03:59,520 --> 00:04:01,130
the amount must be greater than zero

72
00:04:01,130 --> 00:04:02,630
no more than your account balance

73
00:04:02,630 --> 00:04:05,880
so the amount must be greater than zero

74
00:04:08,180 --> 00:04:11,260
and no more than your account balance

75
00:04:14,600 --> 00:04:15,430
return 0.0

76
00:04:17,440 --> 00:04:20,870
and lastly we want to define the show balance method

77
00:04:20,870 --> 00:04:24,350
that we're calling upon line seven up here

78
00:04:24,350 --> 00:04:27,520
so we need to define that show_balance

79
00:04:29,800 --> 00:04:30,950
and the code for that is going to be

80
00:04:30,950 --> 00:04:32,950
print Balance on account

81
00:04:37,320 --> 00:04:39,550
curly braces, left to right curly braces,

82
00:04:39,550 --> 00:04:42,720
is and another set of curly braces left to right

83
00:04:42,720 --> 00:04:46,890
.format(self.name, self._balance)

84
00:04:52,040 --> 00:04:54,590
okay so there's our account class.

85
00:04:54,590 --> 00:04:55,430
As I mentioned,

86
00:04:55,430 --> 00:04:58,870
I've added annotations for the return values,

87
00:04:58,870 --> 00:05:00,270
but I also added annotations,

88
00:05:00,270 --> 00:05:02,190
you probably noticed as I was typing it,

89
00:05:02,190 --> 00:05:04,670
for the parameters as well.

90
00:05:04,670 --> 00:05:07,090
And where this differs,

91
00:05:07,090 --> 00:05:10,100
this class differs from our earlier attempt

92
00:05:10,100 --> 00:05:13,240
is both the deposit and withdraw methods

93
00:05:13,240 --> 00:05:15,620
now also return a value but other than that,

94
00:05:15,620 --> 00:05:17,220
it's very basic.

95
00:05:17,220 --> 00:05:20,110
It's pretty much the same code that we've seen previously.

96
00:05:20,110 --> 00:05:21,920
Now just to test this out,

97
00:05:21,920 --> 00:05:23,780
let's write a bit of code to do just that.

98
00:05:23,780 --> 00:05:27,860
So if __name__ is equal to and in quotes __main__

99
00:05:35,890 --> 00:05:40,060
now we're gonna put john = Account("John")

100
00:05:41,820 --> 00:05:45,160
and john.deposit(10.10)

101
00:05:47,500 --> 00:05:50,250
and john.deposit another 10 cents

102
00:05:53,540 --> 00:05:55,960
john.deposit another 10 cents

103
00:05:58,690 --> 00:06:00,860
john.deposit 30 more cents

104
00:06:03,150 --> 00:06:07,030
and then john.withdraw(0)

105
00:06:07,030 --> 00:06:08,860
and john.show_balance.

106
00:06:11,720 --> 00:06:13,320
So before I run this programme,

107
00:06:13,320 --> 00:06:16,790
we're gonna be depositing a total of $10

108
00:06:16,790 --> 00:06:21,490
and that actually should have been a withdrawal.

109
00:06:21,490 --> 00:06:24,060
So we're depositing a total of $10.30,

110
00:06:24,060 --> 00:06:26,070
$10.10 plus another 20

111
00:06:26,070 --> 00:06:28,830
then we're withdrawing 30 cents or pennies

112
00:06:28,830 --> 00:06:30,980
or whatever you like to call it.

113
00:06:30,980 --> 00:06:32,480
So if we run this,

114
00:06:34,510 --> 00:06:38,010
and I'm just putting this down the bottom,

115
00:06:39,590 --> 00:06:40,430
well what's going on here?

116
00:06:40,430 --> 00:06:42,800
So we got the account must be greater than zero

117
00:06:42,800 --> 00:06:43,880
no more than your account balance

118
00:06:43,880 --> 00:06:46,130
so it seemingly has worked,

119
00:06:46,980 --> 00:06:51,650
but at the moment the balance on account John is $9.999999

120
00:06:51,650 --> 00:06:53,720
so obviously that really should have been,

121
00:06:53,720 --> 00:06:57,550
the balance remaining should have been $10.

122
00:06:57,550 --> 00:06:59,900
So we're using floating point numbers here

123
00:06:59,900 --> 00:07:02,690
and in just about every computer language,

124
00:07:02,690 --> 00:07:05,970
these floating point numbers are subject to rounding errors

125
00:07:05,970 --> 00:07:08,860
when converting between binary and decimal.

126
00:07:08,860 --> 00:07:10,540
Now integer values can be converted

127
00:07:10,540 --> 00:07:13,560
between any two number systems with complete accuracy,

128
00:07:13,560 --> 00:07:15,880
but as soon as you introduce fractions,

129
00:07:15,880 --> 00:07:18,170
you'll often get rounding errors.

130
00:07:18,170 --> 00:07:20,250
Now you're probably familiar with pi

131
00:07:20,250 --> 00:07:21,890
and the fact that it can't be represented

132
00:07:21,890 --> 00:07:23,830
exactly in decimal.

133
00:07:23,830 --> 00:07:26,780
Now other fractions such as 1/3

134
00:07:26,780 --> 00:07:29,800
also can't be represented accurately in decimal

135
00:07:29,800 --> 00:07:32,800
so it comes out as 0.3333 recurring.

136
00:07:33,700 --> 00:07:38,330
Now when 1/10 or 0.1 in decimal is represented in binary,

137
00:07:38,330 --> 00:07:41,470
that also has the same issue with recurring,

138
00:07:41,470 --> 00:07:43,020
that also recurs.

139
00:07:43,020 --> 00:07:43,860
So in other words,

140
00:07:43,860 --> 00:07:46,340
we lose some accuracy every time we use 0.1

141
00:07:46,340 --> 00:07:49,000
in our example on screen

142
00:07:49,000 --> 00:07:53,300
and 0.3 also recurs in binary as would 0.4,

143
00:07:53,300 --> 00:07:58,140
0.5 is 1/2 which can be represented exactly in binary.

144
00:07:58,140 --> 00:08:01,600
Now Richard Pryor's character in the film Superman 3

145
00:08:01,600 --> 00:08:04,550
takes advantage of this to make a small fortune

146
00:08:04,550 --> 00:08:07,000
by creaming up the small fractions of a cent

147
00:08:07,000 --> 00:08:09,770
for millions of transactions but in the real world,

148
00:08:09,770 --> 00:08:13,940
our answer here of 9.99 is obviously not satisfactory.

149
00:08:14,780 --> 00:08:17,990
So what can we actually do about this to solve the problem?

150
00:08:17,990 --> 00:08:20,930
Well, one solution is to use the decimal class

151
00:08:20,930 --> 00:08:22,590
that comes with Python.

152
00:08:22,590 --> 00:08:24,640
Now I'm gonna not cover that right now.

153
00:08:24,640 --> 00:08:25,950
If there's sufficient demand,

154
00:08:25,950 --> 00:08:28,960
then it could be a good topic for a future video.

155
00:08:28,960 --> 00:08:32,110
But what I will do is show an equivalent version

156
00:08:32,110 --> 00:08:34,539
of this programme on the screen for a few seconds

157
00:08:34,539 --> 00:08:37,240
just so you can get an idea for how it's used.

158
00:08:37,240 --> 00:08:40,900
So I'm gonna create a new Python file called rollback2

159
00:08:40,900 --> 00:08:43,460
and paste the code in there just so you've got it

160
00:08:43,460 --> 00:08:44,640
and you can also refer to that

161
00:08:44,640 --> 00:08:48,750
by downloading the source code for this video.

162
00:08:48,750 --> 00:08:52,090
So I'm gonna create a new file rollback2

163
00:08:55,660 --> 00:08:59,020
and I'll just grab that and paste that in.

164
00:08:59,020 --> 00:09:02,390
Okay so there's the code there.

165
00:09:02,390 --> 00:09:05,540
So essentially the main programme still uses float values,

166
00:09:05,540 --> 00:09:09,010
but the accounts class converts them to decimal objects

167
00:09:09,010 --> 00:09:11,250
and you can see that here on line nine,

168
00:09:11,250 --> 00:09:14,420
line 14 and also on line 21 down here.

169
00:09:15,670 --> 00:09:18,420
Now you can work entirely in decimal values,

170
00:09:18,420 --> 00:09:20,890
but the class is a bit cumbersome to use

171
00:09:20,890 --> 00:09:22,940
so personally I like this approach of allowing

172
00:09:22,940 --> 00:09:25,300
clients of the class to work in floats

173
00:09:25,300 --> 00:09:28,610
and then converting them for storage and arithmetic.

174
00:09:28,610 --> 00:09:30,130
All right so I will close that file now

175
00:09:30,130 --> 00:09:31,550
but again as I mentioned,

176
00:09:31,550 --> 00:09:33,180
it's in the source code for this video

177
00:09:33,180 --> 00:09:35,100
so you can refer to that at your leisure.

178
00:09:35,100 --> 00:09:38,300
Let's go back to rollback.py that we were working on.

179
00:09:38,300 --> 00:09:40,180
So the other thing we can do

180
00:09:40,180 --> 00:09:42,930
is work entirely with integer values.

181
00:09:42,930 --> 00:09:43,790
Now as I've said,

182
00:09:43,790 --> 00:09:46,780
integers can be stored exactly in binary

183
00:09:46,780 --> 00:09:48,590
so we won't get any rounding errors

184
00:09:48,590 --> 00:09:51,910
if we perform all our arithmetic on ints.

185
00:09:51,910 --> 00:09:53,900
So when we need to display values,

186
00:09:53,900 --> 00:09:57,820
we divide by 100 so that the programme shows dollars and cents

187
00:09:57,820 --> 00:10:00,180
or pounds and pennies or whatever currency units

188
00:10:00,180 --> 00:10:01,940
that you're actually dealing with.

189
00:10:01,940 --> 00:10:03,880
And if the programme receives input,

190
00:10:03,880 --> 00:10:07,500
we need to multiply by 100 to convert to an integer.

191
00:10:07,500 --> 00:10:09,990
So basically we're working in cents or pennies

192
00:10:09,990 --> 00:10:12,390
rather than dollars or pounds.

193
00:10:12,390 --> 00:10:13,260
So what we need to do now

194
00:10:13,260 --> 00:10:16,300
is make some changes to our source code

195
00:10:16,300 --> 00:10:18,800
to replace that with integers.

196
00:10:19,730 --> 00:10:22,180
We're gonna start up here on line three.

197
00:10:22,180 --> 00:10:25,440
We're going to put int = 0

198
00:10:25,440 --> 00:10:28,230
no decimal anymore so just int = 0

199
00:10:28,230 --> 00:10:32,260
and for the deposit method, amount is going to be an int.

200
00:10:32,260 --> 00:10:35,290
We're also going to still return a float though.

201
00:10:35,290 --> 00:10:36,590
And for printing out,

202
00:10:36,590 --> 00:10:39,010
we're gonna use some formatting for printing out now.

203
00:10:39,010 --> 00:10:41,480
So within the curly braces,

204
00:10:41,480 --> 00:10:44,730
we're gonna put :.2f two decimal points

205
00:10:46,560 --> 00:10:49,210
and we're gonna put amount format is going to be

206
00:10:49,210 --> 00:10:51,210
amount / 100.

207
00:10:53,450 --> 00:10:56,620
For the withdrawal method, we need to convert that.

208
00:10:56,620 --> 00:10:58,180
The input's gonna be an int.

209
00:10:58,180 --> 00:11:00,310
We're still gonna return a float.

210
00:11:00,310 --> 00:11:01,600
In terms of formatting,

211
00:11:01,600 --> 00:11:04,120
exactly the same as we've done for the deposit method,

212
00:11:04,120 --> 00:11:06,450
:.2f within the curly braces

213
00:11:07,820 --> 00:11:11,980
and formatting it's gonna be amount / 100

214
00:11:13,090 --> 00:11:17,640
and then I'm also gonna return amount / 100

215
00:11:17,640 --> 00:11:21,800
and of course we also need to return self._balance / 100

216
00:11:23,890 --> 00:11:26,740
to convert that back to a float as well.

217
00:11:26,740 --> 00:11:30,270
And show balance, we need to make a change to that,

218
00:11:30,270 --> 00:11:32,750
so the second set of curly braces in the print line

219
00:11:32,750 --> 00:11:36,510
is gonna have the same formatting :.2f

220
00:11:36,510 --> 00:11:38,920
and the balance we're gonna do the same thing there

221
00:11:38,920 --> 00:11:41,420
self._balance / 100

222
00:11:42,790 --> 00:11:44,620
and in terms of the deposit function,

223
00:11:44,620 --> 00:11:47,710
we're not going to use decimal points anymore

224
00:11:47,710 --> 00:11:49,720
so we're using whole numbers, integers,

225
00:11:49,720 --> 00:11:51,630
so it's gonna be 10.10,

226
00:11:52,940 --> 00:11:55,270
this is gonna be 10, 10, 30.

227
00:11:57,090 --> 00:11:59,990
So basically I changed all the float parameters to int

228
00:11:59,990 --> 00:12:02,060
and divided the values by 100

229
00:12:02,060 --> 00:12:03,890
before returning or printing them.

230
00:12:03,890 --> 00:12:05,860
And you saw me specify

231
00:12:05,860 --> 00:12:09,440
the format of :.2f in the replacement fields

232
00:12:09,440 --> 00:12:10,600
so that the amounts printing

233
00:12:10,600 --> 00:12:13,410
is floating them with two decimal places.

234
00:12:13,410 --> 00:12:15,240
So if we run this now,

235
00:12:17,070 --> 00:12:19,520
you could see we're now getting the correct formatting

236
00:12:19,520 --> 00:12:20,640
for all our numbers

237
00:12:20,640 --> 00:12:23,300
and also the balance returned now

238
00:12:23,300 --> 00:12:26,380
is as we would expect it to be 10.00.

239
00:12:27,340 --> 00:12:29,520
All right, so I'm gonna finish the video here now.

240
00:12:29,520 --> 00:12:30,450
In the next video,

241
00:12:30,450 --> 00:12:33,570
let's start storing these account details in a database.

242
00:12:33,570 --> 00:12:35,730
See you in the next video.

