back to index

New 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

Whisper Transcript | Transcript Only Page

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.