7.Simple statements

A simple statement is comprised within a single logical line. Several simplestatements may occur on a single line separated by semicolons. The syntax forsimple statements is:

simple_stmt ::=expression_stmt                |assert_stmt                |assignment_stmt                |augmented_assignment_stmt                |annotated_assignment_stmt                |pass_stmt                |del_stmt                |return_stmt                |yield_stmt                |raise_stmt                |break_stmt                |continue_stmt                |import_stmt                |future_stmt                |global_stmt                |nonlocal_stmt                |type_stmt

7.1.Expression statements

Expression statements are used (mostly interactively) to compute and write avalue, or (usually) to call a procedure (a function that returns no meaningfulresult; in Python, procedures return the valueNone). Other uses ofexpression statements are allowed and occasionally useful. The syntax for anexpression statement is:

expression_stmt ::=starred_expression

An expression statement evaluates the expression list (which may be a singleexpression).

In interactive mode, if the value is notNone, it is converted to a stringusing the built-inrepr() function and the resulting string is written tostandard output on a line by itself (except if the result isNone, so thatprocedure calls do not cause any output.)

7.2.Assignment statements

Assignment statements are used to (re)bind names to values and to modifyattributes or items of mutable objects:

assignment_stmt ::= (target_list "=")+ (starred_expression |yield_expression)target_list     ::=target (","target)* [","]target          ::=identifier                    | "(" [target_list] ")"                    | "[" [target_list] "]"                    |attributeref                    |subscription                    |slicing                    | "*"target

(See sectionPrimaries for the syntax definitions forattributeref,subscription, andslicing.)

An assignment statement evaluates the expression list (remember that this can bea single expression or a comma-separated list, the latter yielding a tuple) andassigns the single resulting object to each of the target lists, from left toright.

Assignment is defined recursively depending on the form of the target (list).When a target is part of a mutable object (an attribute reference, subscriptionor slicing), the mutable object must ultimately perform the assignment anddecide about its validity, and may raise an exception if the assignment isunacceptable. The rules observed by various types and the exceptions raised aregiven with the definition of the object types (see sectionThe standard type hierarchy).

Assignment of an object to a target list, optionally enclosed in parentheses orsquare brackets, is recursively defined as follows.

  • If the target list is a single target with no trailing comma,optionally in parentheses, the object is assigned to that target.

  • Else:

    • If the target list contains one target prefixed with an asterisk, called a“starred” target: The object must be an iterable with at least as many itemsas there are targets in the target list, minus one. The first items of theiterable are assigned, from left to right, to the targets before the starredtarget. The final items of the iterable are assigned to the targets afterthe starred target. A list of the remaining items in the iterable is thenassigned to the starred target (the list can be empty).

    • Else: The object must be an iterable with the same number of items as thereare targets in the target list, and the items are assigned, from left toright, to the corresponding targets.

