v. Functions¶

Human being beings are quite limited in their ability agree distinct pieces of information in their working memories. Inquiry suggests that for most people the number of unrelated chunks is most 7. Computers, by contrast, have no difficulty managing thousands of split pieces of information without ever forgetting them or getting them confused.

To get in possible for man beings (programmers) to write complex programs that can span thousands of lines of code, programming languages take features that permit programmers to use the power of abstracton to give names to a sequence of instructions so to use the new names without having to consider the details of the instructions to which they refer.

This chapter discusses functions, 1 of Python's language features that back up this kind of brainchild.

v.one. Function definition and use¶

In the context of programming, a role is a named sequence of statements that performs a desired operation. This operation is specified in a part definition. In Python, the syntax for a part definition is:

                            def              NAME              (              Listing              OF              PARAMETERS              ):              STATEMENTS            

Yous can brand up any names you desire for the functions you create, except that you can't use a name that is a Python keyword. The list of parameters specifies what information, if any, you accept to provide in order to use the new function.

At that place can be whatsoever number of statements within the part, but they have to exist indented from the def .

Function definitions are chemical compound statements, similar to the branching and looping statements nosotros saw in the Conditionals and loops chapter, which means they have the following parts:

  1. A header, which begins with a keyword and ends with a colon.

  2. A torso consisting of i or more Python statements, each indented the aforementioned amount (4 spaces is the Python standard ) from the header.

In a role definition, the keyword in the header is def , which is followed by the name of the function and a list of parameters enclosed in parentheses. The parameter list may be empty, or information technology may contain any number of parameters. In either example, the parentheses are required.

five.ii. Building on what you learned in high school Algebra¶

Dorsum in high schoolhouse Algebera class y'all were introduced to mathematical functions. Maybe you lot were shown a diagram of a "function machine" that looked something like this:

Function machine

The idea behind this diagram is that a office is similar a machine that takes an input, x , and transforms information technology into an output, f(x) . The light yellow box f is an abstraction of the process used to do the transformation from x to f(10) .

Functions in Python can be idea of much the same style, and the similarity with functions from Algebra may help you understand them.

The following quadratic function is an example:

f(x) = 3x 2 - 2x + v

Hither is the same part in Python:

                            def              f              (              10              ):              render              3              *              10              **              2              -              2              *              x              +              five            

Defining a new function does non make the role run. To do that we need a office telephone call. Function calls comprise the name of the function being executed followed by a list of values, called arguments, which are assigned to the parameters in the function definition.

Hither is our role f being called with several different arguments:

                            >>>                            f              (              3              )              26              >>>                            f              (              0              )              v              >>>                            f              (              1              )              6              >>>                            f              (              -              1              )              x              >>>                            f              (              v              )              70            

The function definition must offset be entered into the Python shell before information technology can exist called:

                            >>>                            def              f              (              ten              ):              ...                            return              iii              *              x              **              2              -              2              *              x              +              v              ...              >>>            

Function calls involve an implicit assignment of the argument to the parameter

The relationship between the parameter and the statement in the definition and calling of a role is that of an implicit consignment. It is as if we had executed the consignment statements x = 3 , x = 0 , 10 = 1 , x = -1 , and 10 = 5 respectively before making the function calls to f in the preceding example.

5.3. The return statement¶

The return argument causes a role to immediately stop executing statements in the office body and to transport back (or return) the value after the keyword return to the calling statement.

                            >>>                            result              =              f              (              3              )              >>>                            consequence              26              >>>                            result              =              f              (              3              )              +              f              (              -              i              )              >>>                            result              36            

A render argument with no value later on it however returns a value, of a blazon we haven't seen before:

                            >>>                            def              mystery              ():              ...                            return              ...              >>>                            what_is_it              =              mystery              ()              >>>                            what_is_it              >>>                            type              (              what_is_it              )              <class 'NoneType'>              >>>                            print              (              what_is_it              )              None            

None is the sole value of Python'south NoneType . We will use it frequently after on to correspond an unknown or unassigned value. For at present yous need to exist aware that information technology is the value that is returned past a return statement without an argument.

