Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Adding Syntax

00:00 In the previous lesson, I showed you the latest improvements to the error messages in the language. In this lesson, I’ll show you some new syntax for Python.

00:09 Before Python 3.14, if you needed to catch multiple exceptions, you had to surround them in parentheses. Now, in some cases you don’t. If you’re not familiar with except*, that is used with exception groups which got added in Python 3.11.

00:24 They’re a way of adding exceptions on your exceptions. The change I’m going to demo applies to them as well. First, I’ll start with the old way.

00:42 There you go. The regular old exception,

00:49 and this is the original way of collecting multiple exceptions.

00:59 In Python 3.14, you can forego the parentheses,

01:09 that is, unless you want to name the exception using the as keyword, then the parentheses are still required.

01:21 There’s a tricky little thing in Python that happens when you use return, break or continue inside of a finally block.

01:28 Tricky-to-understand code tends to mean things don’t run the way the programmer expected. As such, Python 3.14 is adding a syntax warning if you attempt to do this, and it probably isn’t what you wanted in the first place.

01:41 Let me show you what I mean. In the top window here, I have Python 3.13. Let me write a little function.

02:03 Now before I run it, what do you think it should return? In this code, an exception gets raised, so should the exception block run? But wait, hold on. finally is always supposed to happen no matter what.

02:15 So what’s your guess? The finally gets executed. That means the exception handling gets swallowed. Depending on what you were trying to do in there, this might not have been what you expected.

02:28 Now let’s try the same thing in 3.14.

02:38 It still behaves the same way, but it raises a syntax warning now. This lets you know that something funky is going on. There was some discussion about making this a syntax error, but the core developers decided to stick with the warning to avoid backward incompatibility issues.

02:56 Python supports annotations, which provide meta information about coding structures. The most common use of these is type hints, which gives static analysis tools the ability to check for type mismatches in your code.

03:09 Up until now, the evaluation of annotations was eager, meaning the compiler evaluates them as soon as it comes across them in the code. Eager evaluation makes the structure on the screen here impossible as it tries to evaluate Node before it is declared, resulting in an error.

03:26 There are ways around this. In this particular case, you could go with a simple solution by putting Node before LinkedList. In more complex situations, you can also use strings to annotate types and those get evaluated at a later time.

03:40 Python 3.14 changes evaluation to be lazy. How it achieves this is a bit complicated, and in the summary section I’ll point you at an article you can read if that’s your jam.

03:50 For now, just understand that the annotation doesn’t get evaluated until it gets used, which means the code on the screen is no longer a problem. In theory, this should offer a performance boost as well, as previously, all annotation calculations needed to be run when a module got loaded, whereas now they can almost be ignored until they’re used.

04:11 You can still force eager evaluation by importing annotations from __future__ if you need this for some reason. The annotation information itself gets stored in .__annotations__ and you’ll find this attribute on modules, classes, functions, and methods.

04:28 You can access this attribute directly if you like, but it can be a little messy. Instead, you should use the get_annotations() function from the new annotations module.

04:39 It handles the messy situations like when there aren’t annotations and uglier situations like metaclasses. get_annotations() gives a consistent response, so you should prefer it over accessing the attribute directly. get_annotations() has actually existed for a while, but it used to be in the inspect module.

04:58 Actually, it’s still there, but as an alias, it now lives in the new annotations module. The inspect module is pretty big, so it’s expensive to load, and so this function got moved, so the load for annotation management would be lighter weight.

05:14 Next up, a bunch of small changes to how Python deals with numbers.

Become a Member to join the conversation.