Assignment of an object to a single target is recursively defined as follows.

  • If the target is an identifier (name):

    • If the name does not occur in aglobal ornonlocalstatement in the current code block: the name is bound to the object in thecurrent local namespace.

    • Otherwise: the name is bound to the object in the global namespace or theouter namespace determined bynonlocal, respectively.

    The name is rebound if it was already bound. This may cause the referencecount for the object previously bound to the name to reach zero, causing theobject to be deallocated and its destructor (if it has one) to be called.

  • If the target is an attribute reference: The primary expression in thereference is evaluated. It should yield an object with assignable attributes;if this is not the case,TypeError is raised. That object is thenasked to assign the assigned object to the given attribute; if it cannotperform the assignment, it raises an exception (usually but not necessarilyAttributeError).

    Note: If the object is a class instance and the attribute reference occurs onboth sides of the assignment operator, the right-hand side expression,a.x can accesseither an instance attribute or (if no instance attribute exists) a classattribute. The left-hand side targeta.x is always set as an instance attribute,creating it if necessary. Thus, the two occurrences ofa.x do notnecessarily refer to the same attribute: if the right-hand side expression refers to aclass attribute, the left-hand side creates a new instance attribute as the target of theassignment:

    classCls:x=3# class variableinst=Cls()inst.x=inst.x+1# writes inst.x as 4 leaving Cls.x as 3

    This description does not necessarily apply to descriptor attributes, such asproperties created withproperty().

  • If the target is a subscription: The primary expression in the reference isevaluated. It should yield either a mutable sequence object (such as a list)or a mapping object (such as a dictionary). Next, the subscript expression isevaluated.

    If the primary is a mutable sequence object (such as a list), the subscriptmust yield an integer. If it is negative, the sequence’s length is added toit. The resulting value must be a nonnegative integer less than thesequence’s length, and the sequence is asked to assign the assigned object toits item with that index. If the index is out of range,IndexError israised (assignment to a subscripted sequence cannot add new items to a list).

    If the primary is a mapping object (such as a dictionary), the subscript musthave a type compatible with the mapping’s key type, and the mapping is thenasked to create a key/value pair which maps the subscript to the assignedobject. This can either replace an existing key/value pair with the same keyvalue, or insert a new key/value pair (if no key with the same value existed).

    For user-defined objects, the__setitem__() method is called withappropriate arguments.

  • If the target is a slicing: The primary expression in the reference isevaluated. It should yield a mutable sequence object (such as a list). Theassigned object should be a sequence object of the same type. Next, the lowerand upper bound expressions are evaluated, insofar they are present; defaultsare zero and the sequence’s length. The bounds should evaluate to integers.If either bound is negative, the sequence’s length is added to it. Theresulting bounds are clipped to lie between zero and the sequence’s length,inclusive. Finally, the sequence object is asked to replace the slice withthe items of the assigned sequence. The length of the slice may be differentfrom the length of the assigned sequence, thus changing the length of thetarget sequence, if the target sequence allows it.

CPython implementation detail: In the current implementation, the syntax for targets is taken to be the sameas for expressions, and invalid syntax is rejected during the code generationphase, causing less detailed error messages.

Although the definition of assignment implies that overlaps between theleft-hand side and the right-hand side are ‘simultaneous’ (for examplea,b=b,a swaps two variables), overlapswithin the collection of assigned-tovariables occur left-to-right, sometimes resulting in confusion. For instance,the following program prints[0,2]:

x=[0,1]i=0i,x[i]=1,2# i is updated, then x[i] is updatedprint(x)

See also

PEP 3132 - Extended Iterable Unpacking

The specification for the*target feature.

7.2.1.Augmented assignment statements

Augmented assignment is the combination, in a single statement, of a binaryoperation and an assignment statement:

augmented_assignment_stmt ::=augtargetaugop (expression_list |yield_expression)augtarget                 ::=identifier |attributeref |subscription |slicingaugop                     ::= "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**="                              | ">>=" | "<<=" | "&=" | "^=" | "|="

(See sectionPrimaries for the syntax definitions of the last threesymbols.)

An augmented assignment evaluates the target (which, unlike normal assignmentstatements, cannot be an unpacking) and the expression list, performs the binaryoperation specific to the type of assignment on the two operands, and assignsthe result to the original target. The target is only evaluated once.

An augmented assignment statement likex+=1 can be rewritten asx=x+1 to achieve a similar, but not exactly equal effect. In the augmentedversion,x is only evaluated once. Also, when possible, the actual operationis performedin-place, meaning that rather than creating a new object andassigning that to the target, the old object is modified instead.

Unlike normal assignments, augmented assignments evaluate the left-hand sidebefore evaluating the right-hand side. For example,a[i]+=f(x) firstlooks-upa[i], then it evaluatesf(x) and performs the addition, andlastly, it writes the result back toa[i].

With the exception of assigning to tuples and multiple targets in a singlestatement, the assignment done by augmented assignment statements is handled thesame way as normal assignments. Similarly, with the exception of the possiblein-place behavior, the binary operation performed by augmented assignment isthe same as the normal binary operations.

For targets which are attribute references, the samecaveat about classand instance attributes applies as for regular assignments.

7.2.2.Annotated assignment statements

Annotation assignment is the combination, in a singlestatement, of a variable or attribute annotation and an optional assignment statement:

annotated_assignment_stmt ::=augtarget ":"expression                              ["=" (starred_expression |yield_expression)]

The difference from normalAssignment statements is that only a single target is allowed.

The assignment target is considered “simple” if it consists of a singlename that is not enclosed in parentheses.For simple assignment targets, if in class or module scope,the annotations are evaluated and stored in a special class or moduleattribute__annotations__that is a dictionary mapping from variable names (mangled if private) toevaluated annotations. This attribute is writable and is automaticallycreated at the start of class or module body execution, if annotationsare found statically.