All Python function calls return a value. If a function call finishes executing the statements in its trunk without hitting a return statement, a None value is returned from the function.

                            >>>                            def              do_nothing_useful              (              n              ,              chiliad              ):              ...                            x              =              due north              +              1000              ...                            y              =              n              -              m              ...              >>>                            do_nothing_useful              (              v              ,              3              )              >>>                            outcome              =              do_nothing_useful              (              5              ,              3              )              >>>                            upshot              >>>              >>>                            print              (              event              )              None            

Since do_nothing_useful does not have a return statement with a value, it returns a None value, which is assigned to result . None values don't display in the Python vanquish unless they are explicited printed.

Whatever statements in the body of a role after a return statement is encountered will never be executed and are referred to as dead code.

                            >>>                            def              try_to_print_dead_code              ():              ...                            print              (              "This will print..."              )              ...                            print              (              "...and so will this."              )              ...                            return              ...                            print              (              "Only non this..."              )              ...                            print              (              "considering it's expressionless code!"              )              ...              >>>                            try_to_print_dead_code              ()              This will impress...              ...and so will this.              >>>            

v.4. Flow of execution¶

In order to ensure that a function is defined before its first apply, you accept to know the gild in which statements are executed, which is chosen the flow of execution.

Execution ever begins at the first statement of the program. Statements are executed i at a time, in order from top to bottom.

Part definitions do not alter the flow of execution of the program, merely remember that statements inside the function are not executed until the function is called.

Function calls are like a detour in the catamenia of execution. Instead of going to the side by side statement, the flow jumps to the first line of the called office, executes all the statements at that place, and and so comes dorsum to pick up where information technology left off.

That sounds simple enough, until you retrieve that one function tin can call another. While in the middle of 1 part, the program might have to execute the statements in some other function. But while executing that new function, the program might accept to execute yet another function!

Fortunately, Python is practiced at keeping track of where it is, so each fourth dimension a part completes, the program picks up where information technology left off in the function that called it. When it gets to the cease of the program, it terminates.

What'due south the moral of this sordid tale? When you read a program, don't just read from top to bottom. Instead, follow the flow of execution. Expect at this program:

                            def              f1              ():              impress              (              "Moe"              )              def              f2              ():              f4              ()              print              (              "Meeny"              )              def              f3              ():              f2              ()              print              (              "Miny"              )              f1              ()              def              f4              ():              impress              (              "Eeny"              )              f3              ()            

The output of this program is:

Follow the period of execution and see if you can understand why it does that.

5.v. Encapsulation and generalization¶

Encapsulation is the process of wrapping a piece of code in a role, allowing you lot to take advantage of all the things functions are good for.

Generalization means taking something specific, such as counting the number of digits in a given positive integer, and making it more full general, such as counting the number of digits of whatever integer.

To see how this process works, let's start with a plan that counts the number of digits in the number 4203 :

                            number              =              4203              count              =              0              while              number              !=              0              :              count              +=              i              number              //=              10              print              (              count              )            

Utilize what you learned in Tracing a program to this until you feel confident you lot understand how information technology works. This plan demonstrates an important design of ciphering called a counter. The variable count is initialized to 0 then incremented each fourth dimension the loop body is executed. When the loop exits, count contains the event — the total number of times the loop trunk was executed, which is the same as the number of digits.

The start footstep in encapsulating this logic is to wrap information technology in a office:

                            def              num_digits              ():              number              =              4203              count              =              0              while              number              !=              0              :              count              +=              1              number              //=              10              render              count              print              (              num_digits              ())            

Running this program will give the states the aforementioned result as before, but this time we are calling a function. It may seem like we accept gained goose egg from doing this, since our program is longer than before and does the aforementioned affair, but the next step reveals something powerful:

                            def              num_digits              (              number              ):              count              =              0              while              number              !=              0              :              count              +=              1              number              //=              10              render              count              print              (              num_digits              (              4203              ))            

By parameterizing the value, we can at present use our logic to count the digits of any positive integer. A telephone call to print(num_digits(710)) will print three . A telephone call to impress(num_digits(1345109)) will impress vii , and and then along.

This office as well contains bugs. If we call num_digits(0) , it will return a 0 , when it should return a ane . If nosotros call num_digits(-23) , the program goes into an infinite loop. You will be asked to gear up both of these bugs as an practise.

5.half dozen. Composition¶

