2. Functions and Getting Help
# Intro
In this lesson you will learn more about using and defining functions.
# Getting Help
help(round)
help()
displays two things:
- the header of that function
round(number[, ndigits])
. In this case, this tells us thatround()
takes an argument we can describe asnumber
. Additionally, we can optionally give a separate argument which could be described asndigits
. - A brief English description of what the function does.
Common pitfall: when you're looking up a function, remember to pass in the name of the function itself, and not the result of calling that function, such as help(round(-2.01))
.
# Defining functions
def least_difference(a, b, c):
diff1 = abs(a - b)
diff2 = abs(b - c)
diff3 = abs(a - c)
return min(diff1, diff2, diff3)
2
3
4
5
Functions start with a header introduced by the
def
keyword. The indented block of code following the:
is run when the function is called.
return
is another keyword uniquely associated with functions. When Python encounters areturn
statement, it exits the function immediately, and passes the value on the right hand side to the calling context.
# Docstrings(函数说明)
def least_difference(a, b, c):
"""Return the smallest difference between any two numbers
among a, b and c.
>>> least_difference(1, 5, -5)
4
"""
diff1 = abs(a - b)
diff2 = abs(b - c)
diff3 = abs(a - c)
return min(diff1, diff2, diff3)
2
3
4
5
6
7
8
9
10
11
The docstring is a triple-quoted string (which may span multiple lines) that comes immediately after the header of a function. When we call help()
on a function, it shows the docstring.
Aside: example calls The last two lines of the docstring are an example function call and result. (The
>>>
is a reference to the command prompt used in Python interactive shells.) Python doesn't run the example call - it's just there for the benefit of the reader. The convention of including 1 or more example calls in a function's docstring is far from universally observed, but it can be very effective at helping someone understand your function. For a real-world example of, see this docstring for the numpy functionnp.eye
(opens new window).
# Functions that don't return
What would happen if we didn't include the return
keyword in our function?
def least_difference(a, b, c):
"""Return the smallest difference between any two numbers
among a, b and c.
"""
diff1 = abs(a - b)
diff2 = abs(b - c)
diff3 = abs(a - c)
min(diff1, diff2, diff3)
print(
least_difference(1, 10, 100),
least_difference(1, 10, 10),
least_difference(5, 6, 7),
)
2
3
4
5
6
7
8
9
10
11
12
13
14
Python allows us to define such functions. The result of calling them is the special value None
. (This is similar to the concept of "null" in other languages.)
Without a return
statement, least_difference
is completely pointless, but a function with side effects may do something useful without returning anything. We've already seen two examples of this: print()
and help()
don't return anything. We only call them for their side effects (putting some text on the screen). Other examples of useful side effects include writing to a file, or modifying an input.
mystery = print()
print(mystery)
2
# Default arguments
print(1, 2, 3, sep=' < ')
if we don't specify a value, sep
is treated as having a default value of ' '
(a single space).
print(1, 2, 3)
Adding optional arguments with default values to the functions we define turns out to be pretty easy:
def greet(who="Colin"):
print("Hello,", who)
greet()
greet(who="Kaggle")
# (In this case, we don't need to specify the name of the argument, because it's unambiguous.)
greet("world")
2
3
4
5
6
7
# Functions Applied to Functions
You can supply functions as arguments to other functions.
def mult_by_five(x):
return 5 * x
def call(fn, arg):
"""Call fn on arg"""
return fn(arg)
def squared_call(fn, arg):
"""Call fn on the result of calling fn on arg"""
return fn(fn(arg))
print(
call(mult_by_five, 1),
squared_call(mult_by_five, 1),
sep='\n', # '\n' is the newline character - it starts a new line
)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Functions that operate on other functions are called "Higher order functions."
Here's an interesting example using the max
function.
By default, max
returns the largest of its arguments. But if we pass in a function using the optional key
argument, it returns the argument x
that maximizes key(x)
(aka the 'argmax').
def mod_5(x):
"""Return the remainder of x after dividing by 5"""
return x % 5
print(
'Which number is biggest?',
max(100, 51, 14),
'Which number is the biggest modulo 5?',
max(100, 51, 14, key=mod_5),
sep='\n',
)
2
3
4
5
6
7
8
9
10
11
# Exercise: Functions and Getting Help
Functions open up a whole new world in Python programming. Try using them yourself (opens new window)
# 1.
Complete the body of the following function according to its docstring.
def round_to_two_places(num):
"""Return the given number rounded to two decimal places.
>>> round_to_two_places(3.14159)
3.14
"""
# Replace this body with your own code.
# ("pass" is a keyword that does literally nothing. We used it as a placeholder
# because after we begin a code block, Python requires at least one line of code)
pass # we can delete pass here
return round(num,2)
q1.check()
2
3
4
5
6
7
8
9
10
11
12
13
# 2.
The help for round
says that ndigits
(the second argument) may be negative.
What do you think will happen when it is? Try some examples in the following cell?
Can you think of a case where this would be useful?
# Put your test code here
round(322.1415, -2)
2
Solution: As you've seen, ndigits=-1
rounds to the nearest 10, ndigits=-2
rounds to the nearest 100 and so on. Where might this be useful? Suppose we're dealing with large numbers:
The area of Finland is 338,424 km² The area of Greenland is 2,166,086 km²
We probably don't care whether it's really 338,424, or 338,425, or 338,177. All those digits of accuracy are just distracting. We can chop them off by calling round()
with ndigits=-3
:
The area of Finland is 338,000 km² The area of Greenland is 2,166,000 km²
(We'll talk about how we would get the commas later when we talk about string formatting 😃)
# 3.
In a previous programming problem, the candy-sharing friends Alice, Bob and Carol tried to split candies evenly. For the sake of their friendship, any candies left over would be smashed. For example, if they collectively bring home 91 candies, they'll take 30 each and smash 1.
Below is a simple function that will calculate the number of candies to smash for any number of total candies.
Modify it so that it optionally takes a second argument representing the number of friends the candies are being split between. If no second argument is provided, it should assume 3 friends, as before.
Update the docstring to reflect this new behaviour.
def to_smash(total_candies, n_friends=3):
"""Return the number of leftover candies that must be smashed after distributing
the given number of candies evenly between 3 friends.
>>> to_smash(91)
1
"""
return total_candies % n_friends
q3.check()
2
3
4
5
6
7
8
9
10
# 4.
It may not be fun, but reading and understanding error messages will be an important part of your Python career.
Each code cell below contains some commented-out buggy code. For each cell...
- Read the code and predict what you think will happen when it's run.
- Then uncomment the code and run it to see what happens. (Tip: In the kernel editor, you can highlight several lines and press
ctrl
+/
to toggle commenting.) - Fix the code (so that it accomplishes its intended purpose without throwing an exception)
round_to_two_places(9.9999) # ruound_to_two_places(9.9999)
x = -10
y = 5
# Which of the two variables above has the smallest absolute value?
smallest_abs = min(abs(x), abs(y)) # smallest_abs = min(abs(x, y))
2
3
4
def f(x):
y = abs(x)
return y # SyntaxError: 'return' outside function
print(f(5))
2
3
4
5