Conditionals ============ .. toctree:: :maxdepth: 1 Indices and tables ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` Python supports the common set of conditional expressions that you will find in other languages, but enhanced slightly with some useful features. .. _section_heading-If_Statement: if Statement ------------ The syntax for the :py:keyword:`if` statement, shown below, is similar to other languages. There can be zero or more :py:keyword:`elif` clauses and zero or one :py:keyword:`else` clauses. The branch is taken if the :token:`expression` evaluates to :py:obj:`True`. .. productionlist:: if_stmt: “if” `expression` “:” : `suite` : “elif” `expression` “:” : `suite` : “else” “:” : `suite` For example:: if tigers_present: print("Running away!") elif swimming_pool_present: print("Chillin...") else: print("Looking for anything") Some simple cases can be boiled down to a conditional expression: .. productionlist:: cond_expr : expression1 "if" expression2 "else" expression3 For example:: status_string = "Running away!" if tigers_present else "Looking for tigers" .. tip:: Recall the :py:keyword:`pass` statement can be used in any branch that must be created but requires no action from the program. It is also useful to use :py:keyword:`pass` to mark out areas for further work when stubbing out code so you can keep creating the outer structure without having to think of all the inner details. .. _section_heading-Case_Statement: case Statement -------------- Python doesn't have syntax for a case statement. There have been attempts to get it added (:PEP:`275` and :PEP:`3103`) but they have failed. The reality is, since :py:keyword:`if` is cheap in Python, you can use, :py:keyword:`if` and membership testing as an alternative to a case statement. For example:: if x in (0, 2, 4, 5): print("---") elif x in (1, 56, 527): print("***") elif x in (99, 404, 38): print("%%%") else: print("~~~") Another alternative is to create a dictionary and index the dictionary for the result. For example:: def fn0(): print("Function0 called") def fn1(): print("Function1 called") def do_work(val): # Use dict to construct artificial case statement # Keys - The values to switch off of # Vals - The functions that get called case = {0: fn0, 1: fn1} # Index into the dict for function to call # and call it. case[val]() do_work(0) .. tip:: Remember, everything in Python is a an object. Functions are objects. Reference to function objects can be passed around by-name, just like references to other types of objects. This is actually a bit of a heated topic. If interested, a good discussion on this can be found `here `_. .. _section_heading-While_Loop: while Loop ---------- Python's support for the :py:keyword:`while` loop construct is similar to other languages. The :py:keyword:`while` loop is executed as long as :py:token:`expression` remains :py:obj:`True`. The :py:keyword:`break` (exit loop) and :py:keyword:`continue` (go back to top of loop) statements are supported. Python extends the :py:keyword:`while` loop with the handy addition of an optional :py:keyword:`else` clause. .. productionlist:: while_stmnt : "while" `expression` ":" : `suite` : "else" ":" : `suite` The :py:keyword:`else` clause is executed when the loop terminates normally (i.e. :py:token:`expression` is, or becomes, :py:obj:`False`), but not if the loop terminates abnormally (i.e. from using :py:keyword:`break`, :py:keyword:`return` or an exception is raised). For example:: cntr = 0 cntr_max = 10 while cntr <= cntr_max: # Discard certain select values if cntr in (1, 5): cntr += 1 continue # Process non-discarded values print(cntr) cntr += 1 else: # Print a completion message print("DONE") Would produce the following (with 1 and 5 skipped): .. code-block:: text 0 2 3 4 6 7 8 9 10 DONE .. _section_heading-For_Loop: for loop -------- Python's support for the :py:keyword:`for` loop construct is similar to other languages, except, in Python the :py:keyword:`for` loop iterates over a sequence of items, not necessarily a progression of numbers. The :py:keyword:`break` (exit loop) and :py:keyword:`continue` (go back to top of loop) statements are supported. Like the :py:keyword:`while` loop, the :py:keyword:`for` loop is also extended with the optional :py:keyword:`else` clause. .. productionlist:: for_stmt : "for" `target_list` "in" `expression_list` ":" : `suite` : "else" ":" : `suite` The :py:keyword:`else` clause is executed when the loop terminates normally (i.e. the sequence of items is exhausted), but not if the loop terminates abnormally (i.e. from using :py:keyword:`break`, :py:keyword:`return` or an exception is raised). For example: >>> for val in "Hello World": ... # Skip spaces ... if val in " " : continue ... # Print value with a trailing dash ... print(val + "-", end='') ... else: ... # Print closing message ... print(":::😊") ... H-e-l-l-o-W-o-r-l-d-:::😊 A :py:keyword:`for` loop also allows you to have multiple loop variables. Each item in :py:token:`expression_list` will be unpacked into the arguments in :py:token:`target_list`. For example: >>> items = enumerate(['a', 'b', 'c', 'd']) >>> items = list(items) [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')] >>> >>> for idx,val in items: ... print("Index: {} Value: {}".format(idx, val)) ... Index: 0 Value: a Index: 1 Value: b Index: 2 Value: c Index: 3 Value: d .. warning:: A common mistake is to modify the sequence being iterated over. Instead, iterate over a copy of it and modify the original. An easy and fast way to get a shallow copy of a sequence is using ``[:]``. For example: >>> salaries = [60000, 75000, 105000] >>> for idx,salary in enumerate(salaries[:]): ... salaries[idx] = salary + 10000 >>> print(salaries) .. _WhyNoSwitch: https://www.pydanny.com/why-doesnt-python-have-switch-case.html