Simply as with mathematical functions, Python functions tin be composed, meaning that yous utilise the upshot of i function as the input to another.

                            >>>                            def              f              (              x              ):              ...                            return              2              *              10              ...              >>>                            def              g              (              x              ):              ...                            return              x              +              5              ...              >>>                            def              h              (              x              ):              ...                            render              x              **              ii              -              3              >>>                            f              (              three              )              half dozen              >>>                            1000              (              3              )              eight              >>>                            h              (              4              )              13              >>>                            f              (              g              (              3              ))              sixteen              >>>                            g              (              f              (              iii              ))              11              >>>                            h              (              f              (              thousand              (              0              )))              97              >>>            

Nosotros tin also use a variable as an argument:

                            >>>                            # Assume function definitions for f and m as in previous example              >>>                            val              =              10              >>>                            f              (              val              )              20              >>>                            f              (              k              (              val              ))              30              >>>            

Observe something very important here. The name of the variable we pass as an argument ( val ) has nothing to do with the proper noun of the parameter ( ten ). Once more, information technology is as if ten = val is executed when f(val) is called. It doesn't matter what the value was named in the caller, inside f and g its proper name is x .

5.vii. Functions are information too¶

The functions you define in Python are a blazon of data.

                            >>>                            def              f              ():              ...                            print              (              "Hello from function f!"              )              ...              >>>                            type              (              f              )              <type 'role'>              >>>                            f              ()              Hello, from function f!              >>>            

Function values can exist elements of a list. Assume f , 1000 , and h have been defined as in the Composition section above.

                            >>>                            do_stuff              =              [              f              ,              m              ,              h              ]              >>>                            for              func              in              do_stuff              :              ...                            func              (              10              )              ...              20              15              97            

As usual, you lot should trace the execution of this example until you experience confident y'all sympathize how it works.

5.8. Listing parameters¶

Passing a list as an argument actually passes a reference to the list, not a copy of the list. Since lists are mutable changes made to the parameter alter the argument equally well. For example, the function below takes a list as an argument and multiplies each chemical element in the listing by 2:

                            def              double_stuff_v1              (              a_list              ):              index              =              0              for              value              in              a_list              :              a_list              [              index              ]              =              2              *              value              index              +=              1            

To test this function, we will put information technology in a file named pure_v_modify.py , and import it into our Python shell, were we tin can experiment with it:

                            >>>                            from              pure_v_modify              import              double_stuff_v1              >>>                            things              =              [              ii              ,              5              ,              'Spam'              ,              9.5              ]              >>>                            double_stuff_v1              (              things              )              >>>                            things              [4, 10, 'SpamSpam', 19.0]            

Note

The file containing the imported code must have a .py file extention, which is not written in the import argument.

The parameter a_list and the variable things are aliases for the same object. The state diagram looks like this:

State diagram for multiple references to a list as a parameter

Since the list object is shared by 2 frames, we drew it between them.

If a function modifies a listing parameter, the caller sees the change.

5.9. Pure functions and modifiers¶

Functions which take lists as arguments and change them during execution are called modifiers and the changes they brand are called side effects.

A pure function does not produce side effects. It communicates with the calling programme only through parameters, which it does non modify, and a return value. Here is double_stuff_v2 written as a pure function:

                            def              double_stuff_v2              (              a_list              ):              new_list              =              []              for              value              in              a_list              :              new_list              +=              [              2              *              value              ]              render              new_list            

This version of double_stuff does non alter its arguments:

                            >>>                            from              pure_v_modify              import              double_stuff_v2              >>>                            things              =              [              2              ,              5              ,              'Spam'              ,              9.5              ]              >>>                            double_stuff_v2              (              things              )              [4, x, 'SpamSpam', 19.0]              >>>                            things              [2, 5, 'Spam', 9.five]              >>>            

To apply the pure function version of double_stuff to change things , you would assign the return value dorsum to things :

                            >>>                            things              =              double_stuff              (              things              )              >>>                            things              [iv, 10, 'SpamSpam', xix.0]              >>>            

five.10. Which is meliorate?¶

Annihilation that tin be done with modifiers tin too be done with pure functions. In fact, some programming languages only allow pure functions. At that place is some testify that programs that use pure functions are faster to develop and less error-prone than programs that employ modifiers. Yet, modifiers are user-friendly at times, and in some cases, functional programs are less efficient.

In general, nosotros recommend that you write pure functions whenever it is reasonable to practise so and resort to modifiers only if there is a compelling advantage. This approach might be called a functional programming style.

