back to indexNew Features in Python 3.10
Chapters
0:0 Intro
0:45 Type Annotations in Python
1:10 Typing Union Operator
2:7 Parenthesized Context Managers
5:7 Structural Pattern Matching
9:31 Better Error Messages
00:00:00.000 |
Hi and welcome to this video. We're going to explore what is new in Python 3.10. 00:00:06.800 |
There are a few different things I want to cover there. We have some more additions to typing, 00:00:12.080 |
which I think are pretty cool. The parenthesized context manager, which is kind of an interesting 00:00:19.440 |
update because it's not really an update, so we'll get into that pretty soon. We have structural 00:00:26.240 |
pattern matching, which I've covered before, and we're just going to run through it really quickly 00:00:30.080 |
in this video. And then there is also a load of new error messages, which are pretty interesting, 00:00:37.200 |
actually. There's some really good ones in there. So we'll go through all of those new features 00:00:43.360 |
in Python 3.10. Okay, so in the last few iterations of Python, there's been a steady 00:00:50.880 |
improvement of the Python's type hinting or type annotations capabilities. And with Python 3.10, 00:00:59.200 |
we are seeing more of that again. Now, there's a few changes or a few updates and features with 00:01:06.320 |
the typing in Python 3.10, but I think the most interesting one is the addition of a new operator. 00:01:14.560 |
So this is what we used to have to do in Python 3.9 and before. So in here, I'm just defining 00:01:24.720 |
really simple function that adds two integers or floats together. Now, if we want to define x and 00:01:31.440 |
y as being potentially an integer data type or a float data type, then we would have to use this 00:01:38.960 |
union operator, which we would import from typing up here. Now, with Python 3.10, we don't have to 00:01:45.200 |
do that anymore. It's much simpler. All we do is include the pipe character here, which is our new 00:01:53.520 |
union operator, which obviously it looks a lot cleaner. So that's the main new feature with type 00:02:01.920 |
annotations in 3.10. So let's move on to the new parenthesize context manager. Okay. So what we're 00:02:09.840 |
talking about when we talk about context managers is exactly what you can see on the screen now. So 00:02:16.080 |
we have, this is the most common example of a context manager in Python. And this is just how 00:02:22.960 |
we read in our files. So we have with, so this is setting up our context. And here we are assigning 00:02:32.480 |
this stream here as F. Okay. And then within this indented area, we can read F, but outside of it, 00:02:40.640 |
we can't. So we couldn't write something like text equals F dot read, because in this case, 00:02:50.480 |
F just doesn't exist outside of that context. So that's what we mean by context manager. 00:02:54.640 |
Now, if we wanted to open multiple context managers within the same area, 00:03:02.240 |
we could write something like this. So we'd have with open and we have another open afterwards, 00:03:09.600 |
and then we would be able to access both of those within this indented area. 00:03:13.200 |
The only problem is that we would have to keep all of this on the same line 00:03:19.760 |
due to limitations with Python's previous parser. Now, the parser got updated in Python 3.9, 00:03:27.040 |
which is why I say this is kind of not really a new update, but it is a new update. 00:03:31.920 |
So before then, we had to keep everything on a single line. And we can get around that a little 00:03:39.120 |
bit by adding the line continuation character, and this would work as well. But the problem with this 00:03:45.600 |
is that it's not technically Pythonic, which I mean, for most people, it doesn't really matter. 00:03:51.520 |
But now what has been added, thanks to the new Python parser, which introduced in 3.9, 00:03:59.120 |
is we can include parenthesized context managers. So we can add these inside brackets. 00:04:07.200 |
And that will now work. And this is officially a new feature for Python 3.10. 00:04:13.920 |
But we can actually switch back to Python 3.9. And if I run this again, 00:04:20.960 |
we see that it still works. So that's kind of weird, right? Now, the reason for that is that 00:04:28.160 |
the parser, the new parser introduced in 3.9, allows this syntax to work. But it was not added 00:04:37.520 |
as a genuine new feature until Python 3.10. Now, why that has been done, I really can't tell you 00:04:46.080 |
because I don't understand. But that is just how it is. Now, if we take this back one version 00:04:53.200 |
further to 3.8, we see that we do actually get the invalid syntax. So this is a new feature, 00:05:02.560 |
but it's also not a new feature. So yeah, that's a strange one. Now, the next one, which I think is 00:05:11.600 |
probably the most hyped new feature of 3.10, and with good reason, it is very cool, is the 00:05:17.840 |
structural pattern matching. Now, we can write this statement here. And this is just a simple 00:05:25.440 |
example. We're going to move on to a real example in a moment. This is an if-else statement. And 00:05:31.760 |
we're just checking this code. We can run that without a problem. And some new syntax has been 00:05:37.360 |
added in Python 3.10. And that is the match case statement. So this is the equivalent of what we 00:05:45.680 |
did up here, but using the new match case syntax, which, OK, that's interesting. It's cool. But it 00:05:52.720 |
doesn't really bring us anything new. We could just do that with a if-else statement before. 00:05:57.520 |
So that's not particularly interesting. But what is interesting is the structural pattern matching 00:06:04.880 |
part of this new syntax, which allows us to do this match case comparison. But rather than 00:06:12.160 |
specifying whether that HTTP code is an exact match to whatever values are in those case statements, 00:06:19.680 |
we can check the structure of a object and check if it matches a pattern which we pass 00:06:26.560 |
through the case statement, which is very, very cool. Now let's see how that works. So if I 00:06:34.400 |
remove these two, I'm going to define a dictionary here. So dictionary A and dictionary B. Now, 00:06:41.600 |
these two both contain similar information, but they're in a different structure. So that means 00:06:46.480 |
that we would have to access both of these using different paths. Now, what we can do is create a 00:06:56.560 |
pattern that matches both of these and add them both within a match case statement. And we can 00:07:03.360 |
use that to check which pattern we have and perform a different operation on each one. 00:07:09.120 |
So to do that, first, so this is our code. We're going through in a loop through dictionary A, 00:07:17.040 |
dictionary B, and I've just added this string called test that shouldn't match to anything 00:07:22.080 |
because it's just a string. Okay. So looping through each of those, and we're going to test 00:07:26.480 |
the match case on each one. So first, so we're matching here and then we have our case. And then 00:07:32.560 |
here is our pattern. So this is a pattern we want to match. Now, if we compare that pattern, 00:07:38.160 |
we'll see that we have ID and meta, ID and meta, and inside meta, we have another dictionary, 00:07:45.920 |
which contains source and location. And here we have source and location as well. Now this doesn't 00:07:51.760 |
need to be perfect match, by the way, we could, this would also match if I got rid of location 00:07:56.080 |
like that. And obviously we'd have to go to loc here as well. So it doesn't have to be a perfect 00:08:04.640 |
match, just as long as whatever you have entered does fit into the structure that we are comparing 00:08:11.200 |
against. Now that's the first one, but that will not match to this because we don't have the meta 00:08:18.720 |
key and the meta does not contain no dictionary. Okay. And in dict B, but it does match this one, 00:08:26.240 |
which is ID source and location. Same as this one here. So that will match. And then here we have 00:08:35.600 |
our catch all statement. So this is like our else statement, and this will just catch any items that 00:08:43.120 |
do not match either of those cases, e.g. our test at the end there. So let's run that and see what 00:08:48.480 |
it prints. Okay. So we see that we get the first one. So it manages to extract, ident, source and 00:08:56.400 |
loc, and print those all out. And then for the second one, it does the same, even though they're 00:09:00.800 |
a different structure because it matches to this different case. And then here we have our catch 00:09:05.200 |
all and we print out no match. So this, I think easily is the coolest feature in 3.10. And I've 00:09:14.560 |
already found it useful for processing data in a similar way to what I'm showing here. So it's, 00:09:19.920 |
in my opinion, super cool and something to be excited for. So let's move on to our final new 00:09:29.120 |
feature, which are the new and improved error messages. Okay. So let's move on to the new error 00:09:36.000 |
message in 3.10. So they've done quite a few new messages here that are just a lot easier to 00:09:45.600 |
understand. So for example, if we take this unclosed dictionary in 3.9, we get this unexpected 00:09:55.120 |
EOF while parsing. EOF means end of file. So this basically is telling us that the parser has gone 00:10:03.040 |
all the way to the end of the file and it hasn't found the closing bracket of our dictionary. 00:10:07.360 |
And okay, fair enough. Once you've been using Python for a while, you know what it means, 00:10:12.960 |
that's fine. But this isn't particularly clear, especially if you're new to Python. I mean, 00:10:18.960 |
I'm certain that the first time I got this error, and I'm certain that almost everyone, 00:10:23.920 |
the first time I got this error, will have had to Google what this means. Now in Python 3.10, 00:10:32.560 |
now it's really simple. It's telling us that our dictionary was never closed, 00:10:37.440 |
which is much better. Now in the same sort of area, we also have unclosed strings where we 00:10:43.920 |
get this EOL, which is end of line. And that means the same thing again, saying we've got to the end 00:10:50.240 |
of the line and your string isn't closed. Now in Python 3.10, rather than that, we get this 00:10:57.360 |
untermated string literal, and that's just so much easier to understand. Another one is assignment 00:11:06.400 |
versus comparisons. So obviously here we should have a double equal sign because we're comparing, 00:11:12.800 |
we're not making two equal to three. So if we run that, we just get invalid syntax. Now for us, 00:11:20.400 |
obviously we know what's going on there, but maybe if you're new to the language, 00:11:24.800 |
it might not be so clear. So now what we get is cannot assign to a literal here. Maybe you meant 00:11:32.400 |
double equal sign, not a single equal sign. So a lot clearer again. Now another area that I think 00:11:41.120 |
is pretty interesting, although I can't seem to get it working at the moment, is where we enter 00:11:47.520 |
a incorrect attribute name. So usually we get this attribute error, and that is essentially what we 00:11:53.600 |
will also get over here in Python 3.10. But as well as this, although we don't see it here, 00:12:00.720 |
we should also get a suggested attribute name based on whichever attribute has the closest match. 00:12:10.240 |
Now I'm not sure why it doesn't work here, but if we take a look here on the actual What's New 00:12:17.440 |
Python page, we can see that this should give us a recommendation of do you mean named tuple, 00:12:25.840 |
which I think is pretty cool. And we should also get the same with named errors as well. 00:12:32.240 |
So if we have this new variable on the left, we'll see that we get this name error. New VR 00:12:40.400 |
is not defined because we have a typo. It's fine. And then in Python 3.10, what we should find 00:12:48.160 |
is that this will also recommend, hey, this isn't quite right. Maybe you meant new VR. And we can 00:12:57.200 |
see this in this example here on the What's New page. So overall, I think those new error measures 00:13:06.000 |
are definitely a lot clearer. And they're probably going to help a lot of people. So 00:13:11.120 |
that's really good to see. Okay, so that's everything for this video. 00:13:16.480 |
I hope it's been useful. And I will see you in the next one.