What’s New In Python 3.10

[1]:
import sys
assert sys.version_info[:2] >= (3, 10)

Better error messages

Syntax Errors

  • When parsing code that contains unclosed parentheses or brackets the interpreter now includes the location of the unclosed bracket of parentheses instead of displaying SyntaxError: unexpected EOF.

  • SyntaxError exceptions raised by the interpreter will now highlight the full error range of the expression that constitutes the syntax error itself, instead of just where the problem is detected.

  • Specialised messages for SyntaxError exceptions have been added e.g. for

    • missing : before blocks

    • unparenthesised tuples in comprehensions targets

    • missing commas in collection literals and between expressions

    • missing : and values in dictionary literals

    • usage of = instead of == in comparisons

    • usage of * in f-strings

Indentation Errors

  • Many IndentationError exceptions now have more context.

Attribute Errors

  • AttributeError will offer suggestions of similar attribute names in the object that the exception was raised from.

Name Errors

  • NameError will offer suggestions of similar variable names in the function that the exception was raised from.

Structural Pattern Matching

Many functional languages have a match expression, for example Scala, Rust, F#.

A match statement takes an expression and compares it to successive patterns given as one or more case blocks. This is superficially similar to a switch statement in C, Java or JavaScript, but much more powerful.

match

The simplest form compares a subject value against one or more literals:

[2]:
def http_error(status):
      match status:
          case 400:
              return "Bad request"
          case 401:
              return "Unauthorized"
          case 403:
              return "Forbidden"
          case 404:
              return "Not found"
          case 418:
              return "I'm a teapot"
          case _:
              return "Something else"

Note:

Only in this case _ acts as a wildcard that never fails and not as a variable name.

The cases not only check for equality, but rebind variables that match the specified pattern. For example:

[3]:
NOT_FOUND = 404
retcode = 200

match retcode:
    case NOT_FOUND:
        print('not found')

print(f"Current value of {NOT_FOUND=}")
not found
Current value of NOT_FOUND=200

«If this poorly-designed feature is really added to Python, we lose a principle I’ve always taught students: ‹if you see an undocumented constant, you can always name it without changing the code’s meaning.› The Substitution Principle, learned in algebra? It’ll no longer apply.» – Brandon Rhodes

«… the semantics of this can be quite different from switch. The cases don’t simply check equality, they rebind variables that match the specified pattern.» – Jake VanderPlas

Symbolic constants

Patterns may use named constants. These must be dotted names to prevent them from being interpreted as capture variable:

[4]:
from enum import Enum

class Color(Enum):
    RED = 0
    GREEN = 1
    BLUE = 2

color = Color(2)

match color:
    case color.RED:
        print("I see red!")
    case color.GREEN:
        print("Grass is green")
    case color.BLUE:
        print("I'm feeling the blues :(")
I'm feeling the blues :(

«… “case CONSTANT” actually matching everything and assigning to a variable named CONSTANT» – Armin Ronacher