5.xi. Polymorphism and duck typing¶

The ability to call the same function with different types of information is called polymorphism. In Python, implementing polymorphism is easy, because Python functions handle types through duck typing. Basically, this means that as long as all the operations on a function parameter are valid, the part will handle the function call without complaint. The post-obit simple case illustrates the concept:

                            >>>                            def              double              (              thing              ):              ...                            return              ii              *              thing              ...              >>>                            double              (              v              )              10              >>>                            double              (              'Spam'              )              'SpamSpam'              >>>                            double              ([              one              ,              two              ])              [1, two, i, 2]              >>>                            double              (              3.five              )              7.0              >>>                            double              ((              'a'              ,              'b'              ))              ('a', 'b', 'a', 'b')              >>>                            double              (              None              )              Traceback (almost recent call last):              File              "<stdin>", line              one, in              <module>              File              "<stdin>", line              ii, in              double              TypeError:              unsupported operand blazon(south) for *: 'int' and 'NoneType'              >>>            

Since * is defined for integers, strings, lists, floats, and tuples, calling our double function with whatever of these types as an argument is not a problem. * is not defined for the NoneType, however, and then sending the double function a None value results in a run time error.

v.12. Two-dimensional tables¶

A two-dimensional tabular array is a table where you read the value at the intersection of a row and a cavalcade. A multiplication table is a proficient example. Let's say y'all want to print a multiplication tabular array for the values from 1 to half-dozen.

A good way to start is to write a loop that prints the multiples of 2, all on i line:

                            for              i              in              range              (              i              ,              7              ):              impress              (              2              *              i              ,              cease              =              "   "              )              print              ()            

Hither we've used the range function, just made it start its sequence at 1. As the loop executes, the value of i changes from one to half-dozen. When all the elements of the range have been assigned to i , the loop terminates. Each time through the loop, it displays the value of ii * i , followed past three spaces.

Again, the extra cease=" " statement in the print function suppresses the newline, and uses three spaces instead. After the loop completes, the call to print at line iii finishes the current line, and starts a new line.

The output of the program is:

So far, so good. The adjacent step is to encapulate and generalize.

v.13. More encapsulation¶

This office encapsulates the previous loop and generalizes it to print multiples of n :

                            def              print_multiples              (              northward              ):              for              i              in              range              (              i              ,              7              ):              print              (              n              *              i              ,              end              =              "   "              )              impress              ()            

To encapsulate, all we had to practise was add the get-go line, which declares the name of the function and the parameter list. To generalize, all we had to practice was replace the value 2 with the parameter north .

If we call this function with the argument 2, we get the aforementioned output equally before. With the statement 3, the output is:

With the argument iv, the output is:

By now you can probably gauge how to print a multiplication table — by calling print_multiples repeatedly with dissimilar arguments. In fact, we can use another loop:

                            for              i              in              range              (              1              ,              seven              ):              print_multiples              (              i              )            

Notice how similar this loop is to the one within print_multiples . All we did was replace the impress function with a function telephone call.

The output of this program is a multiplication table:

                            one      ii      3      4      5      6              two      4      half-dozen      8      x     12              3      6      9      12     fifteen     18              4      viii      12     sixteen     20     24              5      10     fifteen     20     25     30              half-dozen      12     18     24     30     36            

5.xiv. Notwithstanding more encapsulation¶

To demonstrate encapsulation again, let's take the lawmaking from the last section and wrap it up in a function:

                            def              print_mult_table              ():              for              i              in              range              (              ane              ,              7              ):              print_multiples              (              i              )            

This procedure is a common development plan. We develop code past writing lines of code exterior any function, or typing them in to the interpreter. When we get the code working, we extract it and wrap it up in a function.

This development programme is particularly useful if you don't know how to split the program into functions when you start writing. This approach lets you lot blueprint as you go along.

5.fifteen. Local variables¶

You might be wondering how we tin use the same variable, i , in both print_multiples and print_mult_table . Doesn't it cause problems when one of the functions changes the value of the variable?

The answer is no, because the i in print_multiples and the i in print_mult_table are not the same variable.

Variables created within a function definition are local; yous can't access a local variable from outside its home office. That ways you are free to accept multiple variables with the same name every bit long as they are not in the same office.

Python examines all the statements in a office — if any of them assign a value to a variable, that is the clue that Python uses to make the variable a local variable.

