five. Functions¶

Human beings are quite express in their power hold distinct pieces of information in their working memories. Research suggests that for most people the number of unrelated chunks is about seven. Computers, past contrast, accept no difficulty managing thousands of carve up pieces of information without always forgetting them or getting them confused.

To make it possible for human beings (programmers) to write circuitous programs that can span thousands of lines of code, programming languages have features that permit programmers to use the power of abstracton to requite names to a sequence of instructions and and so to use the new names without having to consider the details of the instructions to which they refer.

This chapter discusses functions, one of Python's language features that support this kind of abstraction.

5.1. Role definition and use¶

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

                            def              Proper name              (              Listing              OF              PARAMETERS              ):              STATEMENTS            

Y'all can make up any names yous want for the functions you lot create, except that yous tin't use a proper noun 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.

There can be whatsoever number of statements inside the function, just they have to exist indented from the def .

Part definitions are compound statements, like to the branching and looping statements we 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 body consisting of one or more Python statements, each indented the aforementioned corporeality (4 spaces is the Python standard ) from the header.

In a function definition, the keyword in the header is def , which is followed by the proper name of the function and a list of parameters enclosed in parentheses. The parameter list may be empty, or it may comprise whatever number of parameters. In either instance, the parentheses are required.

5.2. Building on what you learned in high school Algebra¶

Dorsum in high schoolhouse Algebera grade you were introduced to mathematical functions. Perchance you were shown a diagram of a "function automobile" that looked something like this:

Function machine

The idea backside this diagram is that a office is like a machine that takes an input, 10 , and transforms it into an output, f(x) . The light yellowish box f is an brainchild of the process used to practise the transformation from ten to f(ten) .

Functions in Python can be thought of much the same way, and the similarity with functions from Algebra may assistance you lot understand them.

The following quadratic office is an example:

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

Here is the same part in Python:

                            def              f              (              10              ):              return              3              *              x              **              2              -              2              *              10              +              5            

Defining a new function does non make the function run. To do that we demand a function call. Function calls contain the name of the function existence executed followed by a listing of values, called arguments, which are assigned to the parameters in the function definition.

Here is our role f existence called with several unlike arguments:

                            >>>                            f              (              3              )              26              >>>                            f              (              0              )              5              >>>                            f              (              1              )              6              >>>                            f              (              -              ane              )              10              >>>                            f              (              five              )              70            

The function definition must showtime be entered into the Python crush earlier it tin be called:

                            >>>                            def              f              (              ten              ):              ...                            render              3              *              x              **              two              -              two              *              x              +              5              ...              >>>            

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

The relationship between the parameter and the argument in the definition and calling of a function is that of an implicit assignment. It is equally if we had executed the assignment statements x = 3 , ten = 0 , x = i , x = -1 , and x = v respectively before making the function calls to f in the preceding example.

5.3. The render argument¶

The return argument causes a office to immediately stop executing statements in the function body and to ship dorsum (or return) the value later the keyword return to the calling statement.

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

A return statement with no value after it still returns a value, of a type nosotros 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's NoneType . We will use information technology frequently later on to represent an unknown or unassigned value. For now y'all need to exist enlightened that it is the value that is returned by a return statement without an argument.

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

                            >>>                            def              do_nothing_useful              (              due north              ,              thousand              ):              ...                            x              =              north              +              m              ...                            y              =              due north              -              thou              ...              >>>                            do_nothing_useful              (              5              ,              3              )              >>>                            outcome              =              do_nothing_useful              (              5              ,              3              )              >>>                            result              >>>              >>>                            print              (              result              )              None            

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

Whatsoever statements in the body of a part subsequently a render statement is encountered will never be executed and are referred to as dead code.

                            >>>                            def              try_to_print_dead_code              ():              ...                            impress              (              "This will impress..."              )              ...                            print              (              "...and and so volition this."              )              ...                            return              ...                            impress              (              "Only non this..."              )              ...                            impress              (              "because it's dead code!"              )              ...              >>>                            try_to_print_dead_code              ()              This will print...              ...and and then will this.              >>>            

v.iv. Flow of execution¶

In order to ensure that a function is divers before its start use, you take to know the society in which statements are executed, which is called the menstruation of execution.