If the assignment target is not simple (an attribute, subscript node, orparenthesized name), the annotation is evaluated ifin class or module scope, but not stored.

If a name is annotated in a function scope, then this name is local forthat scope. Annotations are never evaluated and stored in function scopes.

If the right hand side is present, an annotatedassignment performs the actual assignment before evaluating annotations(where applicable). If the right hand side is not present for an expressiontarget, then the interpreter evaluates the target except for the last__setitem__() or__setattr__() call.

See also

PEP 526 - Syntax for Variable Annotations

The proposal that added syntax for annotating the types of variables(including class variables and instance variables), instead of expressingthem through comments.

PEP 484 - Type hints

The proposal that added thetyping module to provide a standardsyntax for type annotations that can be used in static analysis tools andIDEs.

Changed in version 3.8:Now annotated assignments allow the same expressions in the right hand side asregular assignments. Previously, some expressions (like un-parenthesizedtuple expressions) caused a syntax error.

7.3.Theassert statement

Assert statements are a convenient way to insert debugging assertions into aprogram:

assert_stmt ::= "assert"expression [","expression]

The simple form,assertexpression, is equivalent to

if__debug__:ifnotexpression:raiseAssertionError

The extended form,assertexpression1,expression2, is equivalent to

if__debug__:ifnotexpression1:raiseAssertionError(expression2)

These equivalences assume that__debug__ andAssertionError refer tothe built-in variables with those names. In the current implementation, thebuilt-in variable__debug__ isTrue under normal circumstances,False when optimization is requested (command line option-O). The currentcode generator emits no code for anassert statement when optimization isrequested at compile time. Note that it is unnecessary to include the sourcecode for the expression that failed in the error message; it will be displayedas part of the stack trace.

Assignments to__debug__ are illegal. The value for the built-in variableis determined when the interpreter starts.

7.4.Thepass statement

pass_stmt ::= "pass"

pass is a null operation — when it is executed, nothing happens.It is useful as a placeholder when a statement is required syntactically, but nocode needs to be executed, for example:

deff(arg):pass# a function that does nothing (yet)classC:pass# a class with no methods (yet)

7.5.Thedel statement

del_stmt ::= "del"target_list

Deletion is recursively defined very similar to the way assignment is defined.Rather than spelling it out in full details, here are some hints.

Deletion of a target list recursively deletes each target, from left to right.

Deletion of a name removes the binding of that name from the local or globalnamespace, depending on whether the name occurs in aglobal statementin the same code block. If the name is unbound, aNameError exceptionwill be raised.

Deletion of attribute references, subscriptions and slicings is passed to theprimary object involved; deletion of a slicing is in general equivalent toassignment of an empty slice of the right type (but even this is determined bythe sliced object).

Changed in version 3.2:Previously it was illegal to delete a name from the local namespace if itoccurs as a free variable in a nested block.

7.6.Thereturn statement

return_stmt ::= "return" [expression_list]

return may only occur syntactically nested in a function definition,not within a nested class definition.

If an expression list is present, it is evaluated, elseNone is substituted.

return leaves the current function call with the expression list (orNone) as return value.

Whenreturn passes control out of atry statement with afinally clause, thatfinally clause is executed beforereally leaving the function.

In a generator function, thereturn statement indicates that thegenerator is done and will causeStopIteration to be raised. The returnedvalue (if any) is used as an argument to constructStopIteration andbecomes theStopIteration.value attribute.

In an asynchronous generator function, an emptyreturn statementindicates that the asynchronous generator is done and will causeStopAsyncIteration to be raised. A non-emptyreturnstatement is a syntax error in an asynchronous generator function.

7.7.Theyield statement

yield_stmt ::=yield_expression

Ayield statement is semantically equivalent to ayieldexpression. Theyield statement can be used to omit theparentheses that would otherwise be required in the equivalent yield expressionstatement. For example, the yield statements

yield<expr>yield from<expr>

are equivalent to the yield expression statements

(yield<expr>)(yield from<expr>)

Yield expressions and statements are only used when defining ageneratorfunction, and are only used in the body of the generator function. Usingyieldin a function definition is sufficient to cause that definition to create agenerator function instead of a normal function.