The stack diagram for this program shows that the two variables named i are non the same variable. They can refer to different values, and changing one does not affect the other.

Stack 2 diagram

The value of i in print_mult_table goes from i to 6. In the diagram it happens to exist 3. The adjacent time through the loop information technology will exist 4. Each time through the loop, print_mult_table calls print_multiples with the current value of i as an argument. That value gets assigned to the parameter north .

Inside print_multiples , the value of i goes from ane to 6. In the diagram, it happens to be 2. Changing this variable has no outcome on the value of i in print_mult_table .

Information technology is mutual and perfectly legal to have different local variables with the same proper noun. In detail, names like i and j are used frequently as loop variables. If yous avoid using them in one office simply because you used them somewhere else, you will probably make the programme harder to read.

5.16. Recursive data structures¶

All of the Python data types we have seen tin be grouped inside lists and tuples in a variety of means. Lists and tuples can besides exist nested, providing myriad possibilities for organizing information. The system of data for the purpose of making it easier to use is chosen a data structure.

It's ballot time and we are helping to compute the votes as they come in. Votes arriving from private wards, precincts, municipalities, counties, and states are sometimes reported as a sum total of votes and sometimes as a listing of subtotals of votes. After considering how best to store the tallies, we decide to use a nested number list, which nosotros define as follows:

A nested number list is a list whose elements are either:

  1. numbers

  2. nested number lists

Notice that the term, nested number list is used in its own definition. Recursive definitions like this are quite common in mathematics and computer science. They provide a concise and powerful way to describe recursive data structures that are partially composed of smaller and simpler instances of themselves. The definition is not circular, since at some signal nosotros will reach a listing that does non have any lists as elements.

At present suppose our job is to write a office that volition sum all of the values in a nested number list. Python has a born function which finds the sum of a sequence of numbers:

                            >>>                            sum              ([              i              ,              2              ,              8              ])              11              >>>                            sum              ((              3              ,              5              ,              8.v              ))              16.5              >>>            

For our nested number list, notwithstanding, sum volition not work:

                            >>>                            sum              ([              1              ,              2              ,              [              eleven              ,              xiii              ],              8              ])              Traceback (most recent call final):              File              "<stdin>", line              1, in              <module>              TypeError:              unsupported operand blazon(s) for +: 'int' and 'list'              >>>            

The problem is that the third chemical element of this list, [11, 13] , is itself a listing, which can not be added to ane , 2 , and eight .

5.17. Recursion¶

To sum all the numbers in our recursive nested number listing nosotros demand to traverse the list, visiting each of the elements inside its nested structure, calculation any numeric elements to our sum, and repeating this procedure with whatever elements which are lists.

Modernistic programming languages generally support recursion, which means that functions tin can call themselves within their definitions. Thanks to recursion, the Python code needed to sum the values of a nested number list is surprisingly curt:

                            def              recursive_sum              (              nested_num_list              ):              the_sum              =              0              for              element              in              nested_num_list              :              if              type              (              element              )              ==              list              :              the_sum              =              the_sum              +              recursive_sum              (              chemical element              )              else              :              the_sum              =              the_sum              +              element              return              the_sum            

The body of recursive_sum consists mainly of a for loop that traverses nested_num_list . If element is a numerical value (the else branch), it is simply added to the_sum . If element is a list, and then recursive_sum is called again, with the element every bit an argument. The statement inside the function definition in which the part calls itself is known as the recursive call.

Recursion is truly ane of the nearly beautiful and elegant tools in calculator science.

A slightly more complicated problem is finding the largest value in our nested number list:

                            def              recursive_max              (              nested_num_list              ):              """                              >>> recursive_max([2, nine, [one, 13], 8, 6])                              thirteen                              >>> recursive_max([2, [[100, 7], xc], [1, 13], viii, 6])                              100                              >>> recursive_max([2, [[13, 7], xc], [1, 100], eight, 6])                              100                              >>> recursive_max([[[13, 7], 90], 2, [1, 100], 8, six])                              100                              """              largest              =              nested_num_list              [              0              ]              while              type              (              largest              )              ==              type              ([]):              largest              =              largest              [              0              ]              for              element              in              nested_num_list              :              if              type              (              element              )              ==              blazon              ([]):              max_of_elem              =              recursive_max              (              element              )              if              largest              <              max_of_elem              :              largest              =              max_of_elem              else              :              # chemical element is not a listing              if              largest              <              element              :              largest              =              element              render              largest            