Execution ever begins at the beginning argument of the program. Statements are executed one at a time, in order from top to lesser.

Function definitions practice not alter the flow of execution of the program, simply remember that statements inside the role are not executed until the role is called.

Function calls are like a detour in the flow of execution. Instead of going to the adjacent statement, the menstruum jumps to the kickoff line of the called part, executes all the statements there, and then comes back to selection up where information technology left off.

That sounds simple enough, until you remember that one function tin can call another. While in the heart of one function, the program might take to execute the statements in another function. But while executing that new function, the program might have to execute yet another function!

Fortunately, Python is practiced at keeping track of where information technology is, and then each time a part completes, the program picks up where it left off in the function that called it. When it gets to the end of the plan, it terminates.

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

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

The output of this program is:

Follow the menses of execution and come across if you lot can empathise why it does that.

five.5. Encapsulation and generalization¶

Encapsulation is the process of wrapping a piece of lawmaking in a function, assuasive yous to accept 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 information technology more general, such as counting the number of digits of any integer.

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

                            number              =              4203              count              =              0              while              number              !=              0              :              count              +=              1              number              //=              ten              print              (              count              )            

Apply what you learned in Tracing a program to this until you lot feel confident you understand how it works. This program demonstrates an of import pattern of computation called a counter. The variable count is initialized to 0 and then incremented each time the loop body is executed. When the loop exits, count contains the upshot — the full number of times the loop body was executed, which is the same every bit the number of digits.

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

                            def              num_digits              ():              number              =              4203              count              =              0              while              number              !=              0              :              count              +=              1              number              //=              ten              return              count              impress              (              num_digits              ())            

Running this program will give us the aforementioned upshot as before, but this fourth dimension we are calling a function. It may seem similar nosotros have gained null from doing this, since our program is longer than before and does the same thing, but the next step reveals something powerful:

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

By parameterizing the value, we can now use our logic to count the digits of whatever positive integer. A telephone call to print(num_digits(710)) will print iii . A call to print(num_digits(1345109)) will print 7 , and and so forth.

This function besides contains bugs. If nosotros call num_digits(0) , information technology will render a 0 , when it should return a one . If we call num_digits(-23) , the programme goes into an infinite loop. Yous will be asked to fix both of these bugs as an exercise.

5.6. Limerick¶

Only every bit with mathematical functions, Python functions can be composed, significant that yous utilize the effect of i function as the input to another.

                            >>>                            def              f              (              x              ):              ...                            return              2              *              x              ...              >>>                            def              g              (              ten              ):              ...                            return              x              +              5              ...              >>>                            def              h              (              x              ):              ...                            return              ten              **              2              -              3              >>>                            f              (              3              )              vi              >>>                            k              (              3              )              8              >>>                            h              (              4              )              thirteen              >>>                            f              (              chiliad              (              3              ))              16              >>>                            m              (              f              (              3              ))              11              >>>                            h              (              f              (              g              (              0              )))              97              >>>            

Nosotros can likewise utilise a variable as an argument:

                            >>>                            # Assume role definitions for f and g as in previous case              >>>                            val              =              10              >>>                            f              (              val              )              20              >>>                            f              (              g              (              val              ))              30              >>>            

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

five.vii. Functions are data too¶

The functions y'all ascertain in Python are a blazon of data.

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

Part values can be elements of a list. Assume f , g , and h take been defined equally in the Composition section above.

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

As usual, you should trace the execution of this example until you feel confident you sympathize how it works.

five.viii. List parameters¶

Passing a list as an statement actually passes a reference to the list, not a re-create of the list. Since lists are mutable changes made to the parameter modify the argument as well. For case, the function below takes a list as an argument and multiplies each element in the listing by 2:

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

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

                            >>>                            from              pure_v_modify              import              double_stuff_v1              >>>                            things              =              [              2              ,              5              ,              'Spam'              ,              9.5              ]              >>>                            double_stuff_v1              (              things              )              >>>                            things              [four, x, 'SpamSpam', 19.0]            

Note

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

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

State diagram for multiple references to a list as a parameter

Since the listing object is shared by two frames, we drew it betwixt them.

If a office 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 furnishings.

