Rock Solid Python with Python Typing Transcripts
Chapter: Orthogonal Typing
Lecture: Static duck typing with Protocols
Login or
purchase this course
to watch this video and the rest of the course contents.
0:00
Well, well, well, our duck is sure looking pretty good right now, isn't it? With the duck typing, maybe we wouldn't have had any of those problems.
0:09
Maybe that type hierarchy would have been useful, but we could have just said, ""It takes a thing that looks like it has an acceleration or something.
0:19
In our world, maybe we just wanted to start the vehicle, turn it in a direction, and accelerate or decelerate it.
0:26
If all of those things on that picture before did those things, it could be a walks like
0:31
a duck, talks like a duck, it is a duck, you can just use it in this duck typing scenario. But with Python types, we saw that not so much, right?
0:41
Well, this whole chapter shows you a how to have static typing and duck typing, and to get along really well.
0:47
It's a very cool thing we're going to talk about called protocols. So let's put aside that crazy deep object hierarchy and build a better motorcycle.
0:58
So we're going to jump over into PyCharm and write some code in a way that looks like it
1:03
supports duck typing or in a sense really does support duck typing, but statically. Sounds paradoxical. Follow me here. It's going to be cool.
1:13
So here we are over in a new chapter six orthogonal or structural typing. And we have a protocol app.
1:20
Now I've kind of laid out in comments that object hierarchy and the challenges you might run into with it.
1:27
And what we're going to do instead is we're going to use something called protocols in a way that is quite interesting. Okay.
1:35
So I would like a type something I could say down here, for example, this do vehicle things, I want to be able to pass in an object called a vehicle.
1:46
And I want it to be able to turn on, turn towards a direction and accelerate. Basically do those three things.
1:53
I want to be able to express that in typing, but in a duck type way.
1:57
So as long as those three operations with the right signature exist on the object class callable, whatever, it works.
2:07
If they don't exist, it's not a match. And we're not going to do this with inheritance. Not only. Okay. really cool typing construct called a protocol.
2:20
Now it looks like what you might know from other languages, like what would be called an interface. In C# and Java, you have pure abstract interfaces,
2:33
just the keyword interface, and that means it can't have an implementation. It only conveys a structure sort of thing.
2:40
In C++, I don't know if they've added that recently. It's been a while since I did C++, but pure abstract base classes, right?
2:48
There's no implementation, just structured, conveyed by that. So you might at first think of protocols like that,
2:55
but they're more about the duck typing side than they are about this interface side. Let's see. So we're gonna create a class,
3:03
which will be called drivable, or whatever you want. If you wanna go C Sharpie on it, you can put an interface,
3:09
but again, that's not exactly the right metaphor. I wanna say typing protocol.
3:14
And then down here, we're going to put the things we would like it to do, turn on, turn towards and so on.
3:21
So let me just write these out and zoom through them. So first we say def turn on just like you would a regular class based function, you
3:29
say the self and this one has no parameters, but it does return a bool.
3:34
But instead of an implementation, you just put triple dot, then def turn towards and so on.
3:41
And feel free to load this puppy up with the types that you want.
3:45
It's going to return a none, but the direction is going to be a string again, dot, dot, dot.
3:51
So here we have this description of the duck typing story that we wanted to tell.
3:58
Anything that goes in here must have a turn on or turns towards that takes us direction,
4:02
which is a string in an accelerate, which takes a rate, positive, negative, whatever, but is a float here.
4:09
Now, here's where the interface sort of abstract base class thing changes. So watch this.
4:17
Let's say this takes a drivable, which should be fine, and drivable. And we have basically the same motorcycle program as from chapter two.
4:26
But down here, I did add a turn on, a turn towards an accelerate to the motorcycle class.
4:32
So it just comes up with some chance of it actually turning on. and it says it's running or it's stalled, right? Something like that.
4:41
You know, put your level of reliability in the divisor there. It turns towards the direction and it's going at a certain rate faster.
4:51
Probably should check whether it's negative or positive and just say slower instead of a negative faster,
4:56
but who didn't like a double negative in their acceleration? All right, so the very important thing to notice
5:02
is motorcycle does not derive from drivable. I did not say this. I wouldn't hurt it to say this, but check this out.
5:12
So if I go down here and I say, I would put, or we're doing our thing here, our motorcycle comes up and it says,
5:22
do motorcycle or do vehicle things and let's just run it. Hey, the Tenere is stalled. Oh no, we're not doing that one. It's running, hooray.
5:29
Now it turns north and now it's going 9.81 faster. So probably units.
5:35
should be required there, someone with pint. But this, okay, so what have we learned here?
5:43
Not too much, it just kind of seems duck typing. But watch this. Notice what I did is I removed
5:53
the turn on capability. So remember to be drivable, what do you need? You got to turn
5:57
on, turn towards and accelerate. What's wrong with the motorcycle? I didn't change its base
6:02
class or anything like that. But Python knows the type system knows this thing is not walks
6:12
like a drivable talks like a drivable. So it is drivable. No, it doesn't because it
6:16
doesn't turn on it doesn't match the duck typing story. But here we have a concrete
6:22
way through this drivable protocol here that says, these are the requirements. I don't
6:29
care what your base class is, I don't care what your hierarchy looks like or any of those
6:33
things, I just need these pieces of functionality, this protocol, drivable, to be met in order to be used here.
6:40
So I put this back, there we go, works fine. And again, you would know if we try to run it, it's going to crash and it says has no attribute turn on.
6:55
What does the error say up here? type drivable got motorcycle instead because motorcycles are not drivable. How awesome is this?
7:06
So I think this is an incredibly cool capability and here's your duck, but your duck typing, but in static typing form.
7:17
We define a thing that expresses what we expect from the thing being passed in, but this bit
7:24
is not at all involved in the type definition of motorcycle. It's not a base class. We haven't registered them together. None of that.
7:32
We just said this function takes a thing that has to have those walks like a duck, talks like a duck, quacks like a duck. And so it is a duck.
7:41
It has to be a drivable type of thing in its behavior. And if it is, it's a good fit. As you saw, if I take out part of it or change it,
7:48
I'm sure if I even just change the signature here, success, oh no, PyCharm is not checking it. It's not going to love that.
7:58
It will not be successful, right? But if these don't exist in the structure that the protocol suggested, not going to work.
8:05
I think this is just such a cool idea. It lets you still have your duck typing.
8:09
It lets you still have a simplified object hierarchy if you have one at all. And yet, you still get run even editor time and
8:19
my PyTime level of compatibility checks. Awesome, huh?