Advanced Parameter Handling For Functions
Advanced Parameter Handling For Functions
In the section called “More Features” we hinted that Python functions can handle a variable
number of argument values in addition to supporting optional argument values. Earlier, when we
defined a function that had optional parameters, it had a definite number of parameters, but some
(or all) could be omitted because we provided default values for them.
If we provide too many positional parameters to a function, Python raises an exception. Consider
the following example. We defined a function of three positional parameters, and then evaluated
it with more than three argument values.
>>>
def avg(a,b,c):
return (a+b+c)/3.0
>>>
avg(10,11,12)
11.0
>>>
avg(10,11,12,13,14,15,16)
Python lets us define a function that handles an unknown and unlimited number of argument
values. Examples of built-in functions with a unlimited number of argument values are max and
min.
Rather than have Python raise an exception, we can request the additional positional argument
values be collected into a tuple. To do this, you provide a final parameter definition of the form
* extras . The * indicates that this parameter variable is the place to capture the extra argument
values. The variable, here called extras , will receive a sequence with all of the extra positional
argument values.
You can only provide one such variable (if you provided two, how could Python decide which of
these two got the extra argument values?) You must provide this variable after the ordinary
positional parameters in the function definition.
We take the first element of the args tuple as our current guess at the maximum value, max. We
use a for loop that will set the variable a to each of the other arguments. If a is larger than our
current guess, we update the current guess, max. At the end of the loop, the post condition is that
we have visited every element in the list args; the current guess must be the largest value.
Here's another example. In this case we have a fixed parameter in the first position and all the
extra parameters collected into a tuple called vals.
This should look familiar to C programmers. Now we can write the following, which may help
ease the transition from C to Python.
In addition to collecting extra positional argument values into a single parameter, Python can
also collect extra keyword argument values into a dict. If you want a container of keyword
arguments, you provide a parameter of the form ** extras . Your variable, here called extras ,
will receive a dict with all of the keyword parameters.
The following function accepts any number opf keyword arguments; they are collected into a
single parameter.
>>>
The keyword arguments are collected into a dict, named args. We check for some combination
of "rate", "time" and "distance" by using the dict method has_key. If the dict of keyword
arguments, args, has the given keyword, has_key returns true. For each combination, we can
solve for the remaining value and update the dict by insert the additional key and value into the
dict.
We can also force a sequence to be broken down into individual parameters. We can use a
special version of the * operator when evaluating a function. Here's an example of forcing a 3-
tuple to be assigned to three positional parameters.
>>>
def avg3(a,b,c):
... return (a+b+c)/3.0
>>>
avg3( *(4,5,7) )
5.333333333333333
In this example, we told Python to break down our 3-tuple, and assign each value of the tuple
to a separate parameter variable.
As with the * operator, we can use ** to make a dict become a series of keyword parameters to
a function.
In this example, we told Python to assign each element of the dict, d, to a parameter of our
function.
We can mix and match this with ordinary parameter assignment, also. Here's an example.
The print statement has irregular, complex syntax. Also, because it's a statement, making
blanket changes requires tedious, manual search and replace on the program source. Writing a
print function can make the print statement slightly easier to cope with.
We want to mirror the capabilities of the existing print statement, so we need to accept an
unlimited number of positional parameters, as well as some optional keyword parameters. One
keyword parameter can be used in place of the "chevron" feature to define the output file. The
other keyword parameters can provide formatting information: what character goes between
fields and what character (if any) goes at the end of the line.
Converts the argument values to strings, and writes them to the given file. If no file is
provided, writes to standard output. The sep parameter is the column separator, which is
a space by default. The end parameter is the end-of-line character, which is a \n by
default.
A simple version of our print replacement function would look something like the following.
This example looks forward to using the map function, which we won't look at in detail until the
section called “Sequence Processing Functions: map, filter, reduce and zip”.
import sys
def _print( *args, **kw ):
out= kw.get('file',sys.stdout)
linesep= kw.get('end','\n')
colsep= kw.get('sep',' ')
out.write( colsep.join( map(str,args) ) )
out.write( linesep )
Our intent is to have a function that we can use as follows. We want to provide a long sequence
of positional parameters first, followed by some optional keyword parameters.
Note that we can't simply say def _print ( *args, sep=' ', end='\n', file=None ) as
the definition of this function. We can't have the "all extra positional parameters" listed first in
the function definition, even though this is our obvious intent. To achieve the syntax we want,
we have to write a function which collects all positional parameters into one sequence of values,
and all keyword parameters into a separate dictionary.