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 a
global
ornonlocal
statement 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 by
nonlocal
, 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 with
property()
.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 ::=augtarget
augop
(expression_list
|yield_expression
)augtarget ::=identifier
|attributeref
|subscription
|slicing
augop ::= "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**=" | ">>=" | "<<=" | "&=" | "^=" | "|="
(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 the
typing
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-emptyreturn
statement 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. Usingyield
in 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 anexcept
clause, 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 optionalelse
clause 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
".")*identifier
relative_module ::= "."*module
| "."+
The basic import statement (nofrom
clause) is executed in twosteps:
find a module, loading and initializing it if necessary
define a name or names in the local namespace for the scope wherethe
import
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 by
as
, 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:
find the module specified in the
from
clause, loading andinitializing it if necessary;for each of the identifiers specified in the
import
clauses:check if the imported module has an attribute by that name
if not, attempt to import a submodule with that name and thencheck the imported module again for that attribute
if the attribute is not found,
ImportError
is raised.otherwise, a reference to that value is stored in the local namespace,using the name in the
as
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.
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 the
type
statement and syntax forgeneric classes and functions.