A pure function does not produce side effects. It communicates with the calling program simply through parameters, which it does not modify, and a return value. Here is double_stuff_v2 written every bit 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 not modify its arguments:

                            >>>                            from              pure_v_modify              import              double_stuff_v2              >>>                            things              =              [              2              ,              v              ,              'Spam'              ,              ix.5              ]              >>>                            double_stuff_v2              (              things              )              [4, 10, 'SpamSpam', nineteen.0]              >>>                            things              [2, v, 'Spam', 9.5]              >>>            

To use the pure part version of double_stuff to modify things , you would assign the return value back to things :

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

5.x. Which is better?¶

Anything that can be washed with modifiers can also exist done with pure functions. In fact, some programming languages simply allow pure functions. There is some evidence that programs that use pure functions are faster to develop and less error-prone than programs that use modifiers. However, modifiers are convenient at times, and in some cases, functional programs are less efficient.

In full general, we recommend that you write pure functions whenever it is reasonable to do then and resort to modifiers just if in that location is a compelling advantage. This approach might be chosen a functional programming style.

5.11. Polymorphism and duck typing¶

The ability to telephone call the same function with unlike types of data is called polymorphism. In Python, implementing polymorphism is easy, because Python functions handle types through duck typing. Basically, this means that as long every bit all the operations on a function parameter are valid, the part will handle the part call without complaint. The following simple example illustrates the concept:

                            >>>                            def              double              (              thing              ):              ...                            render              2              *              thing              ...              >>>                            double              (              five              )              10              >>>                            double              (              'Spam'              )              'SpamSpam'              >>>                            double              ([              ane              ,              2              ])              [1, two, 1, 2]              >>>                            double              (              3.5              )              7.0              >>>                            double              ((              'a'              ,              'b'              ))              ('a', 'b', 'a', 'b')              >>>                            double              (              None              )              Traceback (most recent call last):              File              "<stdin>", line              1, in              <module>              File              "<stdin>", line              2, in              double              TypeError:              unsupported operand type(s) for *: 'int' and 'NoneType'              >>>            

Since * is defined for integers, strings, lists, floats, and tuples, calling our double function with whatsoever of these types every bit an argument is non a problem. * is not defined for the NoneType, nonetheless, so sending the double office a None value results in a run time fault.

5.12. Two-dimensional tables¶

A two-dimensional tabular array is a table where you lot read the value at the intersection of a row and a column. A multiplication table is a practiced example. Let'southward say y'all want to impress a multiplication table for the values from 1 to 6.

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

                            for              i              in              range              (              one              ,              vii              ):              print              (              two              *              i              ,              end              =              "   "              )              impress              ()            

Hither we've used the range role, but made information technology start its sequence at i. Equally the loop executes, the value of i changes from 1 to 6. When all the elements of the range have been assigned to i , the loop terminates. Each fourth dimension through the loop, information technology displays the value of two * i , followed past 3 spaces.

Once again, the extra stop=" " argument in the print function suppresses the newline, and uses three spaces instead. Afterward the loop completes, the call to print at line iii finishes the current line, and starts a new line.

The output of the programme is:

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

5.xiii. More encapsulation¶

This part encapsulates the previous loop and generalizes information technology to print multiples of northward :

                            def              print_multiples              (              n              ):              for              i              in              range              (              1              ,              vii              ):              print              (              n              *              i              ,              finish              =              "   "              )              print              ()            

To encapsulate, all we had to exercise was add the outset line, which declares the name of the function and the parameter list. To generalize, all we had to exercise was supplant the value 2 with the parameter n .

If we phone call this role with the argument 2, nosotros get the same output as earlier. With the argument 3, the output is:

With the argument 4, the output is:

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

                            for              i              in              range              (              i              ,              7              ):              print_multiples              (              i              )            

Observe how like this loop is to the one inside print_multiples . All we did was replace the impress function with a part phone call.

The output of this programme is a multiplication table:

                            one      2      three      4      5      half dozen              2      4      six      viii      ten     12              three      half dozen      9      12     15     18              4      viii      12     16     20     24              5      10     xv     20     25     thirty              6      12     18     24     xxx     36            

5.14. Withal more encapsulation¶

To demonstrate encapsulation again, let's accept the code from the last department and wrap it up in a function:

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

This process is a common development plan. We develop lawmaking by writing lines of code outside any function, or typing them in to the interpreter. When we become the code working, we extract it and wrap it up in a function.

