WEBVTT 1 00:00:02.018 --> 00:00:03.890 So in the last few videos, 2 00:00:03.890 --> 00:00:06.267 I've digressed to look at exceptions 3 00:00:06.267 --> 00:00:08.258 and exception handling in Python, 4 00:00:08.258 --> 00:00:10.829 but now it's time to get back to databases. 5 00:00:10.829 --> 00:00:12.426 Now what we're going to do is have a look at 6 00:00:12.426 --> 00:00:15.894 rolling back transactions in situations 7 00:00:15.894 --> 00:00:19.437 where it's important that all transactions are successful. 8 00:00:19.437 --> 00:00:20.333 Now if you recall, 9 00:00:20.333 --> 00:00:22.557 we discussed one example of that earlier 10 00:00:22.557 --> 00:00:25.557 and that was transferring money between bank accounts. 11 00:00:25.557 --> 00:00:26.647 In that scenario, 12 00:00:26.647 --> 00:00:28.967 we really don't wanna end up in a situation 13 00:00:28.967 --> 00:00:30.615 where one account is debited 14 00:00:30.615 --> 00:00:33.156 without the corresponding amount also being stored 15 00:00:33.156 --> 00:00:34.727 in the other account. 16 00:00:34.727 --> 00:00:38.306 So what we're going to do is use a simple account class, 17 00:00:38.306 --> 00:00:41.815 basically very similar to what we did in an earlier video, 18 00:00:41.815 --> 00:00:44.786 to see how to ensure that both transactions occur 19 00:00:44.786 --> 00:00:46.287 or neither of them do. 20 00:00:46.287 --> 00:00:47.144 Now in the process, 21 00:00:47.144 --> 00:00:48.914 we're also gonna look at a neat way 22 00:00:48.914 --> 00:00:52.274 to do the contents of our database from IntelliJ. 23 00:00:52.274 --> 00:00:53.733 So what I've done is I've created 24 00:00:53.733 --> 00:00:57.813 a new IntelliJ Python project calling it rolling back 25 00:00:57.813 --> 00:01:02.132 and I've created a new Python file called rollback.py 26 00:01:02.132 --> 00:01:05.232 and we're just gonna quickly type in the account class 27 00:01:05.232 --> 00:01:07.250 that we're gonna be working with. 28 00:01:07.250 --> 00:01:11.417 So it's gonna be class Account(object): 29 00:01:13.021 --> 00:01:17.104 and we're gonna start by defining the init method 30 00:01:18.312 --> 00:01:21.729 and that's going to have also a name: str 31 00:01:23.120 --> 00:01:25.370 and also an opening balance 32 00:01:27.570 --> 00:01:30.737 which is a float the default value 0.0 33 00:01:32.559 --> 00:01:35.480 and we're going to assign the parameter 34 00:01:35.480 --> 00:01:38.312 so self.name = name, 35 00:01:38.312 --> 00:01:41.312 self._balance = opening_balance 36 00:01:47.472 --> 00:01:50.032 and then we'll just print something to the console 37 00:01:50.032 --> 00:01:54.199 Account created for two curly braces dot and a space 38 00:01:56.400 --> 00:01:58.632 and it's gonna be .format 39 00:01:58.632 --> 00:02:00.632 and then we do self.name 40 00:02:03.261 --> 00:02:05.928 and end equals two single quotes 41 00:02:07.061 --> 00:02:08.894 then self.show_balance 42 00:02:10.850 --> 00:02:14.410 which we obviously need to write. 43 00:02:14.410 --> 00:02:16.619 All right, next we're going to start off with our 44 00:02:16.619 --> 00:02:20.680 or start with the deposit method so def deposit 45 00:02:20.680 --> 00:02:22.061 self is automatic 46 00:02:22.061 --> 00:02:25.360 and then amount which is gonna be a float. 47 00:02:25.360 --> 00:02:27.981 We can also add an annotation here for the return type 48 00:02:27.981 --> 00:02:30.360 which we've talked about 49 00:02:30.360 --> 00:02:32.210 to be a float. 50 00:02:32.210 --> 00:02:35.877 Then the code is going to be if amount > 0.0 51 00:02:38.129 --> 00:02:42.296 then we're going to do self._balance += amount 52 00:02:46.272 --> 00:02:48.170 and then we're gonna print a message as well 53 00:02:48.170 --> 00:02:52.337 two curly braces deposited.format(amount) 54 00:02:57.621 --> 00:02:58.499 and then in either case 55 00:02:58.499 --> 00:03:01.166 we're gonna return self._balance 56 00:03:02.329 --> 00:03:04.092 and that's our deposit method. 57 00:03:04.092 --> 00:03:05.675 Now the withdraw method, 58 00:03:05.675 --> 00:03:06.675 def withdraw 59 00:03:08.755 --> 00:03:09.955 it's gonna have a self obviously 60 00:03:09.955 --> 00:03:13.573 and then it's going to be amount: float 61 00:03:13.573 --> 00:03:16.053 and another annotation for this for the return type 62 00:03:16.053 --> 00:03:18.386 which is going to be a float 63 00:03:19.373 --> 00:03:21.091 and then the code is going to be 64 00:03:21.091 --> 00:03:24.258 if 0 < amount <= to self._balance 65 00:03:28.984 --> 00:03:32.651 and we wanna do self._balance -= amount 66 00:03:35.474 --> 00:03:37.424 then print something to the console 67 00:03:37.424 --> 00:03:41.591 so print two curly braces withdrawn.format(amount) 68 00:03:48.553 --> 00:03:49.636 return amount 69 00:03:51.504 --> 00:03:52.337 else: 70 00:03:53.435 --> 00:03:56.435 we're going to print a message basically saying 71 00:03:56.435 --> 00:03:58.044 the amount must be greater than zero 72 00:03:58.044 --> 00:03:59.544 no more than your account balance 73 00:03:59.544 --> 00:04:02.794 so the amount must be greater than zero 74 00:04:05.090 --> 00:04:08.173 and no more than your account balance 75 00:04:11.513 --> 00:04:12.346 return 0.0 76 00:04:14.352 --> 00:04:17.783 and lastly we want to define the show balance method 77 00:04:17.783 --> 00:04:21.263 that we're calling upon line seven up here 78 00:04:21.263 --> 00:04:24.430 so we need to define that show_balance 79 00:04:26.713 --> 00:04:27.860 and the code for that is going to be 80 00:04:27.860 --> 00:04:29.860 print Balance on account 81 00:04:34.239 --> 00:04:36.468 curly braces, left to right curly braces, 82 00:04:36.468 --> 00:04:39.639 is and another set of curly braces left to right 83 00:04:39.639 --> 00:04:43.806 .format(self.name, self._balance) 84 00:04:48.959 --> 00:04:51.508 okay so there's our account class. 85 00:04:51.508 --> 00:04:52.341 As I mentioned, 86 00:04:52.341 --> 00:04:55.788 I've added annotations for the return values, 87 00:04:55.788 --> 00:04:57.188 but I also added annotations, 88 00:04:57.188 --> 00:04:59.108 you probably noticed as I was typing it, 89 00:04:59.108 --> 00:05:01.588 for the parameters as well. 90 00:05:01.588 --> 00:05:04.009 And where this differs, 91 00:05:04.009 --> 00:05:07.010 this class differs from our earlier attempt 92 00:05:07.010 --> 00:05:10.159 is both the deposit and withdraw methods 93 00:05:10.159 --> 00:05:12.538 now also return a value but other than that, 94 00:05:12.538 --> 00:05:14.130 it's very basic. 95 00:05:14.130 --> 00:05:17.028 It's pretty much the same code that we've seen previously. 96 00:05:17.028 --> 00:05:18.838 Now just to test this out, 97 00:05:18.838 --> 00:05:20.690 let's write a bit of code to do just that. 98 00:05:20.690 --> 00:05:24.773 So if __name__ is equal to and in quotes __main__ 99 00:05:32.807 --> 00:05:36.974 now we're gonna put john = Account("John") 100 00:05:38.738 --> 00:05:42.071 and john.deposit(10.10) 101 00:05:44.418 --> 00:05:47.168 and john.deposit another 10 cents 102 00:05:50.458 --> 00:05:52.875 john.deposit another 10 cents 103 00:05:55.607 --> 00:05:57.774 john.deposit 30 more cents 104 00:06:00.066 --> 00:06:03.940 and then john.withdraw(0) 105 00:06:03.940 --> 00:06:05.773 and john.show_balance. 106 00:06:08.638 --> 00:06:10.236 So before I run this programme, 107 00:06:10.236 --> 00:06:13.708 we're gonna be depositing a total of $10 108 00:06:13.708 --> 00:06:18.409 and that actually should have been a withdrawal. 109 00:06:18.409 --> 00:06:20.979 So we're depositing a total of $10.30, 110 00:06:20.979 --> 00:06:22.988 $10.10 plus another 20 111 00:06:22.988 --> 00:06:25.746 then we're withdrawing 30 cents or pennies 112 00:06:25.746 --> 00:06:27.897 or whatever you like to call it. 113 00:06:27.897 --> 00:06:29.397 So if we run this, 114 00:06:31.420 --> 00:06:34.920 and I'm just putting this down the bottom, 115 00:06:36.500 --> 00:06:37.345 well what's going on here? 116 00:06:37.345 --> 00:06:39.716 So we got the account must be greater than zero 117 00:06:39.716 --> 00:06:40.796 no more than your account balance 118 00:06:40.796 --> 00:06:43.046 so it seemingly has worked, 119 00:06:43.897 --> 00:06:48.566 but at the moment the balance on account John is $9.999999 120 00:06:48.566 --> 00:06:50.635 so obviously that really should have been, 121 00:06:50.635 --> 00:06:54.466 the balance remaining should have been $10. 122 00:06:54.466 --> 00:06:56.817 So we're using floating point numbers here 123 00:06:56.817 --> 00:06:59.606 and in just about every computer language, 124 00:06:59.606 --> 00:07:02.886 these floating point numbers are subject to rounding errors 125 00:07:02.886 --> 00:07:05.777 when converting between binary and decimal. 126 00:07:05.777 --> 00:07:07.457 Now integer values can be converted 127 00:07:07.457 --> 00:07:10.476 between any two number systems with complete accuracy, 128 00:07:10.476 --> 00:07:12.795 but as soon as you introduce fractions, 129 00:07:12.795 --> 00:07:15.086 you'll often get rounding errors. 130 00:07:15.086 --> 00:07:17.166 Now you're probably familiar with pi 131 00:07:17.166 --> 00:07:18.804 and the fact that it can't be represented 132 00:07:18.804 --> 00:07:20.747 exactly in decimal. 133 00:07:20.747 --> 00:07:23.697 Now other fractions such as 1/3 134 00:07:23.697 --> 00:07:26.715 also can't be represented accurately in decimal 135 00:07:26.715 --> 00:07:29.715 so it comes out as 0.3333 recurring. 136 00:07:30.617 --> 00:07:35.246 Now when 1/10 or 0.1 in decimal is represented in binary, 137 00:07:35.246 --> 00:07:38.388 that also has the same issue with recurring, 138 00:07:38.388 --> 00:07:39.937 that also recurs. 139 00:07:39.937 --> 00:07:40.770 So in other words, 140 00:07:40.770 --> 00:07:43.257 we lose some accuracy every time we use 0.1 141 00:07:43.257 --> 00:07:45.918 in our example on screen 142 00:07:45.918 --> 00:07:50.217 and 0.3 also recurs in binary as would 0.4, 143 00:07:50.217 --> 00:07:55.057 0.5 is 1/2 which can be represented exactly in binary. 144 00:07:55.057 --> 00:07:58.518 Now Richard Pryor's character in the film Superman 3 145 00:07:58.518 --> 00:08:01.468 takes advantage of this to make a small fortune 146 00:08:01.468 --> 00:08:03.918 by creaming up the small fractions of a cent 147 00:08:03.918 --> 00:08:06.689 for millions of transactions but in the real world, 148 00:08:06.689 --> 00:08:10.856 our answer here of 9.99 is obviously not satisfactory. 149 00:08:11.697 --> 00:08:14.908 So what can we actually do about this to solve the problem? 150 00:08:14.908 --> 00:08:17.846 Well, one solution is to use the decimal class 151 00:08:17.846 --> 00:08:19.505 that comes with Python. 152 00:08:19.505 --> 00:08:21.556 Now I'm gonna not cover that right now. 153 00:08:21.556 --> 00:08:22.863 If there's sufficient demand, 154 00:08:22.863 --> 00:08:25.874 then it could be a good topic for a future video. 155 00:08:25.874 --> 00:08:29.023 But what I will do is show an equivalent version 156 00:08:29.023 --> 00:08:31.450 of this programme on the screen for a few seconds 157 00:08:31.450 --> 00:08:34.152 just so you can get an idea for how it's used. 158 00:08:34.152 --> 00:08:37.810 So I'm gonna create a new Python file called rollback2 159 00:08:37.810 --> 00:08:40.370 and paste the code in there just so you've got it 160 00:08:40.370 --> 00:08:41.550 and you can also refer to that 161 00:08:41.550 --> 00:08:45.669 by downloading the source code for this video. 162 00:08:45.669 --> 00:08:49.002 So I'm gonna create a new file rollback2 163 00:08:52.578 --> 00:08:55.938 and I'll just grab that and paste that in. 164 00:08:55.938 --> 00:08:59.309 Okay so there's the code there. 165 00:08:59.309 --> 00:09:02.458 So essentially the main programme still uses float values, 166 00:09:02.458 --> 00:09:05.920 but the accounts class converts them to decimal objects 167 00:09:05.920 --> 00:09:08.169 and you can see that here on line nine, 168 00:09:08.169 --> 00:09:11.336 line 14 and also on line 21 down here. 169 00:09:12.589 --> 00:09:15.330 Now you can work entirely in decimal values, 170 00:09:15.330 --> 00:09:17.809 but the class is a bit cumbersome to use 171 00:09:17.809 --> 00:09:19.850 so personally I like this approach of allowing 172 00:09:19.850 --> 00:09:22.210 clients of the class to work in floats 173 00:09:22.210 --> 00:09:25.520 and then converting them for storage and arithmetic. 174 00:09:25.520 --> 00:09:27.040 All right so I will close that file now 175 00:09:27.040 --> 00:09:28.468 but again as I mentioned, 176 00:09:28.468 --> 00:09:30.090 it's in the source code for this video 177 00:09:30.090 --> 00:09:32.018 so you can refer to that at your leisure. 178 00:09:32.018 --> 00:09:35.218 Let's go back to rollback.py that we were working on. 179 00:09:35.218 --> 00:09:37.090 So the other thing we can do 180 00:09:37.090 --> 00:09:39.840 is work entirely with integer values. 181 00:09:39.840 --> 00:09:40.709 Now as I've said, 182 00:09:40.709 --> 00:09:43.690 integers can be stored exactly in binary 183 00:09:43.690 --> 00:09:45.508 so we won't get any rounding errors 184 00:09:45.508 --> 00:09:48.829 if we perform all our arithmetic on ints. 185 00:09:48.829 --> 00:09:50.810 So when we need to display values, 186 00:09:50.810 --> 00:09:54.738 we divide by 100 so that the programme shows dollars and cents 187 00:09:54.738 --> 00:09:57.090 or pounds and pennies or whatever currency units 188 00:09:57.090 --> 00:09:58.858 that you're actually dealing with. 189 00:09:58.858 --> 00:10:00.799 And if the programme receives input, 190 00:10:00.799 --> 00:10:04.418 we need to multiply by 100 to convert to an integer. 191 00:10:04.418 --> 00:10:06.909 So basically we're working in cents or pennies 192 00:10:06.909 --> 00:10:09.308 rather than dollars or pounds. 193 00:10:09.308 --> 00:10:10.170 So what we need to do now 194 00:10:10.170 --> 00:10:13.210 is make some changes to our source code 195 00:10:13.210 --> 00:10:15.710 to replace that with integers. 196 00:10:16.640 --> 00:10:19.090 We're gonna start up here on line three. 197 00:10:19.090 --> 00:10:22.359 We're going to put int = 0 198 00:10:22.359 --> 00:10:25.141 no decimal anymore so just int = 0 199 00:10:25.141 --> 00:10:29.170 and for the deposit method, amount is going to be an int. 200 00:10:29.170 --> 00:10:32.200 We're also going to still return a float though. 201 00:10:32.200 --> 00:10:33.501 And for printing out, 202 00:10:33.501 --> 00:10:35.929 we're gonna use some formatting for printing out now. 203 00:10:35.929 --> 00:10:38.392 So within the curly braces, 204 00:10:38.392 --> 00:10:41.642 we're gonna put :.2f two decimal points 205 00:10:43.470 --> 00:10:46.120 and we're gonna put amount format is going to be 206 00:10:46.120 --> 00:10:48.120 amount / 100. 207 00:10:50.360 --> 00:10:53.530 For the withdrawal method, we need to convert that. 208 00:10:53.530 --> 00:10:55.090 The input's gonna be an int. 209 00:10:55.090 --> 00:10:57.221 We're still gonna return a float. 210 00:10:57.221 --> 00:10:58.518 In terms of formatting, 211 00:10:58.518 --> 00:11:01.032 exactly the same as we've done for the deposit method, 212 00:11:01.032 --> 00:11:03.365 :.2f within the curly braces 213 00:11:04.730 --> 00:11:08.897 and formatting it's gonna be amount / 100 214 00:11:10.000 --> 00:11:14.552 and then I'm also gonna return amount / 100 215 00:11:14.552 --> 00:11:18.719 and of course we also need to return self._balance / 100 216 00:11:20.800 --> 00:11:23.650 to convert that back to a float as well. 217 00:11:23.650 --> 00:11:27.181 And show balance, we need to make a change to that, 218 00:11:27.181 --> 00:11:29.661 so the second set of curly braces in the print line 219 00:11:29.661 --> 00:11:33.420 is gonna have the same formatting :.2f 220 00:11:33.420 --> 00:11:35.832 and the balance we're gonna do the same thing there 221 00:11:35.832 --> 00:11:38.332 self._balance / 100 222 00:11:39.701 --> 00:11:41.533 and in terms of the deposit function, 223 00:11:41.533 --> 00:11:44.621 we're not going to use decimal points anymore 224 00:11:44.621 --> 00:11:46.632 so we're using whole numbers, integers, 225 00:11:46.632 --> 00:11:48.549 so it's gonna be 10.10, 226 00:11:49.853 --> 00:11:52.186 this is gonna be 10, 10, 30. 227 00:11:54.002 --> 00:11:56.901 So basically I changed all the float parameters to int 228 00:11:56.901 --> 00:11:58.973 and divided the values by 100 229 00:11:58.973 --> 00:12:00.802 before returning or printing them. 230 00:12:00.802 --> 00:12:02.772 And you saw me specify 231 00:12:02.772 --> 00:12:06.352 the format of :.2f in the replacement fields 232 00:12:06.352 --> 00:12:07.512 so that the amounts printing 233 00:12:07.512 --> 00:12:10.322 is floating them with two decimal places. 234 00:12:10.322 --> 00:12:12.155 So if we run this now, 235 00:12:13.984 --> 00:12:16.432 you could see we're now getting the correct formatting 236 00:12:16.432 --> 00:12:17.552 for all our numbers 237 00:12:17.552 --> 00:12:20.213 and also the balance returned now 238 00:12:20.213 --> 00:12:23.296 is as we would expect it to be 10.00. 239 00:12:24.252 --> 00:12:26.432 All right, so I'm gonna finish the video here now. 240 00:12:26.432 --> 00:12:27.362 In the next video, 241 00:12:27.362 --> 00:12:30.482 let's start storing these account details in a database. 242 00:12:30.482 --> 00:12:32.649 See you in the next video.