Doctests are included to provide examples of recursive_max at work.

The added twist to this problem is finding a numerical value for initializing largest . We can't just use nested_num_list[0] , since that my be either a number or a list. To solve this problem we use a while loop that assigns largest to the first numerical value no matter how deeply it is nested.

The 2 examples to a higher place each accept a base case which does not lead to a recursive call: the case where the element is a number and not a list. Without a base case, you have infinite recursion, and your program will non work. Python stops afterwards reaching a maximum recursion depth and returns a runtime fault.

Write the following in a file named infinite_recursion.py :

                            #              # infinite_recursion.py              #              def              recursion_depth              (              number              ):              print              "Recursion depth number                            %d              ."              %              number              recursion_depth              (              number              +              one              )              recursion_depth              (              0              )            

At the unix command prompt in the aforementioned directory in which you lot saved your programme, type the following:

                            python              infinite_recursion              .              py            

After watching the letters flash past, you will be presented with the end of a long traceback that ends in with the post-obit:

                            ...              File              "infinite_recursion.py"              ,              line              3              ,              in              recursion_depth              recursion_depth              (              number              +              1              )              RuntimeError              :              maximum              recursion              depth              exceeded            

Nosotros would certainly never want something similar this to happen to a user of ane of our programs, and so earlier finishing the recursion discussion, permit's see how errors like this are handled in Python.

v.xviii. Exceptions¶

Whenever a runtime fault occurs, it creates an exception. The plan stops running at this signal and Python prints out the traceback, which ends with the exception that occured.

For example, dividing by goose egg creates an exception:

                            >>>                            print              55              /              0              Traceback (most recent call last):              File              "<stdin>", line              one, in              <module>              ZeroDivisionError:              integer sectionalisation or modulo by zero              >>>            

Then does accessing a nonexistent listing item:

                            >>>                            a              =              []              >>>                            print              a              [              5              ]              Traceback (nigh recent call last):              File              "<stdin>", line              1, in              <module>              IndexError:              list index out of range              >>>            

Or trying to make an item assignment on a tuple:

                            >>>                            tup              =              (              'a'              ,              'b'              ,              'd'              ,              'd'              )              >>>                            tup              [              ii              ]              =              'c'              Traceback (nigh contempo telephone call last):              File              "<stdin>", line              one, in              <module>              TypeError:              'tuple' object does not support item assignment              >>>            

In each case, the fault message on the last line has two parts: the blazon of error earlier the colon, and specifics virtually the mistake later the colon.

Sometimes we want to execute an performance that might cause an exception, only we don't want the program to cease. We can handle the exception using the try and except statements.

For example, we might prompt the user for the name of a file and then try to open up it. If the file doesn't exist, we don't want the programme to crash; we desire to handle the exception:

                            filename              =              raw_input              (              'Enter a file name: '              )              endeavour              :              f              =              open              (              filename              ,              "r"              )              except              :              print              'There is no file named'              ,              filename            

The attempt statement executes the statements in the start block. If no exceptions occur, it ignores the except argument. If any exception occurs, it executes the statements in the except branch and then continues.

We can encapsulate this adequacy in a office: exists takes a filename and returns true if the file exists, fake if it doesn't:

                            def              exists              (              filename              ):              attempt              :              f              =              open              (              filename              )              f              .              close              ()              render              True              except              :              return              False            

