WEBVTT 1 00:00:01.440 --> 00:00:02.357 All right so in this video, 2 00:00:02.357 --> 00:00:04.197 we're gonna look at polymorphism 3 00:00:04.197 --> 00:00:07.595 and how it's an important part of the Python philosophy. 4 00:00:07.595 --> 00:00:10.175 Now before I explain what polymorphism is, 5 00:00:10.175 --> 00:00:11.357 let's have a look at some code 6 00:00:11.357 --> 00:00:13.247 and talk about what's going on. 7 00:00:13.247 --> 00:00:15.757 So I'm still in the game project we've been working on. 8 00:00:15.757 --> 00:00:18.517 I'm gonna clear out all the code from our main programme. 9 00:00:18.517 --> 00:00:20.806 I'm just gonna copy it all, delete the lot, 10 00:00:20.806 --> 00:00:24.728 and I'm gonna start by typing in a = 3, 11 00:00:24.728 --> 00:00:27.008 b = 2 in double quotes, 12 00:00:27.008 --> 00:00:28.425 c = 1, 2, 3. 13 00:00:30.557 --> 00:00:34.747 So we've got three variables, a, b, and c. 14 00:00:34.747 --> 00:00:37.317 And I've typed x there and not c. 15 00:00:37.317 --> 00:00:38.848 So a refers to an integer, 16 00:00:38.848 --> 00:00:41.555 b to a string, and c to a topple. 17 00:00:41.555 --> 00:00:43.972 Okay so let's print them out. 18 00:00:49.204 --> 00:00:50.371 Okay let's run 19 00:00:53.432 --> 00:00:55.587 and there's no real surprises at the result 20 00:00:55.587 --> 00:00:57.467 when I run the programme. 21 00:00:57.467 --> 00:01:01.285 So what that's done is pass three total different variables 22 00:01:01.285 --> 00:01:02.834 to the print function 23 00:01:02.834 --> 00:01:05.835 and it's happily printed out a value for each one. 24 00:01:05.835 --> 00:01:08.096 So what's happening here is that each object 25 00:01:08.096 --> 00:01:11.715 is behaving in a similar way when we try to print it. 26 00:01:11.715 --> 00:01:13.165 So in addition to their behaviour 27 00:01:13.165 --> 00:01:15.305 as an int, string, or a topple, 28 00:01:15.305 --> 00:01:18.138 they also have printable behaviour. 29 00:01:19.953 --> 00:01:22.947 So a is an int and we can subtract two ints 30 00:01:22.947 --> 00:01:24.717 to work out their difference. 31 00:01:24.717 --> 00:01:28.368 B is a string and you can't subtract strings in Python 32 00:01:28.368 --> 00:01:31.077 so they are very different types of object, 33 00:01:31.077 --> 00:01:35.244 but they also share printable behaviour and in that respect, 34 00:01:36.408 --> 00:01:39.077 they behave like a different type of object, 35 00:01:39.077 --> 00:01:41.016 an object that's printable. 36 00:01:41.016 --> 00:01:44.016 Now that ability of objects to have different forms 37 00:01:44.016 --> 00:01:48.183 is called polymorphism which just really means many forms. 38 00:01:50.648 --> 00:01:52.573 Now in this particular example, 39 00:01:52.573 --> 00:01:55.248 the polymorphic behaviour of the objects 40 00:01:55.248 --> 00:01:57.987 is implemented using inheritance. 41 00:01:57.987 --> 00:02:02.128 All Python objects inherit from a base class called object, 42 00:02:02.128 --> 00:02:04.795 which defines an __str__ method. 43 00:02:07.927 --> 00:02:10.477 So polymorphism allows the print function 44 00:02:10.477 --> 00:02:12.757 to accept arguments of any type 45 00:02:12.757 --> 00:02:15.840 and it's able to then print them out. 46 00:02:17.317 --> 00:02:20.367 Now even Java programmers wouldn't be surprised at this 47 00:02:20.367 --> 00:02:23.427 because you can do the same thing in Java. 48 00:02:23.427 --> 00:02:26.347 And in fact, I'm gonna do something really strange now 49 00:02:26.347 --> 00:02:30.264 and show you some Java code in a Python course. 50 00:02:32.589 --> 00:02:35.357 So this slide shows some of the declarations 51 00:02:35.357 --> 00:02:37.440 of the Java print method. 52 00:02:38.629 --> 00:02:42.248 Now all the lines starting with asterisks are comments 53 00:02:42.248 --> 00:02:45.846 so we're interested in the lines that start public void. 54 00:02:45.846 --> 00:02:47.236 So ignore the public, 55 00:02:47.236 --> 00:02:50.208 as we're not interested in scope or visibility in Java. 56 00:02:50.208 --> 00:02:52.579 In statically typed languages like Java, 57 00:02:52.579 --> 00:02:55.348 you have to specify the type of every parameter 58 00:02:55.348 --> 00:02:58.709 and also the type of the result that methods return. 59 00:02:58.709 --> 00:03:00.635 So here, void just means that these methods 60 00:03:00.635 --> 00:03:02.468 don't return anything. 61 00:03:03.637 --> 00:03:05.597 Now the first thing to notice 62 00:03:05.597 --> 00:03:08.637 is that there are several versions of this print statement, 63 00:03:08.637 --> 00:03:12.470 each one taking a different type of parameter. 64 00:03:13.528 --> 00:03:16.477 Now Java's a statically typed language 65 00:03:16.477 --> 00:03:19.697 and that means that the type of everything is checked 66 00:03:19.697 --> 00:03:21.488 when the program's compiled. 67 00:03:21.488 --> 00:03:23.709 So if you try to pass a string 68 00:03:23.709 --> 00:03:26.048 to a method that expects an int, 69 00:03:26.048 --> 00:03:28.196 then the programme won't compile. 70 00:03:28.196 --> 00:03:29.517 Now in Python, 71 00:03:29.517 --> 00:03:32.676 the type of something is only of interest when it's used 72 00:03:32.676 --> 00:03:36.299 and that's because Python's a dynamically typed language. 73 00:03:36.299 --> 00:03:38.178 So as you saw in the previous slide, 74 00:03:38.178 --> 00:03:40.838 we've got quite a few versions of that print method here. 75 00:03:40.838 --> 00:03:45.005 In fact, as we go to the next slide, there's more. 76 00:03:46.125 --> 00:03:47.878 So in this slide we can see versions 77 00:03:47.878 --> 00:03:52.045 that accept a char, an int, a long, a float, and a double. 78 00:03:54.838 --> 00:03:57.166 And here we can see the remaining versions 79 00:03:57.166 --> 00:04:02.136 that take an array of characters, a string, and an object. 80 00:04:02.136 --> 00:04:05.438 Now all the methods call another method, write, 81 00:04:05.438 --> 00:04:06.787 to do the printing, 82 00:04:06.787 --> 00:04:08.526 but what most of them have in common 83 00:04:08.526 --> 00:04:11.496 is that they call the String class' valueOf method 84 00:04:11.496 --> 00:04:15.286 to get the string that should be printed. 85 00:04:15.286 --> 00:04:18.398 Now the char and string versions are slightly different. 86 00:04:18.398 --> 00:04:20.004 A string is already a string 87 00:04:20.004 --> 00:04:23.326 so there's no need to do anything to convert it into one. 88 00:04:23.326 --> 00:04:26.587 And an array of characters is close enough to a string 89 00:04:26.587 --> 00:04:30.427 that there's no conversion needed there either. 90 00:04:30.427 --> 00:04:33.985 But all the other methods use this String.valueOf method 91 00:04:33.985 --> 00:04:38.152 to get the string representation of the thing to be printed. 92 00:04:40.678 --> 00:04:43.686 By the way, this is what's meant by overloading methods. 93 00:04:43.686 --> 00:04:46.006 You create different versions of the method 94 00:04:46.006 --> 00:04:47.875 that take different parameters 95 00:04:47.875 --> 00:04:50.864 and the compiler decides which one to use 96 00:04:50.864 --> 00:04:54.886 based on the number and type of the parameters passed to it. 97 00:04:54.886 --> 00:04:59.043 Now overloading isn't possible in Python and isn't necessary 98 00:04:59.043 --> 00:05:01.235 and we've seen how to get the same effect 99 00:05:01.235 --> 00:05:03.286 as having different numbers of parameters, 100 00:05:03.286 --> 00:05:06.824 using named parameters with default values. 101 00:05:06.824 --> 00:05:08.313 We automatically get the ability 102 00:05:08.313 --> 00:05:10.483 to pass parameters of different types 103 00:05:10.483 --> 00:05:13.463 because Python doesn't check the type of variables 104 00:05:13.463 --> 00:05:15.630 when it compiles the code. 105 00:05:17.544 --> 00:05:20.496 So in a statically typed language like Java, 106 00:05:20.496 --> 00:05:22.182 if you want to print a string 107 00:05:22.182 --> 00:05:25.136 then the compiler calls a version of the print method 108 00:05:25.136 --> 00:05:26.966 that can print strings. 109 00:05:26.966 --> 00:05:28.576 And if you wanna print an int 110 00:05:28.576 --> 00:05:31.944 then the compiler calls the version that deals with int. 111 00:05:31.944 --> 00:05:35.195 And similarly, with the last method on the slide, 112 00:05:35.195 --> 00:05:36.861 to print an object, 113 00:05:36.861 --> 00:05:40.075 the compiler calls this version that accepts a parameter 114 00:05:40.075 --> 00:05:41.846 whose type is Object. 115 00:05:41.846 --> 00:05:43.475 Now where it gets interesting 116 00:05:43.475 --> 00:05:46.495 and also relevant to us as Python programmers 117 00:05:46.495 --> 00:05:49.107 is what happens in the valueOf method 118 00:05:49.107 --> 00:05:52.274 so let's actually have a look at that. 119 00:05:53.964 --> 00:05:56.547 Once again, the methods have been overloaded 120 00:05:56.547 --> 00:05:59.336 to cope with the various types of the parameters 121 00:05:59.336 --> 00:06:00.919 that can be passed. 122 00:06:01.955 --> 00:06:05.227 Now the interesting thing here is that none of these methods 123 00:06:05.227 --> 00:06:09.655 attempts to work out what the value should be. 124 00:06:09.655 --> 00:06:10.787 In all cases, 125 00:06:10.787 --> 00:06:14.606 the valueOf method delegates the job of producing the string 126 00:06:14.606 --> 00:06:16.439 to the class involved. 127 00:06:18.246 --> 00:06:19.867 So if we wanna print an int, 128 00:06:19.867 --> 00:06:22.987 the method calls the Integer class' toString method. 129 00:06:22.987 --> 00:06:26.187 Similarly for Long, Float, and Double, 130 00:06:26.187 --> 00:06:28.067 the toString method's called 131 00:06:28.067 --> 00:06:31.435 to get the string representations of the object. 132 00:06:31.435 --> 00:06:34.083 And it's the same for the other types too, 133 00:06:34.083 --> 00:06:35.707 they just wouldn't fit on the screen 134 00:06:35.707 --> 00:06:38.886 so the valueOf method delegates the task of deciding 135 00:06:38.886 --> 00:06:41.864 what the string representation of each class should be, 136 00:06:41.864 --> 00:06:43.646 to the class itself. 137 00:06:43.646 --> 00:06:47.186 Now if valueOf just delegates the task to the class, 138 00:06:47.186 --> 00:06:50.635 it doesn't really need to know what class it's dealing with. 139 00:06:50.635 --> 00:06:52.256 In other words, whatever it gets, 140 00:06:52.256 --> 00:06:54.587 it could just call the toString method 141 00:06:54.587 --> 00:06:56.126 and return the result. 142 00:06:56.126 --> 00:06:59.347 And that turns out to be exactly the approach 143 00:06:59.347 --> 00:07:00.847 that Python takes. 144 00:07:04.136 --> 00:07:04.969 Now I'm not gonna go 145 00:07:04.969 --> 00:07:07.874 into the pros and cons of Java versus Python, 146 00:07:07.874 --> 00:07:11.871 nor of statically versus dynamically typed languages. 147 00:07:11.871 --> 00:07:14.506 I enjoy programming in both Java and Python 148 00:07:14.506 --> 00:07:16.895 and each have their own uses. 149 00:07:16.895 --> 00:07:20.204 What's important is the different philosophies adopted 150 00:07:20.204 --> 00:07:22.306 by the two languages. 151 00:07:22.306 --> 00:07:26.274 Now in Java, you have to specify exactly what type of object 152 00:07:26.274 --> 00:07:27.535 you'll be dealing with. 153 00:07:27.535 --> 00:07:29.854 Otherwise, the code won't even compile. 154 00:07:29.854 --> 00:07:31.695 And that means that every method 155 00:07:31.695 --> 00:07:35.862 knows exactly what it can do with the arguments it receives. 156 00:07:38.474 --> 00:07:41.074 Now Python takes a completely different approach. 157 00:07:41.074 --> 00:07:43.844 It doesn't care about what something is, 158 00:07:43.844 --> 00:07:47.154 it's only interested in how each thing behaves. 159 00:07:47.154 --> 00:07:50.074 So Python focuses on what something does, 160 00:07:50.074 --> 00:07:53.324 without worrying about what type it is. 161 00:07:56.255 --> 00:07:57.745 Now in both languages, 162 00:07:57.745 --> 00:08:02.324 classes inherit from the topmost base class called object 163 00:08:02.324 --> 00:08:05.674 and this base class defines a basic implementation 164 00:08:05.674 --> 00:08:08.934 of the toString method, in the case of Java, 165 00:08:08.934 --> 00:08:11.684 and the __str__ method in Python. 166 00:08:13.963 --> 00:08:16.864 Now the default implementation isn't very pretty, 167 00:08:16.864 --> 00:08:19.984 it just returns the name of the class and a hash code 168 00:08:19.984 --> 00:08:23.283 or the address in memory where the object lives. 169 00:08:23.283 --> 00:08:24.784 Now in both languages, 170 00:08:24.784 --> 00:08:27.334 the polymorphic behaviour of the classes, 171 00:08:27.334 --> 00:08:29.915 in the case of the toString and str methods, 172 00:08:29.915 --> 00:08:32.665 is implemented using inheritance. 173 00:08:35.014 --> 00:08:37.483 So polymorphism basically means 174 00:08:37.483 --> 00:08:41.254 that objects can be more than one thing at the same time. 175 00:08:41.254 --> 00:08:42.763 And then when int is a number, 176 00:08:42.763 --> 00:08:45.643 so it's something you can use to perform arithmetic, 177 00:08:45.643 --> 00:08:48.424 but it's also something that can be printed. 178 00:08:48.424 --> 00:08:52.115 So inheritance is one way to implement polymorphism. 179 00:08:52.115 --> 00:08:55.014 So in this example of making things printable, 180 00:08:55.014 --> 00:08:56.944 every object can be printed, 181 00:08:56.944 --> 00:09:00.681 as well as used for whatever else it does. 182 00:09:00.681 --> 00:09:03.123 Now this is possible because every object 183 00:09:03.123 --> 00:09:06.540 automatically inherits the __str__ method 184 00:09:08.362 --> 00:09:11.529 from it's object base class in Python. 185 00:09:13.635 --> 00:09:15.652 Now inheritance isn't the only way 186 00:09:15.652 --> 00:09:17.723 to implement polymorphism. 187 00:09:17.723 --> 00:09:19.803 Consider a ball and an orange. 188 00:09:19.803 --> 00:09:21.595 They both have a similar shape 189 00:09:21.595 --> 00:09:23.254 so we could juggle with balls 190 00:09:23.254 --> 00:09:25.395 and we could also juggle with oranges, 191 00:09:25.395 --> 00:09:27.274 if we can juggle at all of course, 192 00:09:27.274 --> 00:09:29.715 but they don't inherit their round shape 193 00:09:29.715 --> 00:09:31.813 from any common ancestor. 194 00:09:31.813 --> 00:09:34.704 So a ball and an orange are totally unrelated, 195 00:09:34.704 --> 00:09:37.085 but they can still share some properties 196 00:09:37.085 --> 00:09:40.585 without inheriting them from a base class. 197 00:09:41.995 --> 00:09:46.213 So to a juggler, balls and oranges have similar behaviour. 198 00:09:46.213 --> 00:09:47.613 To a hungry person, 199 00:09:47.613 --> 00:09:51.293 an orange probably has more in common with a loaf of bread 200 00:09:51.293 --> 00:09:53.144 because both can be eaten. 201 00:09:53.144 --> 00:09:56.504 So to stretch the example one more time before I move on, 202 00:09:56.504 --> 00:09:58.323 a gardener may be more interested 203 00:09:58.323 --> 00:10:00.391 in what happens when we plant the orange 204 00:10:00.391 --> 00:10:03.373 and might consider it to have more in common with an acorn, 205 00:10:03.373 --> 00:10:05.744 both can be used to grow a tree. 206 00:10:05.744 --> 00:10:09.077 Okay so going back to our print example. 207 00:10:10.732 --> 00:10:12.504 The print function in Python 208 00:10:12.504 --> 00:10:14.944 doesn't have to cater for the possibility 209 00:10:14.944 --> 00:10:17.092 that the thing it's being asked to print 210 00:10:17.092 --> 00:10:19.723 may not have a suitable method to return a string. 211 00:10:19.723 --> 00:10:22.803 And that's because every class automatically inherits 212 00:10:22.803 --> 00:10:25.681 the method from the object base class. 213 00:10:25.681 --> 00:10:26.771 So that's fine here, 214 00:10:26.771 --> 00:10:28.133 the print function 215 00:10:28.133 --> 00:10:30.784 can cope with anything that's passed to it 216 00:10:30.784 --> 00:10:32.253 because whatever it is, 217 00:10:32.253 --> 00:10:36.420 it's guaranteed to have a string method, str method. 218 00:10:37.752 --> 00:10:40.362 But what bout our enemies in Python? 219 00:10:40.362 --> 00:10:41.383 If we wrote a function 220 00:10:41.383 --> 00:10:43.565 that accepted an Enemy as a parameter 221 00:10:43.565 --> 00:10:46.714 and called the take_damage method of its parameter, 222 00:10:46.714 --> 00:10:49.813 there's no real guarantee that the object we passed to it 223 00:10:49.813 --> 00:10:53.333 would have a take_damage method in Python. 224 00:10:53.333 --> 00:10:56.244 Now we could pass a Player instance to it, for example, 225 00:10:56.244 --> 00:11:00.411 and we haven't given our Player class that method. 226 00:11:01.422 --> 00:11:03.514 Now in Java, that wouldn't be a problem. 227 00:11:03.514 --> 00:11:05.363 We'd have to specify Enemy, say, 228 00:11:05.363 --> 00:11:07.103 as the type of the parameter 229 00:11:07.103 --> 00:11:08.514 and the compiler would then check 230 00:11:08.514 --> 00:11:12.554 that anything we passed did inherit from the Enemy class. 231 00:11:12.554 --> 00:11:15.651 Now in Python though, there's no such checking. 232 00:11:15.651 --> 00:11:18.173 Python isn't interested in the type of objects, 233 00:11:18.173 --> 00:11:20.343 it's only interested in their behaviour 234 00:11:20.343 --> 00:11:22.426 at the time they're used. 235 00:11:23.532 --> 00:11:25.773 Okay so let's end the video here. 236 00:11:25.773 --> 00:11:28.565 In the next video, let's see how all this relates 237 00:11:28.565 --> 00:11:29.863 to Python code. 238 00:11:29.863 --> 00:11:31.929 See you in the next video.