back to index

Every New Feature in Python 3.10.0a2


Chapters

0:0 Intro
2:25 type union operator
4:59 type alias annotation
9:52 equal length flag
11:45 bit count
12:36 mapping for dictionary views

Whisper Transcript | Transcript Only Page

00:00:00.000 | Hi, we're going to go through the second alpha version of Python 3.10 today.
00:00:05.840 | So it was released at the beginning of November.
00:00:08.800 | And with it, we can already see quite a few new features.
00:00:13.360 | So we're just going to go through those.
00:00:15.840 | And it seems honestly pretty interesting.
00:00:18.880 | So I think the first thing we're going to go through the further extensions to the type annotations.
00:00:25.200 | So on that front, there are three main new features, the postponed evaluation of annotations,
00:00:32.800 | the type union operator, and the type alias annotation.
00:00:38.400 | So for those of you that are not aware,
00:00:40.640 | we have the timeline of the type annotations with each new Python release here.
00:00:47.600 | So in version three, we had the initial implementation of function annotations.
00:00:53.440 | And then on and on since then, there's more has been added,
00:00:57.840 | there are a few different ways to do different things up until version 3.9,
00:01:01.840 | where everything was aligned.
00:01:03.520 | And they added the typing module syntax to the standard collections.
00:01:09.760 | So this extension of the typing annotations has been continued with version 3.10.
00:01:18.240 | The first one is the postponed evaluation of annotations.
00:01:21.200 | And this is the point that Python will actually evaluate the type annotation in our code.
00:01:28.720 | So typically, this would be done at function definition time,
00:01:33.040 | meaning that they're evaluated line by line in a top down fashion.
00:01:37.440 | And obviously, that kind of makes sense.
00:01:40.160 | But at the same time, this can cause issues because if we, for example, define a type
00:01:48.560 | at the top or refer to a type near the top of our code that actually doesn't get defined until later
00:01:53.600 | on, I mean, even though it still makes sense, it's just a forward reference that will cause problems.
00:02:00.160 | So what they've done is postpone the evaluation until later on.
00:02:06.720 | So this also speeds up the module imports very slightly,
00:02:11.520 | and also prevents this issue of forward referencing not working.
00:02:18.320 | So I mean, that's pretty much it for the postponed evaluation of annotations.
00:02:23.440 | It's pretty straightforward.
00:02:24.880 | The next type union operator.
00:02:27.360 | So let me show you what we had to do before.
00:02:30.640 | So let's go back to Python 3.9 here.
00:02:34.720 | So say, for example, we have a function and we can take either an integer or a float into that
00:02:42.560 | function. Now, before what we would have to do, or at least in 3.9, we would have to use the union
00:02:53.280 | like this. And then we'd pass a list of our two types.
00:02:59.120 | So int float like that.
00:03:02.720 | I'm just going to output a float.
00:03:05.440 | And you'll see why in a minute.
00:03:09.280 | So here, we're just going to return x times by 3.142.
00:03:16.880 | Okay, so obviously with this, it would make sense if x is either an integer or a float,
00:03:22.080 | but nothing else.
00:03:23.520 | So the way that we would do that before is using this union operator.
00:03:29.200 | And with that union operator, we would have to import that from typing.
00:03:35.840 | So like this.
00:03:38.000 | Okay, let me just save this.
00:03:40.960 | Okay.
00:03:43.540 | So now let's run it and see what happens.
00:03:48.400 | Okay, sorry, I need to actually do something here.
00:03:54.880 | And so we can pass 4, which is an integer.
00:04:00.960 | And then we'll just pass this as well.
00:04:06.160 | So this makes sense.
00:04:07.760 | Okay, that's fine.
00:04:10.000 | It works as we would expect.
00:04:12.480 | So what Python 3.10 has added here.
00:04:17.520 | Go back to this.
00:04:19.520 | So we don't need to import this anymore.
00:04:22.960 | And instead of using this union operator,
00:04:30.720 | we have this really nice new syntax, slightly bitwise, or operator.
00:04:36.000 | And we just use that, so int or float.
00:04:39.280 | And this will work in just the same way.
00:04:42.320 | All right, and that didn't work before.
00:04:44.160 | Before, we would get a syntax error.
00:04:46.480 | So if we run this in 3.9.
00:04:48.560 | Okay, unsupported type error.
00:04:53.440 | So that's the other new addition to typings.
00:04:59.680 | And then the final one is the type alias annotation.
00:05:02.960 | Okay, so the current issue with the type aliases
00:05:08.320 | is that if we are forward referencing another type
00:05:15.440 | that hasn't been defined yet, we would use a string.
00:05:18.160 | So for example, if we are importing this type
00:05:22.800 | from another module, but the module hasn't been imported yet,
00:05:27.200 | we might want to still reference that type.
00:05:29.840 | And we would do that just using a string like this.
00:05:33.840 | And this is fine, but obviously, it's just not very explicit
00:05:40.960 | as to what we're doing here.
00:05:42.000 | So could write something like this with type alias as a type.
00:05:52.080 | And we also want to return type alias.
00:05:55.840 | Okay, and we return name there.
00:05:57.520 | So if we run that, it's fine.
00:06:01.440 | Okay, and we can call it and we'd say,
00:06:05.280 | that's the name, hello.
00:06:08.480 | Works fine.
00:06:10.240 | But the issue is here that it's not clear that this is,
00:06:16.400 | obviously, we've written type alias here,
00:06:18.080 | but if you get another name, it's not very clear
00:06:20.240 | that this is actually a type alias.
00:06:23.120 | So what has been included now is switch over to Python 3.10.
00:06:31.280 | Okay, just rerun this.
00:06:36.480 | Okay, so works.
00:06:40.800 | And so what we now have in Python 3.10 is a type alias type.
00:06:49.920 | So if we do from type extensions, import type alias.
00:07:01.440 | Okay, and now we make it explicit that this is,
00:07:09.120 | in fact, a type alias and not a string.
00:07:11.200 | Okay, and then we can run this again.
00:07:13.520 | Okay, that works.
00:07:17.680 | But now it's just more explicit that, yes, this is not string.
00:07:21.680 | This is, in fact, a type alias.
00:07:23.280 | So that's another addition.
00:07:26.400 | And that's everything that has been added
00:07:28.480 | in terms of the type annotations.
00:07:32.240 | And obviously, I mean, this is not like a huge,
00:07:35.520 | a massive change, but it's,
00:07:38.160 | I think it's very cool regarding the past changes
00:07:42.080 | in type annotations.
00:07:43.600 | See that the developers are doubling down on enhancing
00:07:47.440 | these features.
00:07:48.160 | Obviously, a big strength of Python comes from its ease
00:07:53.280 | of use and the lack of a steep learning curve.
00:07:57.120 | And one of the reasons for this is the lack of need
00:08:01.520 | to actually explicitly define types in our code.
00:08:05.440 | Unlike, for example, C, where you are explicitly defining
00:08:11.760 | what every variable is and the type that it is.
00:08:14.720 | Python, we don't need to do that.
00:08:17.040 | And that makes it a lot easier to get started,
00:08:19.760 | which is great, and that's really good.
00:08:21.440 | But it's also a little bit difficult when it comes
00:08:26.080 | to actually reading more complex code bases.
00:08:29.920 | If you go into a popular open source library
00:08:35.440 | and read through the code,
00:08:36.640 | figuring out what is going into a function
00:08:40.240 | and what's coming out of it is really difficult.
00:08:42.880 | But when we start to add things like this,
00:08:47.520 | it makes it incredibly easy.
00:08:49.600 | So, for example, instead of this,
00:08:52.960 | or actually, maybe this is a better example.
00:08:55.280 | Like here, we know that x has got to be either an integer
00:08:58.880 | or a float.
00:08:59.840 | And we know that it's going to return a float.
00:09:01.360 | If we got rid of these, obviously, with this function,
00:09:05.200 | it's really obvious.
00:09:08.400 | But when you have something like some big machine
00:09:13.360 | learning library, like TensorFlow or PyTorch,
00:09:16.000 | and reading through that, it's pretty confusing.
00:09:21.360 | And without these types, it can get very, very difficult.
00:09:27.520 | But now, if you look at, for example,
00:09:30.640 | parts of the Transformers library,
00:09:32.240 | which is another machine learning library,
00:09:34.960 | they've started adding in types,
00:09:37.600 | and it makes it so much easier to read.
00:09:40.400 | So, for that reason, I think that these little differences
00:09:46.000 | or these little additions are very cool
00:09:48.640 | and really, really good to see.
00:09:51.120 | So, on the other features that have been added,
00:09:54.960 | we have a few, there's a new equal length flag
00:09:59.600 | for the sip function.
00:10:01.520 | So, if we have two lists here, okay,
00:10:08.080 | and then we have another one, okay.
00:10:11.920 | Normally, if we create a zip generator with both of these,
00:10:19.600 | we'll see that there are no issues here.
00:10:23.120 | And, I mean, it's kind of weird because neither,
00:10:26.960 | these are not the same length.
00:10:28.080 | So, this doesn't cause any issues,
00:10:31.760 | which, I mean, maybe that's fine.
00:10:36.160 | But to me, at least, that's pretty weird.
00:10:40.080 | What it does is actually just truncates the longer string,
00:10:43.920 | sorry, the longer list.
00:10:45.280 | And I imagine a lot of developers have had a headache
00:10:50.880 | trying to figure out what has gone wrong
00:10:53.280 | because of this kind of strange feature.
00:10:56.720 | So, what they have added in Python 3.10 is a strict flag.
00:11:05.440 | So, rather than just allowing this to happen,
00:11:10.720 | we can run it with a strict flag set to true.
00:11:12.720 | Okay, so now we actually get a value error saying
00:11:16.560 | the argument two is shorter than argument one,
00:11:18.880 | which is a nice, I mean, it's nothing crazy,
00:11:22.720 | but it's a nice addition.
00:11:25.120 | So, I mean, rather than blindly truncating mismatched data,
00:11:30.240 | we actually can check now with a built-in argument,
00:11:35.200 | which is pretty nice, I think.
00:11:37.520 | And I think it will save people a lot of time
00:11:40.240 | trying to figure out what has gone wrong with their code.
00:11:43.440 | So, it's pretty useful.
00:11:44.320 | The next one is the new bit count.
00:11:47.920 | So, here, we're actually counting the number of active bits
00:11:54.080 | in that integer's binary value or binary representation.
00:12:01.680 | So, for one, so, zero, obviously, it's just going to be this.
00:12:08.480 | For one, the binary representation is this.
00:12:13.040 | For two, this.
00:12:15.680 | So, we can see, right, for the first one,
00:12:18.880 | there's zero ones in there.
00:12:20.960 | For number one, there's one one.
00:12:24.560 | Number two, there's two ones.
00:12:27.600 | So, number three, we would expect that to be two ones,
00:12:33.680 | and we're sure it is.
00:12:35.280 | Okay, so, the final of the other features
00:12:39.040 | are the mapping for dictionary views.
00:12:43.040 | So, in Python, we have three different dictionary views
00:12:46.960 | that we can use.
00:12:47.600 | And that is a view for keys, values,
00:12:53.840 | and the dictionary itself or the dictionary items.
00:12:57.760 | So, if we create a dictionary here,
00:13:01.280 | very simple one.
00:13:05.280 | Yeah, let's just run this script.
00:13:09.760 | Let me show you down here.
00:13:12.320 | So, we have d.keys,
00:13:15.360 | and that returns us the keys in our dictionary.
00:13:21.600 | And then, we also have the values.
00:13:24.880 | Okay, and that returns a view with the values
00:13:28.640 | of our dictionary.
00:13:29.440 | And then, we also have items,
00:13:32.240 | which just returns everything inside our dictionary.
00:13:37.040 | So, what we have now, if we create a keys object here,
00:13:45.360 | which is our view of the keys in the dictionary,
00:13:51.200 | and let's have a look at the underlying attributes
00:13:55.120 | and methods that we have here.
00:13:57.040 | So, with this new update with 3.10,
00:14:00.320 | we have a new attribute called the mapping attribute.
00:14:03.120 | And you can see it's near the bottom here.
00:14:07.760 | So, it returns the dictionary that this view refers to.
00:14:13.600 | So, if we do keys.mapping,
00:14:18.560 | it returns us this mapping proxy object,
00:14:22.080 | which wraps around our original dictionary.
00:14:25.440 | So, yeah, that's the new mapping attribute
00:14:29.440 | that we have for our views now.
00:14:31.120 | And with that, that is everything that is new,
00:14:33.440 | the current alpha version of 3.10.
00:14:37.600 | I hope this has been a useful video,
00:14:40.320 | and thank you for watching.