Yous can employ multiple except blocks to handle unlike kinds of exceptions (run into the Errors and Exceptions lesson from Python creator Guido van Rossum's Python Tutorial for a more consummate discussion of exceptions).

If your program detects an fault condition, yous tin can make it enhance an exception. Here is an instance that gets input from the user and checks that the number is non-negative.

                            #              # learn_exceptions.py              #              def              get_age              ():              age              =              input              (              'Delight enter your age: '              )              if              historic period              <              0              :              raise              ValueError              ,              '              %s                              is non a valid historic period'              %              historic period              return              age            

The raise statement takes two arguments: the exception blazon, and specific data nearly the error. ValueError is the built-in exception which most closely matches the kind of error we want to enhance. The complete listing of built-in exceptions is found in the Built-in Exceptions section of the Python Library Reference, again by Python's creator, Guido van Rossum.

If the role that chosen get_age handles the fault, so the plan can keep; otherwise, Python prints the traceback and exits:

                            >>>                            get_age              ()              Please enter your historic period: 42              42              >>>                            get_age              ()              Please enter your age: -2              Traceback (virtually recent phone call last):              File              "<stdin>", line              1, in              <module>              File              "learn_exceptions.py", line              4, in              get_age              heighten              ValueError              ,              '              %s                              is not a valid age'              %              historic period              ValueError:              -2 is non a valid age              >>>            

The error message includes the exception type and the additional data yous provided.

Using exception handling, nosotros can now modify infinite_recursion.py so that it stops when it reaches the maximum recursion depth allowed:

                            #              # infinite_recursion.py              #              def              recursion_depth              (              number              ):              print              "Recursion depth number                            %d              ."              %              number              effort              :              recursion_depth              (              number              +              1              )              except              :              print              "Maximum recursion depth exceeded."              recursion_depth              (              0              )            

Run this version and observe the results.

5.19. Tail recursion¶

When the only matter returned from a function is a recursive call, information technology is refered to as tail recursion.

Here is a version of the countdown function from chapter 6 written using tail recursion:

                            def              countdown              (              due north              ):              if              due north              ==              0              :              print              "Blastoff!"              else              :              print              n              countdown              (              n              -              i              )            

Any computation that can be made using iteration can too be made using recursion. Here is a version of find_max written using tail recursion:

                            def              find_max              (              seq              ,              max_so_far              ):              if              not              seq              :              return              max_so_far              if              max_so_far              <              seq              [              0              ]:              render              find_max              (              seq              [              1              :],              seq              [              0              ])              else              :              return              find_max              (              seq              [              1              :],              max_so_far              )            

Tail recursion is considered a bad practice in Python, since the Python compiler does non handle optimization for tail recursive calls. The recursive solution in cases like this use more arrangement resources than the equivalent iterative solution.

v.20. Recursive mathematical functions¶

Several well known mathematical functions are defined recursively. Factorial, for example, is given the special operator, ! , and is defined by:

We can hands code this into Python:

                            def              factorial              (              northward              ):              if              n              ==              0              :              return              1              else              :              return              n              *              factorial              (              n              -              1              )            

Another well know recursive relation in mathematics is the fibonacci sequence, which is defined by:

                            fibonacci              (              0              )              =              1              fibonacci              (              1              )              =              i              fibonacci              (              n              )              =              fibonacci              (              n              -              ane              )              +              fibonacci              (              due north              -              2              )            

This can too be written easily in Python:

                            def              fibonacci              (              northward              ):              if              n              ==              0              or              north              ==              1              :              return              i              else              :              render              fibonacci              (              n              -              1              )              +              fibonacci              (              northward              -              2              )            

Calling factorial(1000) will exceed the maximum recursion depth. And try running fibonacci(35) and see how long it takes to consummate (be patient, information technology volition complete).

You will be asked to write an iterative version of factorial every bit an practise, and we volition encounter a amend mode to handle fibonacci in the next chapter.

5.21. Glossary¶

argument

A value provided to a role when the office is called. This value is assigned to the corresponding parameter in the function.

flow of execution

The social club in which statements are executed during a program run.

frame

A box in a stack diagram that represents a function call. It contains the local variables and parameters of the function.

function

A named sequence of statements that performs some useful functioning. Functions may or may not accept parameters and may or may non produce a result.

part call

A argument that executes a function. It consists of the name of the function followed by a listing of arguments enclosed in parentheses.

role composition

Using the output from i function telephone call equally the input to another.

function definition

A argument that creates a new function, specifying its name, parameters, and the statements it executes.

The first function of a compound statement. Headers brainstorm with a keyword and end with a colon (:)

local variable

A variable defined inside a function. A local variable can only be used inside its function.

None

The sole value of <class 'NoneType'>. None is often used to represent the absence of a value. Information technology is also returned past a return argument with no argument or a office that reaches the end of its torso without hitting a return statement containing a value.

parameter

A proper noun used within a office to refer to the value passed as an argument.

stack diagram

A graphical representation of a stack of functions, their variables, and the values to which they refer.

traceback

A listing of the functions that are executing, printed when a runtime error occurs. A traceback is as well normally refered to every bit a stack trace, since information technology lists the functions in the order in which they are stored in the runtime stack.