assert
Statementpass
Statementdel
Statementreturn
Statementyield
Statementraise
Statementbreak
Statementcontinue
Statementimport
Statementglobal
Statementnonlocal
Statementif
Statementwhile
Statementfor
Statementtry
Statementwith
Statementmatch
StatementStatements and expressions form majority of any programming language. In this chapter we will study control flow related statements. We will not study async, functions or class related statements in this chapter. They will be prersented in their own chapters. It is of paramount importance to grasp these concepts in detail because they will form the major part of programs which you will write in future. We have already studied all operators in last chapter while we skipped some expressions which we will study later. A lot of it might not make sense to you but keep reading it and in the end it will all make sense.
Control flow statements form the majority of decision-making or as the name implies control flow of the logic of programs. Mostly this incldue branching using if-else or looping using a loop statement. These two types are core of control flow statements and you will do well to practice them as much as you can.
Statements can be categorized broadly in two categories: simple statements and compound statements. I will first present simple statement because they are easier to understand followed by compound statements.
A simple statement is comprised within a single logical line. Several simple statements may occur on a single line separated by semicolons. The syntax for simple 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
Expression statements are used (mostly interactively) to compute and write a value, or (usually) to call a procedure (a function that returns no meaningful result; in Python, procedures return the value None). Other uses of expression statements are allowed and occasionally useful. The syntax for an expression statement is:
expression_stmt ::= starred_expression starred_expression ::= expression | (starred_item ",")* [starred_item] starred_item ::= assignment_expression | "*" or_expr
An expression statement evaluates the expression list (which may be a single expression).
In interactive mode, if the value is not None, it is converted to a string using the built-in repr() function and the resulting string is written to standard output on a line by itself (except if the result is None, so that procedure calls do not cause any output.)
Assignment statements are used to (re)bind names to values and to modify attributes 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 Section 3.3, “Primaries” for the syntax definitions for attributeref, subscription, and slicing.)
An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.
Assignment is defined recursively depending on the form of the target (list). When a target is part of a mutable object (an attribute reference, subscription or slicing), the mutable object must ultimately perform the assignment and decide about its validity, and may raise an exception if the assignment is unacceptable. The rules observed by various types and the exceptions raised are given with the definition of the object types (see ???).
Assignment of an object to a target list, optionally enclosed in parentheses or square brackets, is recursively defined as follows.
Assignment of an object to a single target is recursively defined as follows.
TypeError
is raised. That object is then asked to
assign the assigned object to the given attribute; if it cannot perform the assignment, it raises an exception (usually
but not necessarily AttributeError
).
Note: If the object is a class instance and the attribute reference occurs on both sides of the assignment operator,
the right-hand side expression, a.x
can access either an instance attribute or (if no instance
attribute exists) a class attribute. The left-hand side target a.x
is always set as an instance
attribute, creating it if necessary. Thus, the two occurrences of a.x
do not necessarily refer to the
same attribute: if the right-hand side expression refers to a class attribute, the left-hand side creates a new
instance attribute as the target of the assignment:
class Cls: x = 3 # class variable inst = 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 as properties created with
property()
.
If the primary is a mutable sequence object (such as a list), the subscript must yield an integer. If it is negative,
the sequence’s length is added to it. The resulting value must be a nonnegative integer less than the sequence’s
length, and the sequence is asked to assign the assigned object to its item with that index. If the index is out of
range, IndexError
is raised (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 must have a type compatible with the mapping’s key type, and the mapping is then asked to create a key/datum pair which maps the subscript to the assigned object. This can either replace an existing key/value pair with the same key value, or insert a new key/value pair (if no key with the same value existed).
For user-defined objects, the __setitem__()
method is called with appropriate arguments.
CPython implementation detail: In the current implementation, the syntax for targets is taken to be the same as for expressions, and invalid syntax is rejected during the code generation phase, causing less detailed error messages.
Although the definition of assignment implies that overlaps between the left-hand side and the right-hand side are
'simultaneous' (for example a, b = b, a
swaps two variables), overlaps within the collection of assigned-to
variables occur left-to-right, sometimes resulting in confusion. For instance, the following program prints [0,
2]
:
x = [0, 1] i = 0 i, x[i] = 1, 2 # i is updated, then x[i] is updated print(x)
See also PEP 3132 which details Extended Iterable Unpacking
Augmented assignment is the combination, in a single statement, of a binary operation and an assignment statement:
augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression) augtarget ::= identifier | attributeref | subscription | slicing augop ::= "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**=" | ">>=" | "<<=" | "&=" | "^=" | "|="
(See Section 3.3, “Primaries” for the syntax definotion of last three symbols.)
An augmented assignment evaluates the target (which, unlike normal assignment statements, cannot be an unpacking) and the expression list, performs the binary operation specific to the type of assignment on the two operands, and assigns the result to the original target. The target is only evaluated once.
An augmented assignment expression like x += 1
can be rewritten as x = x + 1
to achieve a
similar, but not exactly equal effect. In the augmented version, x is only evaluated once. Also, when possible, the actual
operation is performed in-place, meaning that rather than creating a new object and assigning that to the target, the old
object is modified instead. It is always preferred to use the former syntax for faster operation.
Unlike normal assignments, augmented assignments evaluate the left-hand side before evaluating the right-hand side. For
example, a[i] += f(x)
first looks-up a[i]
, then it evaluates f(x)
and
performs the addition, and lastly, it writes the result back to a[i]
.
With the exception of assigning to tuples and multiple targets in a single statement, the assignment done by augmented assignment statements is handled the same way as normal assignments. Similarly, with the exception of the possible in-place behavior, the binary operation performed by augmented assignment is the same as the normal binary operations.
For targets which are attribute references, see note above for class and instance attributes as for regular assignments.
Annotation(specifying the type of variable in this case) assignment is the combination, in a single statement, of a variable or attribute annotation and an optional assignment statement:
annotated_assignment_stmt ::= augtarget ":" expression ["=" (starred_expression | yield_expression)]
The difference from nromal Assignment Statements is that only single target is allowed.
For simple names as assignment targets, if in class or module scope, the annotations are evaluated and stored in a special
class or module attribute __annotations__
that is a dictionary mapping from variable names (mangled if
private) to evaluated annotations. This attribute is writable and is automatically created at the start of class or module
body execution, if annotations are found statically.
For expressions as assignment targets, the annotations are evaluated if in class or module scope, but not stored.
If a name is annotated in a function scope, then this name is local for that scope. Annotations are never evaluated and stored in function scopes.
If the right hand side is present, an annotated assignment performs the actual assignment before evaluating annotations
(where applicable). If the right hand side is not present for an expression target, then the interpreter evaluates the
target except for the last __setitem__()
or __setattr__()
call.
Assert statements are a convenient way to insert debugging assertions into a program:
For example,assert_stmt ::= "assert" expression ["," expression]
assert 0 == 0 assert 0 != 1
The simple form, assert expression
, is equivalent to
if __debug__: if not expression: raise AssertionError
The extended form, assert expression1, expression2
is equivalent to
if __debug__: if not expression1: raise AssertionError(expression2)
These equivalences assume that __debug__
and AssertionError
refer to the built-in variables
with those names. In the current implementation, the built-in variable __debug__
is True
under normal circumstances, False
when optimization is requested (command line option
-O
). The current code generator emits no code for an assert statement when optimization is requested at
compile time. Note that it is unnecessary to include the source code for the expression that failed in the error message; it
will be displayed as part of the stack trace.
Assignments to __debug__
are illegal. The value for the built-in variable is determined when the interpreter
starts.
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 no code needs to be executed, for example:
def f(arg): pass # a function that does nothing (yet) class C: pass # a class with no methods (yet)
del_stmt ::= "del" target_list
Deletion is recursively defined very similar to the way assignment is defined. 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 global namespace, depending on whether the name occurs
in a global
statement in the same code block. If the name is unbound, a NameError
exception
will be raised.
Deletion of attribute references, subscriptions and slicings is passed to the primary object involved; deletion of a slicing is in general equivalent to assignment of an empty slice of the right type (but even this is determined by the sliced object).
An example is given below:
x = 5 del x #print(x) will cause NameError exception if execute l = [1, 2, 3] del l[0] print(l) # will print[2, 3] d = {"k1": "v1", "k2": "v2"} del d["k1"] # d is now {"k2": "v2"}
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, else None
is substituted.
return
leaves the current function call with the expression list (or None
) as return value.
When return
passes control out of a try
statement with a finally
clause,
that finally
clause is executed before really leaving the function.
In a generator function, the return
statement indicates that the generator is done and will cause
StopIteration
to be raised. The returned value (if any) is used as an argument to construct
StopIteration
and becomes the StopIteration.value
attribute.
In an asynchronous generator function, an empty return
statement indicates that the asynchronous generator
is done and will cause StopAsyncIteration
to be raised. A non-empty return statement is a syntax error in an
asynchronous generator function.
We will see heavy usage of the return statement when we study functions.
yield_stmt ::= yield_expression
A yield
statement is semantically equivalent to a yield
expression. The yield statement can
be used to omit the parentheses that would otherwise be required in the equivalent yield expression statement. 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 a generator function, and are only used in the body of the generator function. Using yield in a function definition is sufficient to cause that definition to create a generator function instead of a normal function.
As said in yield expression section we will study these after we have studied functions.
raise_stmt ::= "raise" [expression ["from" expression]]
If no expressions are present, y
re-raises the exception that is currently being handled, which is also
known as the active exception. If there isn't currently an active exception, a
RuntimeError
exception is raised indicating that this is an error.
Otherwise, raise
evaluates the first expression as the exception object. It must be either a subclass or an
instance of BaseException
. If it is a class, the exception instance will be obtained when needed by
instantiating the class with no arguments.
The type of the exception is the exception instance's class, the value is the instance itself.
A traceback object is normally created automatically when an exception is raised and attached to it as the
__traceback__
attribute, which is writable. You can create an exception and set your own traceback in one
step using the with_traceback()
exception method (which returns the same exception instance, with its
traceback set to its argument), like so:
raise Exception("foo occurred").with_traceback(tracebackobj)
The from
clause is used for exception chaining: if given, the second expression must be another exception
class or instance. If the second expression is an exception instance, it will be attached to the raised exception as the
__cause__
attribute (which is writable). If the expression is an exception class, the class will be
instantiated and the resulting exception instance will be attached to the raised exception as the __cause__
attribute. If the raised exception is not handled, both exceptions will be printed:
>>> try: ... print(1 / 0) ... except Exception as exc: ... raise RuntimeError("Something bad happened") from exc ... Traceback (most recent call last): File "<stdin>", line 2, in <module> ZeroDivisionError: division by zero The above exception was the direct cause of the following exception: Traceback (most recent call last): File "<stdin>", line 4, in <module> RuntimeError: Something bad happened
A similar mechanism works implicitly if a new exception is raised when an exception is already being handled. An exception
may be handled when an except
or finally
clause, or a with
statement, is
used. The previous exception is then attached as the new exception's __context__
attribute:
>>> try: ... print(1 / 0) ... except: ... raise RuntimeError("Something bad happened") ... Traceback (most recent call last): File "<stdin>", line 2, in <module> ZeroDivisionError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 4, in <module> RuntimeError: Something bad happened
Exception chaining can be explicitly suppressed by specifying None
in the from
clause:
>>> try: ... print(1 / 0) ... except: ... raise RuntimeError("Something bad happened") from None ... Traceback (most recent call last): File "<stdin>", line 4, in <module> RuntimeError: Something bad happened
We will see more about exceptions when we study try
statement and the execution model of Python.
break_stmt ::= "break"
break
may only occur syntactically nested in a for
or while
loop, but not
nested in a function or class definition within that loop.
It terminates the nearest enclosing loop, skipping the optional else
clause if the loop has one.
If a for
loop is terminated by break
, the loop control target keeps its current value.
When break
passes control out of a try
statement with a finally
clause,
that finally
clause is executed before really leaving the loop.
continue_stmt ::= "continue"
continue
may only occur syntactically nested in a for
or while
loop, but
not nested in a function or class definition within that loop. It continues with the next cycle of the nearest enclosing
loop.
When continue
passes control out of a try
statement with a finally clause, that
finally
clause is executed before really starting the next loop cycle.
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 (no from
clause) is executed in two steps:
import
statement occurs.
When the statement contains multiple clauses (separated by commas) the two steps are carried out separately for each clause,
just as though the clauses had been separated out into individual import
statements.
The steps in locating and initializing the module will be discussed later.
If the requested module is retrieved successfully, it will be made available in the local namespace in one of three ways:
as
, then the name following as is bound directly to the imported
module.
The from
form uses a slightly more complex process:
from
clause, loading and initializing it if necessary;
import
clauses:
ImportError
is raised.
Examples:
import foo # foo imported and bound locally import foo.bar.baz # foo, foo.bar, and foo.bar.baz imported, foo bound locally import foo.bar.baz as fbb # foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as fbb from foo.bar import baz # foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as baz from foo import attr # foo imported and foo.attr bound as attr
If the list of identifiers is replaced by a star ('*
'), all public names defined in the module are bound in
the local namespace for the scope where the import
statement occurs.
The public names defined by a module are determined by checking the module's namespace
for a variable named __all__
; if defined, it must be a sequence of strings which are names defined or
imported by that module. The names given in __all__
are all considered public and are required to exist. If
__all__
is not defined, the set of public names includes all names found in the module's namespace which do
not begin with an underscore character. __all__
should contain the entire public
API. It is intended to avoid accidentally exporting items that are not part of the API (such as library modules which were
imported and used within the module).
The wild card form of import — from module import *
— is only allowed at the module level. Attempting to use
it in class or function definitions will raise a SyntaxError
.
When specifying what module to import you do not have to specify the absolute name of the module. When a module or package is
contained within another package it is possible to make a relative import within the same top package without having to
mention the package name. By using leading dots in the specified module or package after from you can specify how high to
traverse up the current package hierarchy without specifying exact names. One leading dot means the current package where the
module making the import exists. Two dots means up one package level. Three dots is up two levels, etc. So if you execute
from . import mod
from a module in the pkg
package then you will end up importing
pkg.mod
. If you execute from ..subpkg2 import mod
from within pkg.subpkg1
you will import pkg.subpkg2.mod
.
importlib.import_module()
is provided to support applications that determine dynamically the modules to be
loaded.
Raises an auditing event import
with arguments module, filename, sys.path, sys.meta_path,
sys.path_hooks
.
A future statement is a directive to the compiler that a particular module should be compiled using syntax or semantics that will be available in a specified future release of Python where the feature becomes standard.
The future statement is intended to ease migration to future versions of Python that introduce incompatible changes to the language. It allows use of the new features on a per-module basis before the release in which the feature becomes standard.
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 that can appear before a future statement are:
The only feature that requires using the future statement is annotations (see PEP 563).
All historical features enabled by the future statement are still recognized by Python 3. The list includes
absolute_import, division, generators, generator_stop, unicode_literals, print_function, nested_scopes
and
with_statement
. They are all redundant because they are always enabled, and only kept for backwards
compatibility.
A future statement is recognized and treated specially at compile time: Changes to the semantics of core constructs are often implemented by generating different code. It may even be the case that a new feature introduces new incompatible syntax (such as a new reserved word), in which case the compiler may need to parse the module differently. Such decisions cannot be pushed off until 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 not known to it.
The direct runtime semantics are the same as for any import statement: there is a standard module
__future__
, described later, and it will be imported in the usual way at the time the future statement is
executed.
The interesting runtime semantics depend on the specific feature enabled by the future statement.
Note that there is nothing special about the statement:
import __future__ [as name]
That is not a future statement; it’s an ordinary import statement with no special semantics or syntax restrictions.
Code compiled by calls to the built-in functions exec()
and compile()
that occur in a
module M
containing a future statement will, by default, use the new syntax or semantics associated with
the future statement. This can be controlled by optional arguments to compile()
.
A future statement typed at an interactive interpreter prompt will take effect for 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 includes
a future statement, it will be in effect in the interactive session started after the script is executed.
See PEP 236 for more information about original proposal.
global_stmt ::= "global" identifier ("," identifier)*
The global
statement is a declaration which holds for the entire current code block. It means that the
listed identifiers are to be interpreted as globals. It would be impossible to assign to a global variable without global,
although free variables may refer to globals without being declared global.
Names listed in a global
statement must not be used in the same code block textually preceding that global
statement.
Names listed in a global
statement must not be defined as formal parameters, or as targets in
with
statements or except
clauses, or in a for
target list, class
definition, function definition, import statement, or variable annotation.
CPython implementation detail: The current implementation does not enforce some of these restrictions, but programs should not abuse this freedom, as future implementations may enforce them or silently change the meaning of the program.
Programmer's note: global
is a directive to the parser. It applies only
to code parsed at the same time as the global
statement. In particular, a global statement contained in a
string or code object supplied to the built-in exec()
function does not affect the code block containing the
function call, and code contained in such a string is unaffected by global statements in the code containing the function
call. The same applies to the eval()
and compile()
functions.
nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*
The nonlocal
statement causes the listed identifiers to refer to previously bound variables in the nearest
enclosing scope excluding globals. This is important because the default behavior for binding is to search the local
namespace first. The statement allows encapsulated code to rebind variables outside of the local scope besides the global
(module) scope.
Names listed in a nonlocal
statement, unlike those listed in a global
statement, must refer
to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot be determined
unambiguously).
Names listed in a nonlocal
statement must not collide with pre-existing bindings in the local scope.
See also PEP 3104 for full specification.
As the name implies compound statements may consist of more than one statement. They can contain one or more other statements(these can be same or different statement) inside them; the containing statement have certain effects on the contained statements. Typically they always span more than one line although it is possible to write them in one line for simple cases.
A compound statement is usually formed with one of more 'clauses'. A clause is made up of a header and a 'suite'. The clause
headers of a particular compound statement are all at the same indentation level. Each clause header starts with a uniquely
identifying keyword(like if, while
or for
) and ends with a colon(:). A clause controls a
group of statements which forms a suite. A suite can be one or more semicolon-separated simple statements on the same line as
the header, following the header's colon, or it can be one or more indented statements on lines that follow. Only the latter
form of a suite can contain nested compound statements; the following is illegal, mostly because it wouldn’t be clear to which
if clause a following else clause would belong:
if test1: if test2: print(x)
Also note that the semicolon binds tighter than the colon in this context, so that in the following example, either all or none
of the print()
calls are executed:
if x < y < z: print(x); print(y); print(z)
Summary of grammar of compound statements is given below:
compound_stmt ::= if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | match_stmt | funcdef | classdef | async_with_stmt | async_for_stmt | async_funcdef suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT statement ::= stmt_list NEWLINE | compound_stmt stmt_list ::= simple_stmt (";" simple_stmt)* [";"]
Note that statements always end in a NEWLINE
possibly followed by a DEDENT
. Also note that
optional continuation clauses always begin with a keyword that cannot start a statement, thus there are no ambiguities (the
‘dangling else
’ problem is solved in Python by requiring nested if statements to be indented). See dangling else for an example.
The formatting of the grammar rules in the following sections places each clause on a separate line for clarity.
Section 4.15, “The if
Statement” is used for conditional execution:
if_stmt ::= "if" assignment_expression ":" suite ("elif" assignment_expression ":" suite)* ["else" ":" suite]
It selects exactly one of the suites by evaluating the expressions one by one until one is found to be true (see Section 3.10, “Boolean Operators” for the definition of true and false); then that suite is executed (and no other part of the
if
d statement is executed or evaluated). If all expressions are false, the suite of the
else
clause, if present, is executed.
An example is given below:
a = 0 if a == 0: print('a is zero') if a == False: print('a is False') my_name = 'Shiv' if my_name != 'Shiv': print('What is your name?') else: print('Welcome Shiv') rate_of_inflation = 5 if rate_of_inflation <= 4: print('Inflation is under control.') elif (rate_of_inflation > 4) or (rate_of_inflation < 7): print('Inflation is bearable') else: print('Inflation is concerning!')
And the output is:
a is zero
a is False
Welcome Shiv
Inflation is bearable
elif
case. The print
statements in the
example form the suite of the if
statement grammar.
The while
statement is used for repeated execution as long as an expression is true:
while_stmt ::= "while" assignment_expression ":" suite ["else" ":" suite]
This repeatedly tests the expression and, if it is true, executes the first suite; if the expression is false (which may be
the first time it is tested) the suite of the else
clause, if present, is executed and the loop terminates.
A break
statement executed in the first suite terminates the loop without executing the
else
clause's suite. A continue
statement executed in the first suite skips the rest of the
suite and goes back to testing the expression.
Some examples are given below:
You can see in following example that x
is initialized with 0
and while
loop tests whether x
is less that 11
. If this test passes then x
is
printed and incremented by 1
. Clearly, it will print 1
through 10
and when
x
becomes 11
the loop terminates.
>>> x = 0 >>> while x < 11: ... print(x) ... x += 1 ... 0 1 2 3 4 5 6 7 8 9 10 >>> x = 0
Similar to previous example with added if
statement which tests if x
is greater than
5
and if true the break
statement terminates the loop. The value of x
will
be 6
after the loop.
>>> while x < 11: ... print(x) ... x += 1 ... if x > 5: ... break ... 0 1 2 3 4 5
Here we used continue
to not execute print
function. Also, at the end of this loop the
value of x
will be 11
.
>>> x = 0 >>> while x < 11: ... x += 1 ... if x > 5: ... continue ... print(x) ... 1 2 3 4 5
Here the initial test itself will fail so else
clause is executed.
>>> x = 0 >>> while x > 0: ... print(x) ... else: ... print(x + 1) ... 1
Nested while
loop example to print tables of 1
and 2
. Notice how the loops
are nested with indentation and usage of format string to print the tables.
>>> i = 1 >>> while i < 3: ... j = 1 ... while j < 11: ... print(f"{i}*{j} = {i * j}") ... j += 1 ... i += 1 ... 1*1 = 1 1*2 = 2 1*3 = 3 1*4 = 4 1*5 = 5 1*6 = 6 1*7 = 7 1*8 = 8 1*9 = 9 1*10 = 10 2*1 = 2 2*2 = 4 2*3 = 6 2*4 = 8 2*5 = 10 2*6 = 12 2*7 = 14 2*8 = 16 2*9 = 18 2*10 = 20
The for statement is used to iterate over the elements of a sequence (such as a string, tuple or list) or other iterable object:
for_stmt ::= "for" target_list "in" expression_list ":" suite ["else" ":" suite]
The expression list is evaluated once; it should yield an iterable object. An iterator is created for the result of the
expression_list
. The suite is then executed once for each item provided by the iterator, in the order
returned by the iterator. Each item in turn is assigned to the target list using the standard rules for assignments (see
Assignment Statements), and then the suite is executed. When the items are exhausted (which is immediately
when the sequence is empty or an iterator raises a StopIteration
exception), the suite in the else clause,
if present, is executed, and the loop terminates.
A break
statement executed in the first suite terminates the loop without executing the
else
clause's suite. A continue
statement executed in the first suite skips the rest of the
suite and continues with the next item, or with the else
clause if there is no next item.
The for-loop makes assignments to the variables in the target list. This overwrites all previous assignments to those variables including those made in the suite of the for-loop:
for i in range(10): print(i) i = 5 # this will not affect the for-loop # because i will be overwritten with the next # index in the range
Names in the target list are not deleted when the loop is finished, but if the sequence is empty, they will not have been
assigned to at all by the loop. Hint: the built-in function range()
returns an iterator of integers suitable
to emulate the effect of Pascal's for i := a to b do;
e.g., list(range(3))
returns the list
[0, 1, 2]
.
Since range
is most commonly used function it, let us study it a bit. It comes in four forms:
range(end), range(start,end)
and range(start,end,step)
where start, end,
step
are all integers. range(end)
is an
iterator with starting value 0
and ending with start - 1
i.e. it is a half-close half-open
interval. The value of integers will increase by 1
for next value. For range(start, end)
it
start with start
and ends with end - 1
. If start
is greater than
end
then it returns an empty iterable i.e. if used with a for
loop then loop body will not
execute. range(start, end, step)
is like earlier but in this case the value increases/decreases by
step
value.
Let us go through some examples:
>>> for i in range(11): ... print(i) ... 0 1 2 3 4 5 6 7 8 9 10
Like the while
loop we can use continue
to not execute print
function.
>>> for x in range(0, 11): ... if x > 5: ... continue ... print(x) ... 0 1 2 3 4 5
Similar to while
example, we can use break
statement to terminate the loop:
>>> for i in range(11): ... print(i) ... if i > 5: ... break ... 0 1 2 3 4 5 6
The table example is rewritten below to demonstrate nested for
loop:
The>>> for i in range(1,3): ... for j in range(1,11): ... print(f'{i}*{j} = {i*j}') ... 1*1 = 1 1*2 = 2 1*3 = 3 1*4 = 4 1*5 = 5 1*6 = 6 1*7 = 7 1*8 = 8 1*9 = 9 1*10 = 10 2*1 = 2 2*2 = 4 2*3 = 6 2*4 = 8 2*5 = 10 2*6 = 12 2*7 = 14 2*8 = 16 2*9 = 18 2*10 = 20
else
clause example:
>>> for i in range(2,1): ... print(i) ... else: ... print('for loop did not execute') ... for loop did not execute
Another example to demonstrate step of range
.
>>> for i in range(0,11,2): ... print(i) ... 0 2 4 6 8 10
We are going to study exceptions in their own chapter and will study this there.
The with
statement is used to wrap the execution of a block with methods defined by a context manager (see
section With Statement Context Managers). This allows common try…except…finally
usage patterns to be
encapsulated for convenient reuse.
with_stmt ::= "with" ( "(" with_stmt_contents ","? ")" | with_stmt_contents ) ":" suite with_stmt_contents ::= with_item ("," with_item)* with_item ::= expression ["as" target]
The execution of the with
statement with one "item" proceeds as follows:
with_item
) is evaluated to obtain a context manager.
__enter__()
is loaded for later use.
__exit__()
is loaded for later use.
__enter__()
method is invoked.
with
statement, the return value from __enter__()
is
assigned to it.[1]__exit__()
method is invoked. If an exception caused the suite to be exited, its
type, value, and traceback are passed as arguments to __exit__()
. Otherwise, three None arguments are
supplied.
If the suite was exited due to an exception, and the return value from the __exit__()
method was false,
the exception is reraised. If the return value was true, the exception is suppressed, and execution continues with the
statement following the with
statement.
If the suite was exited for any reason other than an exception, the return value from __exit__()
is
ignored, and execution proceeds at the normal location for the kind of exit that was taken.
The following code:
with EXPRESSION as TARGET: SUITE
is semantically equivalent to:
manager = (EXPRESSION) enter = type(manager).__enter__ exit = type(manager).__exit__ value = enter(manager) hit_except = False try: TARGET = value SUITE except: hit_except = True if not exit(manager, *sys.exc_info()): raise finally: if not hit_except: exit(manager, None, None, None)
With more than one item, the context managers are processed as if multiple with
statements were nested:
with A() as a, B() as b: SUITE
is semantically equivalent to:
with A() as a: with B() as b: SUITE
You can also write multi-item context managers in multiple lines if the items are surrounded by parentheses. For example:
with ( A() as a, B() as b, ): SUITE
See also PEP 343 for more on with statement.
This is new in version 3.10. The match statement is used for pattern matching. Syntax:
match_stmt ::= 'match' subject_expr ":" NEWLINE INDENT case_block+ DEDENT subject_expr ::= star_named_expression "," star_named_expressions? | named_expression case_block ::= 'case' patterns [guard] ":" block
The match
and case
keywords are soft keywords.
Pattern matching takes a pattern as input (following case
) and a subject value (following
match
). The pattern (which may contain subpatterns) is matched against the subject value. The outcomes are:
See PEP 634 for full specification.
Here’s an overview of the logical flow of a match statement:
subject_expr
is evaluated and a resulting subject value obtained. If the subject
expression contains a comma, a tuple is constructed using the standard rules.
case_block
is attempted to match with the subject value. The specific rules for
success or failure are described below. The match attempt can also bind some or all of the standalone names within the
pattern. The precise pattern binding rules vary per pattern type and are specified below. Name
bindings made during a successful pattern match outlive the executed block and can be used after the match
statement.[2]block
inside case_block
is
executed.
case_block
is attempted as described above.
A simple match statement:
>>> flag = False >>> match (100, 200): ... case (100, 300): # Mismatch: 200 != 300 ... print('Case 1') ... case (100, 200) if flag: # Successful match, but guard fails ... print('Case 2') ... case (100, y): # Matches and binds y to 200 ... print(f'Case 3, y: {y}') ... case _: # Pattern not attempted ... print('Case 4, I match anything!') ... Case 3, y: 200
In this case, if flag
is a guard. Read more about that in the next section.
guard ::= "if" named_expression
A guard
(which is part of the case
) must succeed for code inside the case block to
execute. It takes the form: if
followed by an expression.
The logical flow of a case
block with a guard
follows:
case
block succeeded. If the pattern failed, the guard
is not evaluated and the next case
block is checked.
guard
.
guard
condition evaluates as true, the case block is selected.
guard
condition evaluates as false, the case block is not selected.
guard
raises an exception during evaluation, the exception bubbles up.
Guards are allowed to have side effects as they are expressions. Guard evaluation must proceed from the first to the last case block, one at a time, skipping case blocks whose pattern(s) don't all succeed. (I.e., guard evaluation must happen in order.) Guard evaluation must stop once a case block is selected.
An irrefutable case block is a match-all case block. A match statement may have at most one irrefutable case block, and it must be last.
A case block is considered irrefutable if it has no guard and its pattern is irrefutable. A pattern is considered irrefutable if we can prove from its syntax alone that it will always succeed. Only the following patterns are irrefutable:
patterns ::= open_sequence_pattern | pattern pattern ::= as_pattern | or_pattern closed_pattern ::= | literal_pattern | capture_pattern | wildcard_pattern | value_pattern | group_pattern | sequence_pattern | mapping_pattern | class_pattern
The descriptions below will include a description "in simple terms" of what a pattern does for illustration purposes (credits to Raymond Hettinger for a document that inspired most of the descriptions). Note that these descriptions are purely for illustration purposes and may not reflect the underlying implementation. Furthermore, they do not cover all valid forms.
An OR pattern is two or more patterns separated by vertical bars |
. Syntax:
or_pattern ::= "|".closed_pattern+
Only the final subpattern may be irrefutable, and each subpattern must bind the same set of names to avoid ambiguity.
An OR pattern matches each of its subpatterns in turn to the subject value, until one succeeds. The OR pattern is then considered successful. Otherwise, if none of the subpatterns succeed, the OR pattern fails.
In simple terms, P1 | P2 | ...
will try to match P1
, if it fails it will try to match
P2
, succeeding immediately if any succeeds, failing otherwise.
An AS pattern matches an OR pattern on the left of the as keyword against a subject. Syntax:
as_pattern ::= or_pattern "as" capture_pattern
If the OR pattern fails, the AS pattern fails. Otherwise, the AS pattern binds the subject to the name on the right of
the as keyword and succeeds. capture_pattern
cannot be a a _
.
In simple terms P as NAME
will match with P
, and on success it will set NAME =
<subject>
.
literal_pattern ::= signed_number | signed_number "+" NUMBER | signed_number "-" NUMBER | strings | "None" | "True" | "False" | signed_number: NUMBER | "-" NUMBER
The rule strings
and the token NUMBER
are defined in the standard Python
grammar. Triple-quoted strings are supported. Raw strings and byte strings are supported. Formatted string literals are
not supported.
The forms signed_number '+
' NUMBER and signed_number '-
' NUMBER
are
for expressing complex numbers; they require a real number on the left and an imaginary number on the
right. E.g. 3 + 4j
.
In simple terms, LITERAL
will succeed only if <subject> == LITERAL
. For the
singletons None, True
and False
, the is
operator is used.
A capture pattern binds the subject value to a name. Syntax:
capture_pattern ::= !'_' NAME
A single underscore is not a capture pattern (this is what !'_'
expresses). It is instead treated as a
wildcard_pattern
.
In a given pattern, a given name can only be bound once. E.g. case x, x: ...
is invalid while
case [x] | x: ...
is allowed.
Capture patterns always succeed. The binding follows scoping rules established by the assignment expression operator in
PEP 572; the name becomes a
local variable in the closest containing function scope unless there's an applicable global
or
nonlocal
statement.
In simple terms NAME
will always succeed and it will set NAME = <subject>
.
A wildcard pattern always succeeds (matches anything) and binds no name. Syntax:
wildcard_pattern ::= '_'
_
is a soft keyword within any pattern, but only within patterns. It is an identifier, as usual, even
within match
subject expressions, guards
, and case
blocks.
In simple terms, _
will always succeed.
A value pattern represents a named value in Python. Syntax:
value_pattern ::= attr attr ::= name_or_attr "." NAME name_or_attr ::= attr | NAME
The dotted name in the pattern is looked up using standard Python name resolution rules. The pattern succeeds if the
value found compares equal to the subject value (using the ==
equality operator).
In simple terms NAME1.NAME2
will succeed only if <subject> == NAME1.NAME2
If the same value occurs multiple times in the same match statement, the interpreter may cache the first value found and reuse it rather than repeat the same lookup. This cache is strictly tied to a given execution of a given match statement.
A group pattern allows users to add parentheses around patterns to emphasize the intended grouping. Otherwise, it has no additional syntax. Syntax:
group_pattern ::= "(" pattern ")"
In simple terms (P)
has the same effect as P
.
A sequence pattern contains several subpatterns to be matched against sequence elements. The syntax is similar to the unpacking of a list or tuple.
sequence_pattern ::= "[" [maybe_sequence_pattern] "]" | "(" [open_sequence_pattern] ")" open_sequence_pattern ::= maybe_star_pattern "," [maybe_sequence_pattern] maybe_sequence_pattern ::= ",".maybe_star_pattern+ ","? maybe_star_pattern ::= star_pattern | pattern star_pattern ::= "*" (capture_pattern | wildcard_pattern)
There is no difference if parentheses or square brackets are used for sequence patterns (i.e. (...)
vs
[...]
).
A single pattern enclosed in parentheses without a trailing comma (e.g. (3 | 4)
) is a group
pattern. While a single pattern enclosed in square brackets (e.g. [3 | 4]
) is still a sequence
pattern.
At most one star subpattern may be in a sequence pattern. The star subpattern may occur in any position. If no star subpattern is present, the sequence pattern is a fixed-length sequence pattern; otherwise it is a variable-length sequence pattern.
The following is the logical flow for matching a sequence pattern against a subject value:
Subject values of type str, bytes
and bytearray
do not match sequence patterns.
str, bytes
or bytearray
the sequence pattern
fails.
If the sequence pattern is fixed-length:
Otherwise, if the sequence pattern is variable-length:
The length of the subject sequence is obtained via len()
(i.e. via the
__len__()
protocol). This length may be cached by the interpreter in a similar manner as value
patterns.
In simple terms {KEY1: P1, KEY2: P2, ... }
matches only if all the following happens:
<subject>
is a mapping
KEY1 in <subject>
P1
matches <subject>[KEY1]
What we have not discussed here is function definitions, class definitions, async for
and async
with
statements.
[1] The with statement guarantees that if the __enter__()
method returns without an
error, then __exit__()
will always be called. Thus, if an error occurs during the assignment to the target
list, it will be treated the same as an error occurring within the suite would be.
[2] During failed pattern matches, some subpatterns may succeed. Do not rely on bindings being made for a failed match. Conversely, do not rely on variables remaining unchanged after a failed match. The exact behavior is dependent on implementation and may vary. This is an intentional decision made to allow different implementations to add optimizations.
[3] In pattern matching, a sequence is defined as one of the following:
collections.abc.Sequence
collections.abc.Sequence
Py_TPFLAGS_SEQUENCE
bit set
The following standard library classes are sequences:
array.array
collections.deque
list
memoryview
range
tuple
© 2022 Shiv S. Dayal. www.ashtavakra.org. GNU FDL license v1.3 or later is applicable where not stated.