6.4 Parameters, Parameter Passing, and Scope

Throughout the previous chapters, we have used functions to implement abstraction. We have broken problems down into smaller, more manageable pieces and have implemented functions that we can call over and over again. In the previous section we pushed this idea one step further by passing functions as parameters to other functions. In this section we explore in more detail the underlying mechanics of functions and parameter passing.

Consider the function shown in LISTING 6.7, which computes the hypotenuse of a right triangle. Using the Pythagorean theorem, a2 + b2 = c2, this function needs the lengths of the two sides, called a and b, and computes and returns the length of the long side, called c. In the function definition, the parameters a and b are known as the formal parameters. SESSION 6.11 shows the function in use.

Image

LISTING 6.7 A simple function to compute the hypotenuse of a triangle

Image

SESSION 6.11 A simple method

In the first example, references to the objects 3 and 4 are passed to the function. These are known as the actual parameters because they represent the “actual” data that the function will receive. As we have seen before, the parameter list (a, b) receives these object references one at a time, in order, from left to right. So, a receives a reference to the object 3, and b receives a reference to the object 4.

In the second example in Session 6.11, the actual parameters are not literal numbers but are instead names that are referring to the objects 3 and 4. Prior to the function call, Python evaluates the two names side1 and side2 to find the objects. Once again, a receives a reference to the object 3, and b receives a reference to the object 4.

6.4.1 Call by Assignment Parameter Passing

In general, the process by which a function’s formal parameter receives an actual parameter value is known as parameter passing. There are many different ways to pass parameters, and different programming languages have chosen to use a variety of them. In Python, all parameters are passed using a single mechanism known as call by assignment parameter passing.

Call by assignment parameter passing uses a simple two-step process to pass data when the function is called—a process known as invocation. The first thing that happens is that the actual parameters are evaluated. This evaluation results in an object reference to the value of the parameter. In the first case from Session 6.11, evaluating a literal number simply returns a reference to the number itself. In the second example, evaluating a variable name returns the object reference named by that variable.

Once the evaluation of the actual parameters is complete, the object references are passed to and received by the formal parameters in the function. The formal parameter becomes a new name for the reference that is passed. In a sense, it is as if we executed the assignment statement

Image

As a final example, consider the third invocation shown in Session 6.11. Here, the actual parameters are expressions that double the lengths of the original sides. Call by assignment parameter passing evaluates these expressions first, and then assigns the references to the resulting objects to the formal parameters a and b. The hypotenuse function has no idea where the references came from or how complicated the original expression might have been. Instead, the references that it receives are simply the results of the evaluation.

Call by assignment parameter passing has some important ramifications that may not be immediately obvious. Changes to the formal parameter may or may not result in changes to the actual parameter depending on whether the actual parameter is mutable or immutable. If the actual parameter is immutable, then changes to the formal parameter will have no effect outside the function. If the actual parameter is mutable, then changes to the object referenced by the formal parameter will be visible outside the function.

For example, if the actual parameter is a reference to the integer 3, then assigning a reference to the integer 5 to the formal parameter would not be visible outside the function. If the actual parameter is a reference to a list, however, then any changes to the contents of the list, including additions or deletions, will be visible outside the function. However, if the formal parameter is assigned to a different list, the behavior is consistent with the behavior for integers.

6.4.2 Namespaces

In Python, all the names defined in a program, whether for data or for functions, are organized into namespaces—collections of all names that are available to be accessed at a particular point in time during the execution of a Python program. When we start Python, we create two namespaces. The first, called the builtins namespace (see FIGURE 6.9), includes all the system-defined names of functions and data types that we regularly use in Python. Names such as the built-in functions range, str, and float are included in this namespace. The second namespace, called the main namespace, is initially empty. Python calls these two namespaces _ _builtins_ _ and _ _main_ _.

A figure represents the builtins name space. The figure shows the names and objects they refer. They are as follows: str Type ‘str’, int Type ‘int’, and range Builtin function range.

FIGURE 6.9 The builtins namespace.

As we begin to create our own names in a Python session, they are added to the main namespace. In the example in Session 6.11, the variable names side1 and side2 are added to the main namespace. Likewise, the function name hypotenuse is added to the main namespace. Notice that the names are added as a result of an assignment statement or a method definition. The objects referred to by the names are shown as well. FIGURE 6.10 shows the location of the names and the objects they reference. Note that the objects exist outside the namespace.

A figure represents the main name space along with the builtins name space.

FIGURE 6.10 The main namespace.

At this point it is instructive to investigate the namespace idea interactively. Python provides us with the function dir, which allows us to see a list of the names in any namespace. SESSION 6.12 shows what happens when we invoke the dir function after defining the hypotenuse function and assigning values to the side1 and side2 variables.

Image

SESSION 6.12 Exploring the main namespace

In addition to the three names that we just created, there are four other names of interest defined in our namespace. The _ _builtins_ _ refers to the builtins namespace we mentioned earlier. It includes the built-in functions as well as Python’s predefined errors. To find the names of the objects in the builtins namespace, you can call the function dir(_ _builtins_ _). The _ _doc_ _ name is always available to hold a reference to a string that describes the namespace. The _ _main_ _ namespace does not have documentation, but other namespaces such as math may. The _ _name_ _ variable holds the name of the current namespace. In Session 6.12, you can see that we evaluated _ _name_ _ to find that we are in the _ _main_ _ namespace.

One name in the list from dir that we have yet to discuss is math. This name appears because we imported the math module on line 1 of the session. As you can see, the name math refers to an object that is a module. A module defines its own namespace. Just as with the builtins namespace, you can see the names in the math namespace by evaluating dir(math). Note that the math namespace also has its own _ _name_ _ and _ _doc_ _ entries.