This development plan is peculiarly useful if you don't know how to split up the program into functions when you start writing. This approach lets yous design as you become along.

5.15. Local variables¶

Yous might be wondering how nosotros tin use the same variable, i , in both print_multiples and print_mult_table . Doesn't it cause bug when ane 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 inside a function definition are local; you tin't access a local variable from outside its home function. That means you are costless to have multiple variables with the same name as long as they are not in the same role.

Python examines all the statements in a function — if whatever of them assign a value to a variable, that is the clue that Python uses to brand the variable a local variable.

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

Stack 2 diagram

The value of i in print_mult_table goes from one to 6. In the diagram it happens to be 3. The next fourth dimension through the loop it will be 4. Each fourth dimension 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 n .

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

It is common and perfectly legal to have different local variables with the same name. In particular, names similar i and j are used frequently equally loop variables. If you avert using them in i function just because you used them somewhere else, you lot will probably make the programme harder to read.

5.16. Recursive data structures¶

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

It'southward election fourth dimension and we are helping to compute the votes as they come up in. Votes arriving from individual wards, precincts, municipalities, counties, and states are sometimes reported equally a sum total of votes and sometimes every bit a list of subtotals of votes. Later considering how all-time to shop the tallies, we decide to utilize a nested number listing, which we define equally follows:

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

  1. numbers

  2. nested number lists

Notice that the term, nested number listing is used in its own definition. Recursive definitions like this are quite common in mathematics and reckoner science. They provide a concise and powerful mode to describe recursive data structures that are partially composed of smaller and simpler instances of themselves. The definition is not round, since at some point we will reach a list that does not have whatsoever lists equally elements.

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

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

For our nested number list, however, sum will not piece of work:

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

The problem is that the 3rd element of this listing, [11, 13] , is itself a list, which tin can not be added to 1 , 2 , and 8 .

5.17. Recursion¶

To sum all the numbers in our recursive nested number list we need to traverse the list, visiting each of the elements within its nested construction, adding whatsoever numeric elements to our sum, and repeating this process with whatsoever elements which are lists.

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

                            def              recursive_sum              (              nested_num_list              ):              the_sum              =              0              for              chemical element              in              nested_num_list              :              if              blazon              (              element              )              ==              listing              :              the_sum              =              the_sum              +              recursive_sum              (              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 but added to the_sum . If chemical element is a list, and then recursive_sum is called again, with the element as an argument. The statement inside the function definition in which the function calls itself is known as the recursive call.

Recursion is truly one of the near beautiful and elegant tools in figurer scientific discipline.

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

                            def              recursive_max              (              nested_num_list              ):              """                              >>> recursive_max([2, 9, [1, 13], 8, 6])                              13                              >>> recursive_max([2, [[100, 7], 90], [i, 13], 8, vi])                              100                              >>> recursive_max([2, [[xiii, seven], xc], [1, 100], eight, six])                              100                              >>> recursive_max([[[13, 7], 90], two, [1, 100], 8, vi])                              100                              """              largest              =              nested_num_list              [              0              ]              while              type              (              largest              )              ==              type              ([]):              largest              =              largest              [              0              ]              for              element              in              nested_num_list              :              if              type              (              element              )              ==              type              ([]):              max_of_elem              =              recursive_max              (              chemical element              )              if              largest              <              max_of_elem              :              largest              =              max_of_elem              else              :              # element is not a list              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 . Nosotros tin't just use nested_num_list[0] , since that my be either a number or a list. To solve this trouble we use a while loop that assigns largest to the start numerical value no matter how deeply it is nested.

The two examples above each take a base of operations case which does not pb to a recursive phone call: the case where the element is a number and non a list. Without a base of operations case, you have space recursion, and your program will non piece of work. Python stops after reaching a maximum recursion depth and returns a runtime mistake.

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              +              1              )              recursion_depth              (              0              )            

At the unix command prompt in the aforementioned directory in which you saved your program, 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 following:

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

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

5.eighteen. Exceptions¶

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

For instance, dividing past cipher creates an exception:

                            >>>                            print              55              /              0              Traceback (most contempo call concluding):              File              "<stdin>", line              1, in              <module>              ZeroDivisionError:              integer division or modulo by zero              >>>            

