Python provides a mechanism for optional parameters. This allows us
to create a single function which has several alternative forms. In other
languages, like C++ or Java, these are called overloaded functions; they
are actually separate function definitions with the same name but
different parameter forms. In Python, we can write a single function that
accepts several parameter forms.
Python has three mechanisms for dealing with optional parameters and
a variable number of parameters. We'll cover the basics of optional
parameters in this section. The other mechanisms for dealing with variable
numbers of parameters will be deferred until the section called “Advanced Parameter Handling For Functions” because these mechanisms use some more advanced
data structures.
Python functions can return multiple values. We'll look at this,
also.
Default Values for Parameters
One way the we can handle optional parameters is by providing a
default value for a parameter. If no argument is supplied for the
parameter, the default value is used.
def report( spin, count=1 ):
print spin, count, "times in a row"
This silly function can be used in two ways:
report( n )
report( n, 2 )
The first form provides a default argument of 1 for the
count
parameter. The second form has an explicit
argument value of 2 for the
count
parameter.
If a parameter has no default value, it is not optional. If a
parameter has a default value, it is optional. In order to disambiguate
the assignment of arguments to parameters, Python uses a simple rule:
all required parameters must be first, all optional parameters must come
after the required parameters.
The int
function does this. We can say
int("23")
to do decimal conversion and
int("23",16)
to do hexadecimal conversion. Clearly, the
second argument to int
has a default value of
10.
When we look at the Python range
function, we
see a more sophisticated version of this.
range
(
x
) is the same as
range
(
0
,
x
,
1
)
range
(
x
,
y
) is the same as range
(
x
,
y
,
1
)
It appears from these examples that the
first
parameter is optional. The authors of Python use a pretty slick trick
for this that you can use also. The range
function
behaves as though the following function is defined.
def range(x, y=None, z=None):
if y==None:
start, stop, step = 0, x, 1
elif z==None:
start, stop, step = x, y, 1
else:
start, stop, step = x, y, z
Real work is done with start, stop and step
By providing a default of None
, the function
can determine whether a value was supplied or not supplied. This allows
for complex default handling within the body of the function.
Conclusion. Python must find a value for all parameters. The basic rule is
that the values of parameters are set in the order in which they are
declared. Any missing parameters will have their default values
assigned. These are called positional parameters, since the position
is the rule used for assigning argument values when the function is
applied.
If a mandatory parameter (a parameter without a default value) is
missing, this is a basic TypeError
. For
example.
Example 9.3. badcall.py
#!/usr/bin/env python
def hack(a,b):
print a+b
hack(3)
When we run this example, we see the following.
$
python badcall.py
Traceback (most recent call last):
File "badcall.py", line 5, in ?
hack(3)
TypeError: hack() takes exactly 2 arguments (1 given)
$
Providing Argument Values by Keyword
In addition to supplying argument values by position, Python also
permits argument values to be specified by name. Using explicit keywords
can make programs much easier to read.
First, we'll define a function with a simple parameter
list:
import random
def averageDice( samples=100 ):
"""Return the average of a number of throws of 2 dice."""
s = 0
for i in range(samples):
d1,d2 = random.randrange(6)+1,random.randrange(6)+1
s += d1+d2
return float(s)/float(samples)
Next, we'll show three different kinds of arguments: keyword,
positional, and default.
test1 = averageDice( samples=200 )
test2 = averageDice( 300 )
test3 = averageDice()
When the averageDice
function is evaluated to
set test1
, the keyword form is used. The second call
of the averageDice
function uses the positional
form. The final example relies on a default for the parameter.
Conclusion. This gives us a number of variations including positional
parameters and keyword parameters, both with and without defaults.
Positional parameters work well when there are few parameters and
their meaning is obvious. Keyword parameters work best when there are
a lot of parameters, especially when there are optional
parameters.
Good use of keyword parameters mandates good selection of
keywords. Single-letter parameter names or obscure abbreviations do not
make keyword parameters helpfully informative.
Here are the rules we've seen so far:
-
Supply values for all parameters given by name, irrespective
of position.
-
Supply values for all remaining parameters by position; in the
event of duplicates, raise a
TypeError
.
-
Supply defaults for any parameters that have defaults defined;
if any parameters still lack values, raise a
TypeError
.
There are still more options available for handling variable
numbers of parameters. It's possible for additional positional
parameters to be collected into a sequence object. Further, additional
keyword parameters can be collected into a dictionary object. We'll get
to them when we cover dictionaries in the section called “Advanced Parameter Handling For Functions”.
Returning Multiple Values
One common desire among programmers is a feature that allows a
function to return multiple values. Python has some built-in functions
that have this property. For example, divmod
returns the divisor and remainder in division. We could imagine a
function, rollDice
that would return two values
showing the faces of two dice.
In Python, it is done by returning a tuple
.
We'll wait for Chapter 13, Tuples
for complete
information on tuple
s. The following is a quick
example of how multiple assignment works with functions that return
multiple values.
Example 9.4. rolldice.py
import random
def rollDice():
return ( 1 + random.randrange(6), 1 + random.randrange(6) )
d1,d2=rollDice()
print d1,d2
This shows a function that creates a two-valued
tuple
. You'll recall from the section called “Multiple Assignment Statement” that Python is perfectly happy with
multiple expressions on the right side of
=
, and
multiple destination variables on the left side. This is one reason why
multiple assignment is so handy.