For full details ofyield semantics, refer to theYield expressions section.

7.8.Theraise statement

raise_stmt ::= "raise" [expression ["from"expression]]

If no expressions are present,raise re-raises theexception that is currently being handled, which is also known as theactive exception.If there isn’t currently an active exception, aRuntimeError exception is raisedindicating that this is an error.

Otherwise,raise evaluates the first expression as the exceptionobject. It must be either a subclass or an instance ofBaseException.If it is a class, the exception instance will be obtained when needed byinstantiating the class with no arguments.

Thetype of the exception is the exception instance’s class, thevalue is the instance itself.

A traceback object is normally created automatically when an exception is raisedand attached to it as the__traceback__ attribute.You can create an exception and set your own traceback in one step using thewith_traceback() exception method (which returns thesame exception instance, with its traceback set to its argument), like so:

raiseException("foo occurred").with_traceback(tracebackobj)

Thefrom clause is used for exception chaining: if given, the secondexpression must be another exception class or instance. If the secondexpression is an exception instance, it will be attached to the raisedexception as the__cause__ attribute (which is writable). If theexpression is an exception class, the class will be instantiated and theresulting exception instance will be attached to the raised exception as the__cause__ attribute. If the raised exception is not handled, bothexceptions will be printed:

>>>try:...print(1/0)...exceptExceptionasexc:...raiseRuntimeError("Something bad happened")fromexc...Traceback (most recent call last):  File"<stdin>", line2, in<module>print(1/0)~~^~~ZeroDivisionError:division by zeroThe above exception was the direct cause of the following exception:Traceback (most recent call last):  File"<stdin>", line4, in<module>raiseRuntimeError("Something bad happened")fromexcRuntimeError:Something bad happened

A similar mechanism works implicitly if a new exception is raised whenan exception is already being handled. An exception may be handledwhen anexcept orfinally clause, or awith statement, is used. The previous exception is thenattached as the new exception’s__context__ attribute:

>>>try:...print(1/0)...except:...raiseRuntimeError("Something bad happened")...Traceback (most recent call last):  File"<stdin>", line2, in<module>print(1/0)~~^~~ZeroDivisionError:division by zeroDuring handling of the above exception, another exception occurred:Traceback (most recent call last):  File"<stdin>", line4, in<module>raiseRuntimeError("Something bad happened")RuntimeError:Something bad happened

Exception chaining can be explicitly suppressed by specifyingNone inthefrom clause:

>>>try:...print(1/0)...except:...raiseRuntimeError("Something bad happened")fromNone...Traceback (most recent call last):  File"<stdin>", line4, in<module>RuntimeError:Something bad happened

Additional information on exceptions can be found in sectionExceptions,and information about handling exceptions is in sectionThe try statement.

Changed in version 3.3:None is now permitted asY inraiseXfromY.

Added the__suppress_context__ attribute to suppressautomatic display of the exception context.

Changed in version 3.11:If the traceback of the active exception is modified in anexceptclause, a subsequentraise statement re-raises the exception with themodified traceback. Previously, the exception was re-raised with thetraceback it had when it was caught.

7.9.Thebreak statement

break_stmt ::= "break"

break may only occur syntactically nested in afor orwhile loop, but not nested in a function or class definition withinthat loop.

It terminates the nearest enclosing loop, skipping the optionalelseclause if the loop has one.

If afor loop is terminated bybreak, the loop controltarget keeps its current value.

Whenbreak passes control out of atry statement with afinally clause, thatfinally clause is executed beforereally leaving the loop.

7.10.Thecontinue statement

continue_stmt ::= "continue"

continue may only occur syntactically nested in afor orwhile loop, but not nested in a function or class definition withinthat loop. It continues with the next cycle of the nearest enclosing loop.

Whencontinue passes control out of atry statement with afinally clause, thatfinally clause is executed beforereally starting the next loop cycle.

7.11.Theimport statement

import_stmt     ::= "import"module ["as"identifier] (","module ["as"identifier])*                    | "from"relative_module "import"identifier ["as"identifier]                    (","identifier ["as"identifier])*                    | "from"relative_module "import" "("identifier ["as"identifier]                    (","identifier ["as"identifier])* [","] ")"                    | "from"relative_module "import" "*"module          ::= (identifier ".")*identifierrelative_module ::= "."*module | "."+