So does accessing a nonexistent list item:

                            >>>                            a              =              []              >>>                            print              a              [              5              ]              Traceback (most recent phone call concluding):              File              "<stdin>", line              ane, in              <module>              IndexError:              list index out of range              >>>            

Or trying to make an item assignment on a tuple:

                            >>>                            tup              =              (              'a'              ,              'b'              ,              'd'              ,              'd'              )              >>>                            tup              [              two              ]              =              'c'              Traceback (most recent telephone call concluding):              File              "<stdin>", line              ane, in              <module>              TypeError:              'tuple' object does not support item assignment              >>>            

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

Sometimes we desire to execute an operation that might cause an exception, but nosotros don't want the plan to cease. We can handle the exception using the effort and except statements.

For case, we might prompt the user for the name of a file and then attempt to open up it. If the file doesn't exist, nosotros don't want the plan to crash; we want to handle the exception:

                            filename              =              raw_input              (              'Enter a file proper noun: '              )              try              :              f              =              open              (              filename              ,              "r"              )              except              :              print              'At that place is no file named'              ,              filename            

The try statement executes the statements in the first 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.

Nosotros tin encapsulate this capability in a part: exists takes a filename and returns true if the file exists, faux if information technology doesn't:

                            def              exists              (              filename              ):              try              :              f              =              open up              (              filename              )              f              .              close              ()              return              True              except              :              return              False            

You lot can employ multiple except blocks to handle different kinds of exceptions (see the Errors and Exceptions lesson from Python creator Guido van Rossum's Python Tutorial for a more than complete discussion of exceptions).

If your program detects an error condition, you can make it raise an exception. Hither is an example that gets input from the user and checks that the number is not-negative.

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

The raise statement takes 2 arguments: the exception blazon, and specific information near the mistake. ValueError is the built-in exception which well-nigh closely matches the kind of error we want to heighten. The consummate list of built-in exceptions is found in the Built-in Exceptions section of the Python Library Reference, again by Python'due south creator, Guido van Rossum.

If the function that called get_age handles the mistake, then the program can proceed; otherwise, Python prints the traceback and exits:

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

The mistake message includes the exception type and the boosted information y'all provided.

Using exception treatment, we can at present 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              try              :              recursion_depth              (              number              +              i              )              except              :              impress              "Maximum recursion depth exceeded."              recursion_depth              (              0              )            

Run this version and notice the results.

5.19. Tail recursion¶

When the just thing returned from a function is a recursive call, it is refered to as tail recursion.

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

                            def              countdown              (              northward              ):              if              north              ==              0              :              print              "Blastoff!"              else              :              print              due north              inaugural              (              northward              -              one              )            

Any computation that can be made using iteration can also exist fabricated 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              ]:              return              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 not handle optimization for tail recursive calls. The recursive solution in cases like this use more than arrangement resources than the equivalent iterative solution.

v.20. Recursive mathematical functions¶

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

We can hands code this into Python:

                            def              factorial              (              n              ):              if              n              ==              0              :              render              1              else              :              return              n              *              factorial              (              due north              -              one              )            

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

                            fibonacci              (              0              )              =              1              fibonacci              (              one              )              =              ane              fibonacci              (              n              )              =              fibonacci              (              n              -              1              )              +              fibonacci              (              n              -              2              )            

This can also exist written hands in Python:

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

Calling factorial(k) volition exceed the maximum recursion depth. And effort running fibonacci(35) and see how long it takes to complete (be patient, it will complete).

You will be asked to write an iterative version of factorial as an do, and we will encounter a better way to handle fibonacci in the side by side chapter.

5.21. Glossary¶

argument

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

menstruation of execution

The order in which statements are executed during a program run.

frame

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

function

A named sequence of statements that performs some useful operation. Functions may or may not take parameters and may or may not produce a effect.

function call

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

function composition

Using the output from one function phone call every bit the input to another.

part definition

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

The get-go part of a compound statement. Headers begin with a keyword and end with a colon (:)

local variable

A variable defined inside a function. A local variable can only exist 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 part that reaches the end of its body without hitting a return argument containing a value.

parameter

A name used inside a function to refer to the value passed equally 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 besides commonly refered to as a stack trace, since information technology lists the functions in the order in which they are stored in the runtime stack.