1
00:00:00,000 --> 00:00:05,990
Polymorphism is the practice of using one object of one particular class as if

2
00:00:06,000 --> 00:00:08,990
it were another object of another class.

3
00:00:09,000 --> 00:00:10,990
Let's take a look at how this is done in Python.

4
00:00:11,000 --> 00:00:13,990
This is actually something that Python is very good at.

5
00:00:14,000 --> 00:00:20,990
We'll make a working copy of classes.py and we'll call it classes-working.py.

6
00:00:21,000 --> 00:00:27,990
We'll open that and we see we have our Duck class that has quack and walk in it.

7
00:00:28,000 --> 00:00:42,990
And we'll go ahead and create a Dog class and Dog will have bark.

8
00:00:43,000 --> 00:00:52,990
And fur.

9
00:00:53,000 --> 00:01:01,990
The dog has brown and white fur.

10
00:01:02,000 --> 00:01:17,990
Now, we'll go ahead and create a dog object called fido = Dog and fido.bark and fido.fur.

11
00:01:18,000 --> 00:01:23,990
So now we have a Dog object and a Duck object.

12
00:01:24,000 --> 00:01:29,990
And if we go and run this, we see that the Duck quacks and walks like a duck.

13
00:01:30,000 --> 00:01:32,990
And the Dog barks and has brown and white fur.

14
00:01:33,000 --> 00:01:37,990
So these are two separate and distinct objects and they have two separate and

15
00:01:38,000 --> 00:01:39,990
distinct interfaces.

16
00:01:40,000 --> 00:01:44,990
If we want to be able to use them polymorphically, we need to make sure that

17
00:01:45,000 --> 00:01:46,990
they have a common interface.

18
00:01:47,000 --> 00:01:54,990
And so the Duck class, we can give it a bark and a fur and say bark.

19
00:01:55,000 --> 00:01:59,990
print('The duck cannot bark').

20
00:02:00,000 --> 00:02:10,990
And fur, and this one will say "The duck has feathers."

21
00:02:11,000 --> 00:02:18,990
And we can give the Dog, a walk.

22
00:02:19,000 --> 00:02:22,990
print('Walks like a dog').

23
00:02:23,000 --> 00:02:33,990
And quack. The dog cannot quack.

24
00:02:34,000 --> 00:02:37,990
Now, we can use them in the same way.

25
00:02:38,000 --> 00:02:45,990
For example, let's just get rid of all of this, and we have a Dog and we have a Duck.

26
00:02:46,000 --> 00:02:55,990
And if I say for object in and give it a list, donald and fido.

27
00:02:56,000 --> 00:03:11,990
I can say, o.quack(), o.walk(), o.bark(), o.fur().

28
00:03:12,000 --> 00:03:16,990
So what we have here is we're calling all four of these functions for both of these objects.

29
00:03:17,000 --> 00:03:18,990
We're using them in exactly the same way.

30
00:03:19,000 --> 00:03:23,990
We're using them in a way that really does not know or care exactly what type

31
00:03:24,000 --> 00:03:24,990
of an object it is.

32
00:03:25,000 --> 00:03:29,990
It's simply calling these methods without concern for which type of an object,

33
00:03:30,000 --> 00:03:32,990
just assuming that these methods actually exist in there.

34
00:03:33,000 --> 00:03:36,990
So we'll save that and we'll run it and we see our result.

35
00:03:37,000 --> 00:03:38,990
We have the Duck first. Quaaack!

36
00:03:39,000 --> 00:03:39,990
Walks like a duck.

37
00:03:40,000 --> 00:03:40,990
The duck cannot bark.

38
00:03:41,000 --> 00:03:41,990
The duck has feathers.

39
00:03:42,000 --> 00:03:43,990
And then we have the Dog.

40
00:03:44,000 --> 00:03:47,990
And there is all those same methods on the Dog.

41
00:03:48,000 --> 00:03:58,990
So if I had say a function, say in_the_ forest, and it expects a dog and it says,

42
00:03:59,000 --> 00:04:09,990
dog.bark() and dog.fur().

43
00:04:10,000 --> 00:04:16,990
And let's say I had another one that says in_the_pond and it expects a duck.

