The heart of programming is the evaluate-apply cycle, where function arguments are evaluated and then the function is applied to those argument values. We’ll review this in Semantics.
In Function Definition: The def and return Statements we introduce the syntax for defining a function. In Function Use, we’ll describe using a function we’ve defined.
Some languages make distinctions between varieties of functions, separating them into “functions” and “subroutines”. We’ll visit this from a Python perspective in Function Varieties.
We’ll look at some examples in Some Examples. We’ll look at ways to use IDLE in Hacking Mode.
We introduce some of the alternate argument forms available for handling optional and keyword parameters in More Function Definition Features.
Further sophistication in how Python handles parameters has to be deferred to Advanced Parameter Handling For Functions, as it depends on a knowledge of dictionaries, introduced in Mappings and Dictionaries.
In Object Method Functions we will describe how to use method functions as a prelude to Data Structures; real details on method functions are deferred until Classes.
We’ll also defer examination of the yield statement until Iterators and Generators. The yield statement creates a special kind of function, one that is most useful when processing complex data structures, something we’ll look at in Data Structures.
A function, in a mathematical sense, is often described as a mapping from domain values to range values. Given a domain value, the function returns the matching range value.
If we think of the square root function, it maps a positive number, n, to another number, s, such that .
If we think of multplication as a function, it maps a pair of values, a and b, to a new value, c, such that . When we memorize multiplication tables, we are memorizing these mappings.
In Python, this narrow definition is somewhat relaxed. Python lets us create functions which do not need a domain value, but create new objects. It also allows us to have functions that don’t return values, but instead have some other effect, like reading user input, or creating a directory, or removing a file.
What We Provide. In Python, we create a new function by providing three pieces of information: the name of the function, a list of zero or more variables, called parameters, with the domain of input values, and a suite of statements that creates the output values. This definition is saved for later use. We’ll show this first in Function Definition: The def and return Statements.
Typically, we create function definitions in script files because we don’t want to type them more than once. Almost universally, we import a file with our function definitions so we can use them.
We use a function in an expression by following the function’s name with (). The Python interpreter evaluates the argument values in the (), then applies the function. We’ll show this second in Function Use.
Applying a function means that the interpreter first evaluates all of the argument values, then assigns the argument values to the function parameter variables, and finally evaluates the suite of statements that are the function’s body. In this body, any return statements define the resulting range value for the function. For more information on this evaluate-apply cycle, see The Evaluate-Apply Cycle.
Namespaces and Privacy. Note that the parameter variables used in the function definition, as well as any variables in a function are private to that function’s suite of statements. This is a consequence of the way Python puts all variables in a namespace. When a function is being evaluated, Python creates a temporary namespace. This namespace is deleted when the function’s processing is complete. The namespace associated with application of a function is different from the global namespace, and different from all other function-body namespaces.
While you can change the standard namespace policy (see The global Statement) it generally will do you more harm than good. A function’s interface is easiest to understand if it is only the parameters and return values and nothing more. If all other variables are local, they can be safely ignored.
Terminology: argument and parameter. We have to make a firm distinction between an argument value, an object that is created or updated during execution, and the defined parameter variable of a function. The argument is the object used in particular application of a function; it may be referenced by other variables or objects. The parameter is a variable name that is part of the function, and is a local variable within the function body.
We create a function with a def statement. This provides the name, parameters and the suite of statements that creates the function’s result.
def name ( parameter 〈 , ... 〉 ): suite
The name is the name by which the function is known. The parameters is a list of variable names; these names are the local variables to which actual argument values will be assigned when the function is applied. The suite (which must be indented) is a block of statements that computes the value for the function.
The first line of a function’s suite is expected to be a document string (generally a triple-quoted string) that provides basic documentation for the function. This is traditionally divided in two sections, a summary section of exactly one line and the detail section. We’ll return to this style guide in Functions Style Notes.
The return statement specifies the result value of the function. This value will become the result of applying the function to the argument values. This value is sometimes called the effect of the function.
return expression
The yield statement specifies one of the result values of an iterable function. We’ll return to this in Iterators and Generators.
Let’s look at a complete example.
def odd( spin ):
"""Return true if this spin is odd."""
if spin % 2 == 1:
return True
return False
When Python evaluates odd(n), the following things will happen.
We would use this odd() function like this.
s = random.randrange(37)
# 0 <= s <= 36, single-0 roulette
if s == 0:
print "zero"
elif odd(s):
print s, "odd"
else:
print s, "even"
Some programming languages make a distinction between various types of functions or “subprograms”. There can be “functions” or “subroutines” or “procedure functions”. Python (like Java and C++) doesn’t enforce this kind of distinction.
Instead, Python imposes some distinction based on whether the function uses parameters and returns a value or yields a collection of values.
“Ordinary” Functions. Functions which follow the classic mathematical definitions will map input argument values to a resulting value. These are, perhaps, a common kind of function. They include a return statement to express the resulting value.
Procedure Functions. One common kind of function is one that doesn’t return a result, but instead carries out some procedure. This function would omit any return statement. Or, if a return statement is used to exit from the function, the statement would have no value to return.
Carrying out an action is sometimes termed a side-effect of the function. The primary effect is always the value returned.
Here’s an example of a function that doesn’t return a value, but carries out a procedure.
from __future__ import print_function
def report( spin ):
"""Report the current spin."""
if spin == 0:
print( "zero" )
return
if odd(spin):
print( spin, "odd" )
return
print( spin, "even" )
This function, report(), has a parameter named spin, but doesn’t return a value. Here, the return statements exit the function but don’t return values.
This kind of function would be used as if it was a new Python language statement, for example:
for i in range(10):
report( random.randrange(37) )
Here we execute the report() function as if it was a new kind of statement. We don’t evaluate it as part of an expression.
There’s actually no real subtlety to this distinction. Any expression can be used as a Python statement. A function call is an expression, and an expression is a statement. This greatly simplifies Python syntax. The docstring for a function will explain what kind of value the function returns, or if the function doesn’t return anything useful.
The simple return statement, by the way, returns the special value None. This default value means that you can define your function like report(), above, use it in an expression, and everything works nicely because the function does return a value.
for i in range(10):
t= report( random.randrange(37) )
print t
You’ll see that t is None .
Factory Functions. Another common form is a function that doesn’t take a parameter. This function is a factory which generates a value.
Some factory functions work by accessing some object encapsulated in a module. In the following example, we’ll access the random number generator encapsulated in the random module.
def spinWheel():
"""Return a string result from a roulette wheel spin."""
t= random.randrange(38)
if t == 37:
return "00"
return str(t)
This function’s evaluate-apply cycle is simplified to just the apply phase. To make 0 (zero) distinct from 00 (double zero), it returns a string instead of a number.
Generators. A generator function contains the yield statement. These functions look like conventional functions, but they have a different purpose in Python. We will examine this in detail in Iterators and Generators.
These functions have a persistent internal processing state; ordinary functions can’t keep data around from any previous calls without resorting to global variables. Further, these functions interact with the for statement. Finally, these functions don’t make a lot of sense until we’ve worked with sequences in Sequences: Strings, Tuples and Lists.
Here’s a big example of using the odd() , spinWheel() and report() functions.
functions.py
#!/usr/bin/env python
import random
def odd( spin ):
"""odd(number) -> boolean."""
return spin%2 == 1
def report( spin ):
"""Reports the current spin on standard output. Spin is a String"""
if int(spin) == 0:
print "zero"
return
if odd(int(spin)):
print spin, "odd"
return
print spin, "even"
def spinWheel():
"""Returns a string result from a roulette wheel spin."""
t= random.randrange(38)
if t == 37:
return "00"
return str(t)
for i in range(12):
n= spinWheel()
report( n )
We’ve defined a function named odd(). This function evaluates a simple expression; it returns True if the value of it’s parameter, spin, is odd.
The function called report() uses the odd() function to print a line that describes the value of the parameter, spin. Note that the parameter is private to the function, so this use of the variable name spin is technically distinct from the use in the odd() function. However, since the report() function provides the value of spin to the odd() function, their two variables often happen to have the same value.
The spinWheel() function creates a random number and returns the value as a string.
The “main” part of this program is the for loop at the bottom, which calls spinWheel(), and then report(). The spinWheel() function uses random.randrange(); the report() function uses the odd() function. This generates and reports on a dozen spins of the wheel.
For most of our exercises, this free-floating main script is acceptable. When we cover modules, in Components, Modules and Packages, we’ll need to change our approach slightly to something like the following.
def main():
for i in range(12):
n= spinWheel()
report( n )
main()
This makes the main operation of the script clear by packaging it as a function. Then the only free-floating statement in the script is the call to main().
On one hand we have interactive use of the Python interpreter: we type something and the interpreter responds immediately. We can do simple things, but when our statements get too long, this interaction can become a niusance. We introduced this first, in Command-Line Interaction.
On the other hand, we have scripted use of the interpreter: we present a file as a finished program to execute. While handy for getting useful results, this isn’t the easiest way to get a program to work in the first place. We described this in Script Mode.
In between the interactive mode and scripted mode, we have a third operating mode, that we might call hacking mode. The idea is to write most of our script and then exercise portions of our script interactively. In this mode, we’ll develop script files, but we’ll exercise them in an interactive environment. This is handy for developing and debugging function definitions.
The basic procedure is as follows.
In our favorite editor, write a script with our function definitions. We often leave this editor window open. IDLE, for example, leaves this window open for us to look at.
Open a Python shell. IDLE, for example, always does this for us.
In the Python Shell, import the script file. In IDLE, this is effectively what happens when we run the module with F5.
This will execute the various def statements, creating our functions in our interactive shell.
In the Python Shell, test the function interactively. If it works, we’re done.
If the functions in our module didn’t work, we return to our editor window, make any changes and save the file.
In the Python Shell, clear out the old definition by restarting the shell. In IDLE, we can force this with F6. This happens automatically when we run the module using F5
Go back to step 3, to import and test our definitions.
The interactive test results can be copied and pasted into the docstring for the file with our function definitions. We usually copy the contents of the Python Shell window and paste it into our module’s or function’s docstring. This record of the testing can be validated using the doctest module.
Example. Here’s the sample function we’re developing. If you look carefully, you might see a serious problem. If you don’t see the problem, don’t worry, we’ll find it by doing some debugging.
In IDLE, we created the following file.
function1.py Initial Version
def odd( number ):
"""odd(number) -> boolean
Returns True if the given number is odd.
"""
return number % 2 == "1"
We have two windows open: function1.py and Python Shell.
Here’s our interactive testing session. In our function1.py window, we hit F5 to run the module. Note the line that shows that the Python interpreter was restarted; forgetting any previous definitions. Then we exercised our function with two examples.
Python 2.5.1 (r251:54863, Oct 5 2007, 21:08:09) [GCC 4.0.1 (Apple Inc. build 5465)] on darwin Type “help”, “copyright”, “credits” or “license” for more information. ************************************************************ Personal firewall software may warn about the connection IDLE makes to its subprocess using this computer’s internal loopback interface. This connection is not visible on any external interface and no data is sent to or received from the Internet. ************************************************************ IDLE 1.1.4 >>> ================================ RESTART ================================ >>> >>> odd(2) False >>> odd(3) False
Clearly, it doesn’t work, since 3 is odd. When we look at the original function, we can see the problem.
The expression number % 2 == "1" should be number % 2 == 1.
We need to fix function1.py. Once the file is fixed, we need to remove the old stuff from Python, re-import our function and rerun our test. IDLE does this for us when we hit F5 to rerun the module. It shows this with the prominent restart message.
If you are not using IDLE, you will need to restart Python to clear out the old definitions. Python optimizes import operations; if it’s seen the module once, it doesn’t import it a second time. To remove this memory of which modules have been imported, you will need to restart Python.
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 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.
The most common way to implement optional parameters is by providing a default value for the optional parameters. 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.
Important
Red Alert
It’s very, very important to note that default values must be immutable objects. We’ll return to this concept of mutability in Data Structures.
For now, be aware that numbers, strings, None, and tuple objects are immutable.
As we look at various data type, we’ll find that lists, sets and dictionaries are mutable, and cannot be used as default values for function parameters.
Fancy Defaults. 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 value 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:
badcall.py
#!/usr/bin/env python
def hack(a,b):
print a+b
hack(3)
When we run this example, we see the following.
MacBook-5:Examples slott$ python badcall.py
Traceback (most recent call last):
File "badcall.py", line 4, in <module>
hack(3)
TypeError: hack() takes exactly 2 arguments (1 given)
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:
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 Advanced Parameter Handling For Functions.
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 Tuples for complete information on tuples. The following is a quick example of how multiple assignment works with functions that return multiple values.
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 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.
Fast exponentiation. This is a fast way to raise a number to an integer power. It requires the fewest multiplies, and does not use logarithms.
Fast Exponentiation of integers, raises n to the p power
Base Case. If : return 1.0.
Odd. If p is odd: return .
Even. If p is even:
compute ;
return .
Greatest Common Divisor. The greatest common divisor is the largest number which will evenly divide two other numbers.
You use this when you reduce fractions. See Greatest Common Divisor for an alternate example of this exercise’s algorithm. This version can be slightly faster than the loop we looked at earlier.
Greatest Common Divisor of two integers, p and q
Factorial Function. Factorial of a number n is the number of possible arrangements of 0 through n things. It is computed as the product of the numbers 1 through n. That is, .
The formal definition is
We touched on this in Computing e. This function definition can simplify the program we wrote for that exercise.
Factorial of an integer, n
Fibonacci Series. Fibonacci numbers have a number of interesting mathematical properties. The ratio of adjacent Fibonacci numbers approximates the golden ratio (, about 1.618), used widely in art and architecture.
The nth Fibonacci Number, .
Ackermann’s Function. An especially complex algorithm that computes some really big results. This is a function which is specifically designed to be complex. It cannot easily be rewritten as a simple loop. Further, it produces extremely large results because it describes extremely large exponents.
Ackermann’s Function of two numbers, m and n
Yes, this requires you to compute before you can compute .
Maximum Value of a Function. Given some integer-valued function f(), we want to know what value of x has the largest value for f() in some interval of values. For additional insight, see [Dijkstra76].
Imagine we have an integer function of an integer, call it f(). Here are some examples of this kind of function.
The question we want to answer is what value of x in some fixed interval returns the largest value for the given function? In the case of the first example, def f1(x): return x, the largest value of f1() in the interval occurs when x is 9.
What about f3() in the range ?
Max of a Function, F, in the interval low to high
Initialize.
;
;
.
Loop. While .
New Max? If :
;
.
Next X. Increment x by 1.
Return. Return max as the value at which had the largest value.
Integration. This is a simple rectangular rule for finding the area under a curve which is continuous on some closed interval.
We will define some function which we will integrate, call it f(x)(). Here are some examples.
When we specify , we are specifying two dimensions. The y is given by the function’s values. The x dimension is given by some interval. If you draw the function’s curve, you put two limits on the x axis, this is one set of boundaries. The space between the curve and the y axis is the other boundary.
The x axis limits are a and b. We subdivide this interval into s rectangles, the width of each is . We take the function’s value at the corner as the average height of the curve over that interval. If the interval is small enough, this is reasonably accurate.
Integrate a Function, F, in the interval a to b in s steps
Initialize.
Loop. While .
Increment sum by .
Increment x by h.
Return sum as the area under the curve F() for .
Field Bet Results. In the dice game of Craps, the Field bet in craps is a winner when any of the numbers 2, 3, 4, 9, 10, 11 or 12 are rolled. On 2 and 12 it pays 2:1, on any of the other numbers, it pays 1:1.
Define a function win( dice, num, pays). If the value of dice equals num, then the value of pays is returned, otherwise 0 is returned. Make the default for pays a 1, so we don’t have to repeat this value over and over again.
Define a function field( dice ). This will call win() 7 times: once with each of the values for which the field pays. If the value of dice is a 7, it returns -1 because the bet is a loss. Otherwise it returns 0 because the bet is unresolved.
It would start with
def field( dice ):
win( dice, 2, pays=2 )
win( dice, 3, pays=1 )
...
Create a function roll() that creates two dice values from 1 to 6 and returns their sum. The sum of two dice will be a value from 2 to 12.
Create a main program that calls roll() to get a dice value, then calls field() with the value that is rolled to get the payout amount. Compute the average of several hundred experiments.
range() Function Keywords. Does the range function permit keywords for supplying argument values? What are the keywords?
Optional First Argument. Optional parameters must come last, yet range fakes this out by appearing to have an optional parameter that comes first. The most common situation is range(5) , and having to type range(0,5) seems rather silly. In this case, convenience trumps strict adherence to the rules. Is this a good thing? Is strict adherence to the rules more or less important than convenience?
We’ve seen how we can create functions and use those functions in programs and other functions. Python has a related technique called methods or method functions. The functions we’ve used so far are globally available. A method function, on the other hand, belongs to an object. The object’s class defines what methods and what properties the object has.
We’ll cover method functions in detail, starting in Classes. For now, however, some of the Python data types we’re going to introduce in Data Structures will use method functions. Rather than cover too many details, we’ll focus on general principles of how you use method functions in this section.
The syntax for calling a method function looks like this:
someObject.aMethod( argument list )
A single . separates the owning object (someObject) from the method name (aMethod()).
We glanced at a simple example when we first looked at complex numbers. The complex conjugate function is actually a method function of the complex number object. The example is in Complex Numbers.
In the next chapter, we’ll look at various kinds of sequences. Python defines some generic method functions that apply to any of the various classes of sequences. The string and list classes, both of which are special kinds of sequences, have several methods functions that are unique to strings or lists.
For example:
>>> "Hi Mom".lower()
'hi mom'
Here, we call the lower() method function, which belongs to the string object "Hi Mom".
When we describe modules in Components, Modules and Packages, we’ll cover module functions. These are functions that are imported with the module. The array module, for example, has an array() function that creates array objects. An array object has several method functions. Additionally, an array object is a kind of sequence, so it has all of the methods common to sequences, also.
file objects have an interesting life cycle, also. A file object is created with a built-in function, file(). A file object has numerous method functions, many of which have side-effects of reading from and writing to external files or devices. We’ll cover files in Files, listing most of the methods unique to file objects.
The suite within a compound statement is typically indented four spaces. It is often best to set your text editor with tab stops every four spaces. This will usually yield the right kind of layout.
We’ll show the spaces explicitly as ⎵ in the following fragment.
def⎵max(a,⎵b): ⎵⎵⎵⎵if⎵a⎵>=⎵b: ⎵⎵⎵⎵⎵⎵⎵⎵m⎵=⎵a ⎵⎵⎵⎵if⎵b⎵>=⎵a: ⎵⎵⎵⎵⎵⎵⎵⎵m⎵=⎵b ⎵⎵⎵⎵return⎵m
This is has typical spacing for a piece of Python programming.
Also, limit your lines to 80 positions or less. You may need to break long statements with a \ at the end of a line. Also, parenthesized expressions can be continued onto the next line without a \. Some programmers will put in extra () just to make line breaks neat.
Names. Function names are typically mixedCase(). However, a few important functions were done in CapWords() style with a leading upper case letter. This can cause confusion with class names, and the recommended style is a leading lowercase letter for function names.
In some languages, many related functions will all be given a common prefix. Functions may be called inet_addr(), inet_network(), inet_makeaddr(), inet_lnaof(), inet_netof(), inet_ntoa(), etc. Because Python has classes (covered in Data + Processing = Objects) and modules (covered in Components, Modules and Packages), this kind of function-name prefix is not used in Python programs. The class or module name is the prefix. Look at the example of math and random for guidance on this.
Parameter names are also typically mixedCase. In the event that a parameter or variable name conflicts with a Python keyword, the name is extended with an _. In the following example, we want our parameter to be named range, but this conflicts with the builtin function range(). We use a trailing _ to sort this out.
def integrate( aFunction, range_ ):
"""Integrate a function over a range."""
...
Blank lines are used sparingly in a Python file, generally to separate unrelated material. Typicaly, function definitions are separated by single blank lines. A long or complex function might have blank lines within the body. When this is the case, it might be worth considering breaking the function into separate pieces.
Docstrings. The first line of the body of a function is called a docstring. The recommended forms for docstrings are described in Python Extension Proposal (PEP) 257.
Typically, the first line of the docstring is a pithy summary of the function. This may be followed by a blank line and more detailed information. The one-line summary should be a complete sentence.
def fact( n ):
"""fact( number ) -> number
Returns the number of permutations of n things."""
if n == 0: return 1L
return n*fact(n-1L)
def bico( n, r ):
"""bico( number, number ) -> number
Returns the number of combinations of n things
taken in subsets of size r.
Arguments:
n -- size of domain
r -- size of subset
"""
return fact(n)/(fact(r)*fact(n-r))
The docsting can be retrieved with the help() function.
Here’s an example, based on our fact() shown above.
>>> help(fact)
Help on function fact in module __main__:
fact(n)
fact( number ) -> number
Returns the number of permutations of n things.
Note that you will be in the help reader, with a prompt of (END). Hit q to quit the help reader. For more information, see Getting Help.