We now have all the tools we need to understand the difference between the statements import math and from math import *. SESSION 6.13 shows the result of calling the dir function after importing the math module using the statement from math import *. Notice that all the names from the math module now appear as part of the main namespace. This allows us to call functions such as sqrt directly without prefacing the function name with the module name.

Image

SESSION 6.13 Importing the math names into the main namespace

6.4.3 Calling Functions and Finding Names

When a function is invoked, a new namespace known as the local namespace is created corresponding to the function itself. This namespace includes those names that are created inside the function—the formal parameters as well as any names that are created via an assignment statement in the body of the function. These names are referred to as local variables because they have been created within the function and are part of the local namespace. When the function completes, either due to a return statement or because it runs out of code statements, the local namespace is destroyed. In turn, all the locally defined names are no longer available for use.

The placement of these namespaces with respect to one another is a key consideration. The main namespace is placed inside the builtins namespace. Likewise, local namespaces are placed inside the namespace of the module where they are defined. For programs that you write, the namespaces for your functions will be placed in the main namespace. The namespaces for functions from modules that you import will be placed in the namespace of the imported module.

FIGURE 6.11 shows the placement of the local namespace for the hypotenuse function when it is called; it is just a sampling of the names in the builtins namespace. This figure also provides an illustration of the call-by-assignment mechanism. Note that the formal parameters a and b refer to the same objects as the actual parameters side1 and side2, respectively.

A figure represents a local namespace.

FIGURE 6.11 A local namespace.

When a name is used in a statement, Python needs a way to locate the particular occurrence of that name among all of the names that have been introduced up to that point. To find the name, Python uses the following simple rules:

  1. Whenever a name is used, except on the left-hand side of an assignment statement, Python searches through the namespaces in the following order:

    1. The current local namespace, if one exists

    2. The main or module namespace

    3. The builtins namespace

      When Python finds the first occurrence of the name, the search ends. Looking again at Figure 6.11, you may find it helpful to think of this process as searching from the “inside out.” If the name is not found, a NameError is reported.

  2. When you use a name on the left-hand side of an assignment statement, Python searches only the current namespace.

    1. If the name is not found, a new name is created in the current namespace.

    2. If the name is found, then the old reference is replaced with the object from the right-hand side of the assignment statement.

To show these rules in action, consider the code shown in SESSION 6.14. Here, function test1 defines one formal parameter value called a. It adds 5 to a and prints the result. Since a is a formal parameter, it becomes part of the local namespace for the function test1.

Image

SESSION 6.14 Showing name lookup rules at work

Next, an assignment statement creates a variable called a and sets it to refer to the object 6. This occurrence of the name a is added to the main namespace. When we invoke test1 using a as the actual parameter, call-by-assignment parameter passing will first evaluate a. The result is a reference to the object 6, which is passed and received by the formal parameter a in the local namespace. When the assignment statement is executed in the function test1, Python must search for the name a. The result of the search is that the a from the local namespace is used in the statement a = a + 5. The a in the main namespace is unaffected and still refers to the object 6.

In the second example in Session 6.14, test2 is defined with a formal parameter called b. This function prints b and then prints a. However, the name a is not defined in the local namespace for test2. When the print statements are executed, we will use the previous rules to locate the names. The result of the search is that b is found in the local namespace but a is found in the main namespace.

In this example, the reference to the object 14 is assigned to the formal parameter b in test2 so that the first print statement simply prints the value 14. The second print statement tries to find a variable called a. Because it cannot be found in the local scope, the search proceeds outward to the main namespace, where a is found with a value of 6. Therefore, 6 is printed.

Note that after the call to test2 completes, a still has the value 6 because it is part of the main namespace. Once the function test2 completes, its namespace is destroyed and b is no longer present. Since b does not exist in the main namespace, an error is reported because b is not defined.

6.4.4 Modules and Namespaces

The hypotenuse function defined earlier uses the sqrt function from the math module. To access that function, we needed to import the math module. In Python, the statement import math creates a name in the current namespace with a reference to a new namespace for the module itself. In this case, the name math is added to the main namespace. The new namespace for the math module is placed in the builtins namespace, as shown in FIGURE 6.12. The math namespace contains names of functions such as sqrt. Note that the name sqrt refers to a function definition.

A figure shows all the namespaces including imported module.

FIGURE 6.12 Namespaces including imported module.

Notice that the namespace for the math module was placed in the builtins namespace, not in the main namespace. The namespaces for all imported modules will be placed at the same level within the builtins namespace. The only thing that is placed directly in the main namespace is the name of the module with the corresponding reference to the module namespace.

To take this one step further, consider the hypotenuse function at the point where the sqrt function has been invoked. As before, the namespace for hypotenuse has been placed as a local namespace in the main namespace. When the hypotenuse function calls the sqrt function, a new local namespace for sqrt is created. Even though the call to sqrt was made from the hypotenuse namespace, the sqrt namespace is placed in the math namespace because that is where the sqrt function was defined.

The local namespace created when a function is called is always created in the namespace for the module in which the function was defined. In our example, this is true regardless of how the math module is imported. Even if we had imported math using from math import *, the namespace for sqrt would be placed in the math namespace.

FIGURE 6.13 shows all of the namespaces created up to this point in our example. According to the name lookup rules defined earlier, searches for names used in the sqrt function will start in the local sqrt namespace, proceed outward to the math namespace, and finally move to the builtins namespace.

A figure represents an invocation of sqrt function from math.

FIGURE 6.13 Invocation of sqrt function from math.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.204.216