44
00:04:17,000 --> 00:04:24,990
And it says duck.quack() and it calls duck.walk().

45
00:04:25,000 --> 00:04:28,990
Now, I can call either of these methods with either of these objects.

46
00:04:29,000 --> 00:04:33,990
I can say in_the_forest, and you see the in_the_forest is expecting a dog and

47
00:04:34,000 --> 00:04:34,990
I can pass it donald.

48
00:04:35,000 --> 00:04:41,990
And as long as donald implements the interface that is being used in this

49
00:04:42,000 --> 00:04:43,990
function, it will still work.

50
00:04:44,000 --> 00:04:45,990
Save this and run it.

51
00:04:46,000 --> 00:04:49,990
It says the duck cannot bark and The duck has feathers.

52
00:04:50,000 --> 00:05:00,990
And likewise, if I call in_the_pond and I pass it fido, save that and run it.

53
00:05:01,000 --> 00:05:04,990
The dog cannot quack and it walks like a dog.

54
00:05:05,000 --> 00:05:06,990
So this is what polymorphism is.

55
00:05:07,000 --> 00:05:13,990
And Python is particularly good at this because the objects in Python don't

56
00:05:14,000 --> 00:05:18,990
actually care what the name of the class is.

57
00:05:19,000 --> 00:05:23,990
When you use an object, Python is what's called loosely typed or actually they

58
00:05:24,000 --> 00:05:28,990
call it duck typing, because the types in Python, everything is an object.

59
00:05:29,000 --> 00:05:32,990
And if it walks like a duck, then you can use it like a duck.

60
00:05:33,000 --> 00:05:33,990
That's why they call it duck typing.

61
00:05:34,000 --> 00:05:35,990
It's loosely typed.

62
00:05:36,000 --> 00:05:41,990
When I declare that this in_the_forest function expects a dog, I'm just naming

63
00:05:42,000 --> 00:05:43,990
it dog, but it's an object.

64
00:05:44,000 --> 00:05:50,990
I could name it cat and it would still work exactly the same, because that's

65
00:05:51,000 --> 00:05:51,990
really just a variable name.

66
00:05:52,000 --> 00:05:52,990
That's not a type name at all.

67
00:05:53,000 --> 00:05:54,990
That's no kind of a restriction.

68
00:05:55,000 --> 00:05:56,990
It's just what I'm calling it here.

69
00:05:57,000 --> 00:05:58,990
So I save that and run it.

70
00:05:59,000 --> 00:06:00,990
It still works exactly the same.

71
00:06:01,000 --> 00:06:06,990
So a strong advantage of this loosely typed or what they call duck typing is

72
00:06:07,000 --> 00:06:09,990
that polymorphism is natural.

73
00:06:10,000 --> 00:06:15,990
So I can create a super class that implements all of the things that an animal

74
00:06:16,000 --> 00:06:20,990
normally does, and then I can create subclasses from that with just the specific

75
00:06:21,000 --> 00:06:25,990
attributes of the type of an animal that I'm interfacing, and then anything that

76
00:06:26,000 --> 00:06:28,990
expects any of those interfaces can use it.

77
00:06:29,000 --> 00:06:31,990
Because all of those interfaces are guaranteed to be there.

78
00:06:32,000 --> 00:06:35,990
So I know that that's a big concept to wrap your head around, but think of it

79
00:06:36,000 --> 00:06:42,990
this way. Any object of any class that implements the interface that's expected

80
00:06:43,000 --> 00:06:46,990
by any function can be used by that function.

81
00:06:47,000 --> 00:06:53,990
So when I create a function here called in_the_forest and it expects an object

82
00:06:54,000 --> 00:06:58,990
that can bark and an object that has fur, or a function that expects an object

83
00:06:59,000 --> 00:07:00,990
that can quack and the object that can walk,

84
00:07:01,000 --> 00:07:06,990
any object that implements those methods will work in that function regardless

85
00:07:07,000 --> 00:07:07,990
of what its type is.

86
00:07:08,000 --> 00:07:18,000
And that is polymorphism and that's how it works in Python.