The basic import statement (nofrom clause) is executed in twosteps:

  1. find a module, loading and initializing it if necessary

  2. define a name or names in the local namespace for the scope wheretheimport statement occurs.

When the statement contains multiple clauses (separated bycommas) the two steps are carried out separately for each clause, justas though the clauses had been separated out into individual importstatements.

The details of the first step, finding and loading modules, are described ingreater detail in the section on theimport system,which also describes the various types of packages and modules that canbe imported, as well as all the hooks that can be used to customizethe import system. Note that failures in this step may indicate eitherthat the module could not be located,or that an error occurred whileinitializing the module, which includes execution of the module’s code.

If the requested module is retrieved successfully, it will be madeavailable in the local namespace in one of three ways:

  • If the module name is followed byas, then the namefollowingas is bound directly to the imported module.

  • If no other name is specified, and the module being imported is a toplevel module, the module’s name is bound in the local namespace as areference to the imported module

  • If the module being imported isnot a top level module, then the nameof the top level package that contains the module is bound in the localnamespace as a reference to the top level package. The imported modulemust be accessed using its full qualified name rather than directly

Thefrom form uses a slightly more complex process:

  1. find the module specified in thefrom clause, loading andinitializing it if necessary;

  2. for each of the identifiers specified in theimport clauses:

    1. check if the imported module has an attribute by that name

    2. if not, attempt to import a submodule with that name and thencheck the imported module again for that attribute

    3. if the attribute is not found,ImportError is raised.

    4. otherwise, a reference to that value is stored in the local namespace,using the name in theas clause if it is present,otherwise using the attribute name

Examples:

importfoo# foo imported and bound locallyimportfoo.bar.baz# foo, foo.bar, and foo.bar.baz imported, foo bound locallyimportfoo.bar.bazasfbb# foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as fbbfromfoo.barimportbaz# foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as bazfromfooimportattr# foo imported and foo.attr bound as attr

If the list of identifiers is replaced by a star ('*'), all publicnames defined in the module are bound in the local namespace for the scopewhere theimport statement occurs.

Thepublic names defined by a module are determined by checking the module’snamespace for a variable named__all__; if defined, it must be a sequenceof strings which are names defined or imported by that module. The namesgiven in__all__ are all considered public and are required to exist. If__all__ is not defined, the set of public names includes all names foundin the module’s namespace which do not begin with an underscore character('_').__all__ should contain the entire public API. It is intendedto avoid accidentally exporting items that are not part of the API (such aslibrary modules which were imported and used within the module).

The wild card form of import —frommoduleimport* — is only allowed atthe module level. Attempting to use it in class or function definitions willraise aSyntaxError.

When specifying what module to import you do not have to specify the absolutename of the module. When a module or package is contained within anotherpackage it is possible to make a relative import within the same top packagewithout having to mention the package name. By using leading dots in thespecified module or package afterfrom you can specify how high totraverse up the current package hierarchy without specifying exact names. Oneleading dot means the current package where the module making the importexists. Two dots means up one package level. Three dots is up two levels, etc.So if you executefrom.importmod from a module in thepkg packagethen you will end up importingpkg.mod. If you executefrom..subpkg2importmod from withinpkg.subpkg1 you will importpkg.subpkg2.mod.The specification for relative imports is contained inthePackage Relative Imports section.

importlib.import_module() is provided to support applications thatdetermine dynamically the modules to be loaded.

Raises anauditing eventimport with argumentsmodule,filename,sys.path,sys.meta_path,sys.path_hooks.

7.11.1.Future statements

Afuture statement is a directive to the compiler that a particularmodule should be compiled using syntax or semantics that will be available in aspecified future release of Python where the feature becomes standard.

The future statement is intended to ease migration to future versions of Pythonthat introduce incompatible changes to the language. It allows use of the newfeatures on a per-module basis before the release in which the feature becomesstandard.

future_stmt ::= "from" "__future__" "import"feature ["as"identifier]                (","feature ["as"identifier])*                | "from" "__future__" "import" "("feature ["as"identifier]                (","feature ["as"identifier])* [","] ")"feature     ::=identifier

A future statement must appear near the top of the module. The only lines thatcan appear before a future statement are:

  • the module docstring (if any),

  • comments,

  • blank lines, and

  • other future statements.

The only feature that requires using the future statement isannotations (seePEP 563).

All historical features enabled by the future statement are still recognizedby Python 3. The list includesabsolute_import,division,generators,generator_stop,unicode_literals,print_function,nested_scopes andwith_statement. They areall redundant because they are always enabled, and only kept forbackwards compatibility.

A future statement is recognized and treated specially at compile time: Changesto the semantics of core constructs are often implemented by generatingdifferent code. It may even be the case that a new feature introduces newincompatible syntax (such as a new reserved word), in which case the compilermay need to parse the module differently. Such decisions cannot be pushed offuntil runtime.

For any given release, the compiler knows which feature names have been defined,and raises a compile-time error if a future statement contains a feature notknown to it.

The direct runtime semantics are the same as for any import statement: there isa standard module__future__, described later, and it will be imported inthe usual way at the time the future statement is executed.

The interesting runtime semantics depend on the specific feature enabled by thefuture statement.

Note that there is nothing special about the statement:

import__future__[asname]

That is not a future statement; it’s an ordinary import statement with nospecial semantics or syntax restrictions.

Code compiled by calls to the built-in functionsexec() andcompile()that occur in a moduleM containing a future statement will, by default,use the new syntax or semantics associated with the future statement. This canbe controlled by optional arguments tocompile() — see the documentationof that function for details.

A future statement typed at an interactive interpreter prompt will take effectfor the rest of the interpreter session. If an interpreter is started with the-i option, is passed a script name to execute, and the script includesa future statement, it will be in effect in the interactive session startedafter the script is executed.

See also

PEP 236 - Back to the __future__

The original proposal for the __future__ mechanism.

7.12.Theglobal statement

global_stmt ::= "global"identifier (","identifier)*

Theglobal statement causes the listed identifiers to be interpretedas globals. It would be impossible to assign to a global variable withoutglobal, although free variables may refer to globals without beingdeclared global.

Theglobal statement applies to the entire scope of a function orclass body. ASyntaxError is raised if a variable is used orassigned to prior to its global declaration in the scope.

Programmer’s note:global is a directive to the parser. Itapplies only to code parsed at the same time as theglobal statement.In particular, aglobal statement contained in a string or codeobject supplied to the built-inexec() function does not affect the codeblockcontaining the function call, and code contained in such a string isunaffected byglobal statements in the code containing the functioncall. The same applies to theeval() andcompile() functions.

7.13.Thenonlocal statement

nonlocal_stmt ::= "nonlocal"identifier (","identifier)*

When the definition of a function or class is nested (enclosed) withinthe definitions of other functions, its nonlocal scopes are the localscopes of the enclosing functions. Thenonlocal statementcauses the listed identifiers to refer to names previously bound innonlocal scopes. It allows encapsulated code to rebind such nonlocalidentifiers. If a name is bound in more than one nonlocal scope, thenearest binding is used. If a name is not bound in any nonlocal scope,or if there is no nonlocal scope, aSyntaxError is raised.

Thenonlocal statement applies to the entire scope of a function orclass body. ASyntaxError is raised if a variable is used orassigned to prior to its nonlocal declaration in the scope.

See also

PEP 3104 - Access to Names in Outer Scopes

The specification for thenonlocal statement.

Programmer’s note:nonlocal is a directive to the parserand applies only to code parsed along with it. See the note for theglobal statement.

7.14.Thetype statement

type_stmt ::= 'type'identifier [type_params] "="expression

Thetype statement declares a type alias, which is an instanceoftyping.TypeAliasType.

For example, the following statement creates a type alias:

typePoint=tuple[float,float]

This code is roughly equivalent to:

annotation-defVALUE_OF_Point():returntuple[float,float]Point=typing.TypeAliasType("Point",VALUE_OF_Point())

annotation-def indicates anannotation scope, which behavesmostly like a function, but with several small differences.

The value of thetype alias is evaluated in the annotation scope. It is not evaluated when thetype alias is created, but only when the value is accessed through the type alias’s__value__ attribute (seeLazy evaluation).This allows the type alias to refer to names that are not yet defined.

Type aliases may be made generic by adding atype parameter listafter the name. SeeGeneric type aliases for more.

type is asoft keyword.

Added in version 3.12.

See also

PEP 695 - Type Parameter Syntax

Introduced thetype statement and syntax forgeneric classes and functions.