Python Code Blocks: Functions
Contents
7. Python Code Blocks: Functions#
7.1. Lesson overview#
A function is a labelled code block that is executed when its name is called. When writing longer Python programs, we may notice sections of code that have a similar logical pattern. We can bundle up that logic into one defined code block called a function, and instead of repeating the same lines of code many times over, we simply call the function with one line of code. This creates a more manageable code base with fewer lines of duplicated code throughout our program. In this lesson, we will explain how to write functions, how to return the output of a function, how to pass arguments to a function, and explore how variables are scoped between function code blocks.
Definition: function
A labelled code block that executes when its name is called.
7.2. Creating a function#
Creating a simple function is straightforward in Python. Let us look at the example code below that creates the
function test()
:
def test():
print("running test function")
The first line has the command def test():
which is the function declaration statement that starts the code block.
The keyword def
stands for “define”, as in we are
defining our function, and test
is the name we give to the function. Function declarations require two parenthesis
()
after the function name. Finally, there is the colon :
which ends the function declaration statement. The
subsequent indented code contains the code block that the function will represent. In this case, the function will
print out the string running test function
to the terminal.
After we have defined our function, we can call it by typing test()
:
test()
running test function
The parenthesis ()
after test
means we are calling the function. This will execute the code block of the function.
If we do not include ()
, the function will not be called and the code block will not be executed. The importance of
using ()
after the function’s name is demonstrated below:
def test():
print("running test function")
print("Without ():")
test
print("With ():")
test()
Without ():
With ():
running test function
Hey! Listen!
Remember that consistent indentation inside a code block is required in Python. See Creating Code Blocks for more info.
7.2.1. Example: Insert name here#
Create a function called my_name()
that prints out the statement,
My name is [NAME].
where [NAME] is your name. After creating the function, demonstrate that it works.
Solution:
This short example demonstrates the basics in creating and using a function. The code block below uses the name of
Goldy Gopher when creating my_name()
.
# Print out name to shell
def my_name():
print("My name is Goldy Gopher!")
# Calling function
my_name()
My name is Goldy Gopher!
7.3. Returning an output#
In our example above, the output of the function is printed out. However, we may want a function to do a bunch of
operations on some input and then return the result instead of simply printing it out.
We can do this by using the return
keyword to return the function output, which we can assign to a variable. The code below demonstrates how return
is used in a function:
# Convert Fahrenheit to Celsius
def convert_f_to_c(temp):
celsius = (temp - 32) * (5/9)
return celsius
temp_c = convert_f_to_c(5)
print("Temp in C:", temp_c)
Temp in C: -15.0
In this example we have defined a function convert_f_to_c()
that takes in one argument temp
(arguments will be explained in the next section), which represents a temperature in the
Fahrenheit scale. Our function converts temp
to the Celsius scale and assigns the value to the variable celsius
.
The return celsius
command returns the output of the function. Note that if we do not return the output, then
temp_c
will get assigned a None
value, because the function will have returned nothing.
We can also return multiple outputs from a function through the return
keyword. The code below demonstrates how
this can be done by modifying our convert_f_to_c()
function:
# Convert Fahrenheit to Celsius
def convert_f_to_c(temp):
celsius = (temp - 32) * (5/9)
units = "celsius"
return celsius, units
temp_c, unit = convert_f_to_c(5)
print("Temp:", temp_c)
print("Unit:", unit)
Temp: -15.0
Unit: celsius
Here, the return
statement is now written as return celsius, units
to signify we want the variables celsius
and units
returned in that order. In this example, we then assign temp_c
to take the first (i.e., celsius
) and
unit
takes the second output (i.e., units
) when convert_f_to_c(5)
is called.
If you only assign one variable to a multiple output return statement, you will instead get a tuple of the outputs joined together:
output = convert_f_to_c(5)
print("Tuple of outputs:",output)
print("Data type of variable \"output:\"", type(output))
Tuple of outputs: (-15.0, 'celsius')
Data type of variable "output:" <class 'tuple'>
7.3.1. Example: Temperature conversion#
Using the function convert_f_to_c()
from the section above, create a code block that converts the following list of
temperatures:
Temperatures to convert: 68 oF, -319 oF, 150.2 oF, and 901.4 oF
Use the following guidelines and tips when creating your code:
Create a
list
calledtemp_f
that stores the starting temperatures.In its current state,
convert_f_to_c()
will not accept alist
as an argument. If you do this, you will get an error. Instead, use afor
loop to pass each value one at a time into the function.Store your converted temperatures into a new
list
object calledtemp_c
. You will need to first initialize this object without any value. This can be done with either the commandtemp_c = []
ortemp_c = list()
.Converted temperatures can be added to
temp_c
using the.append()
method for lists. Look online for examples on how to use this useful method!
Solution:
This example demonstrates how our increasing knowledge in Python allows us to adapt previously made code for new
applications. Since convert_f_to_c()
only accepts single values as an input (e.g., an int
or float
object) we
utilize a for
loop to access each temperature one at a time. An example solution is shown below:
# Convert Fahrenheit to Celsius
def convert_f_to_c(temp):
celsius = (temp - 32) * (5/9)
return celsius
# List of
temp_f = [68, -319, 150.2, 901.4]
# Initialize converted list
temp_c = []
# Loop over all entries in temp_f
for i in temp_f:
celsius_temp = round(convert_f_to_c(i),1)
temp_c.append(celsius_temp)
# Display converted temperatures
print("Temp in C:", temp_c)
Temp in C: [20.0, -195.0, 65.7, 483.0]
7.4. Arguments#
A variable that is passed into a function is called an
argument. Arguments allow us to pass in data to the
function. In the previous example, the function convert_f_to_c()
has one argument, the temp
variable. The name
of the argument as defined in the function and is passed to the function’s code block as a variable. When we call
convert_f_to_c(5)
, the value 5
is passed as the argument and gets assigned to the variable temp
in the function’s
code block.
Definition: argument
A variable that is passed into a function.
7.4.1. Positional arguments#
In our function convert_f_to_c(temp)
, the position in which temp
is passed into the function (in this case that
temp
is actually passed into the function) is critical for the function to work. If we call convert_f_to_c()
without passing any arguments we will get an error:
temp_c = convert_f_to_c()
print("Temp in C:", temp_c)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [9], in <cell line: 1>()
----> 1 temp_c = convert_f_to_c()
2 print("Temp in C:", temp_c)
TypeError: convert_f_to_c() missing 1 required positional argument: 'temp'
The output TypeError: convert_f_to_c() missing 1 required positional argument: 'temp'
mentions that we are missing
a positional argument. Positional arguments are
arguments that are passed into a function in a specific
order. For this example, the Python shell is expecting temp
to be the first variable passed into. Since no variable
is passed into the function, a positional error is flagged.
Definition: positional arguments
Arguments that are passed into a function in a specific order.
As you can probably guess, functions can be called using multiple positional arguments. An example of this is shown below:
def convert_f(temp, units):
# Convert temp to Celsius
new_temp = (temp - 32) * (5/9)
if units == "K":
new_temp += 273.15
return new_temp
temp_k = convert_f(5, "K")
print('Temp in K:', temp_k)
Temp in K: 258.15
Here, convert_f()
requires two arguments to be passed to it. When we call convert_f(5, 'K')
, the order of the
arguments are assigned from left to right, so 5
is assigned to temp
and 'K'
is assigned to units
. The Python
shell automatically knows what variables to assign each argument to because of their position when passed into the
function (hence the name “positional arguments”). Since the specific order that arguments are passed into a function
matters when using positional arguments, an incorrect order can result in an error. See the example below in which
we flip the argument order:
temp_k = convert_f("K", 5)
print('Temp in K:', temp_k)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [11], in <cell line: 1>()
----> 1 temp_k = convert_f("K", 5)
2 print('Temp in K:', temp_k)
Input In [10], in convert_f(temp, units)
1 def convert_f(temp, units):
2 # Convert temp to Celsius
----> 3 new_temp = (temp - 32) * (5/9)
4 if units == "K":
5 new_temp += 273.15
TypeError: unsupported operand type(s) for -: 'str' and 'int'
Since the shell is expecting a float
or int
value for temp
and not a str
, and error is reported when
new_temp
is assigned. In short, be very mindful of the specific order you pass positional arguments into a
function!
7.4.2. Keyword arguments#
Another way we can pass an argument into a function is by associating an argument to a specific identifier (i.e., a keyword) that is associated with the function’s code block. Arguments that are passed this way are called keyword argument, and are useful as there is no ambiguity into what each argument represents.
Definition: keyword arguments
Arguments that are assigned an identifying keyword when passed into a function.
For example, let us demonstrate how keyword arguments can be used with our convert_f()
function. The example below
shows how to pass our two input variables as keyword arguments:
temp_k = convert_f(temp = 5, units = "K")
print("Temp in K:", temp_k)
Temp in K: 258.15
When using keyword arguments, we pass arguments using the format keyword = value
. Since the arguments are explicitly
defined, the specific order how they are passed into the function do not matter. For example, the code below flips the
positional order of the keyword arguments with no issue:
temp_k = convert_f(units = "K", temp = 5)
print("Temp in K:", temp_k)
Temp in K: 258.15
Overall, calling a function using keyword arguments is a helpful for following the logic and readability of your Python code.
7.4.3. Common errors when passing arguments#
There are a few common errors to watch out for when passing arguments into functions. For example, if we mix keyword and positional arguments we will see the following error:
temp_k = convert_f(temp = 5, "K")
print("Temp in K:", temp_k)
Input In [14]
temp_k = convert_f(temp = 5, "K")
^
SyntaxError: positional argument follows keyword argument
The error SyntaxError: positional argument follows keyword argument
is reporting that we tried to pass a positional
argument after a keyword argument, which we cannot do. When calling a function, all positional arguments must be
listed first before any keyword arguments.
A similar error will occur if we try to pass too many arguments into a single variable. An example of this is shown below:
temp_k = convert_f(5, temp = 10)
print("Temp in K:", temp_k)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [15], in <cell line: 1>()
----> 1 temp_k = convert_f(5, temp = 10)
2 print("Temp in K:", temp_k)
TypeError: convert_f() got multiple values for argument 'temp'
Here, the error TypeError: convert_f() got multiple values for argument 'temp'
is reporting that we already passed
a value to temp
with the first positional argument, so passing temp = 10
afterwards caused an error. Likewise, if
you pass more arguments than what a function is expecting, Python will report an error:
temp_k = convert_f(5, "K", 10)
print("Temp in K:", temp_k)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [16], in <cell line: 1>()
----> 1 temp_k = convert_f(5, "K", 10)
2 print("Temp in K:", temp_k)
TypeError: convert_f() takes 2 positional arguments but 3 were given
The error TypeError: convert_f() takes 2 positional arguments but 3 were given
reports that convert_f()
only
accepts two arguments (i.e., temp
and units
), but the function received three arguments which caused the error.
7.4.4. Assigning default values to arguments#
Sometimes it is useful to assign a default value to an argument if that value is commonly used. An added benefit to doing this is that these arguments no longer need to be assigned during every function call. The code below demonstrates this concept using a function that converts a temperature from one of the four common temperature scales (Celsius, Fahrenheit, Kelvin, or Rankine) to another temperature scale:
def convert_temp(temp, output_unit = "K", input_unit = "F"):
# Convert input temp to Kelvin
if input_unit == "F":
temp_k = (temp - 32) * (5 / 9) + 273.15
elif input_unit == "C":
temp_k = temp + 273.15
elif input_unit == "R":
temp_k = temp * (5 / 9)
# Convert Kelvin to desired output
if output_unit == "F":
new_temp = ((temp_k - 273.15) * (9 / 5)) + 32
elif output_unit == "C":
new_temp = temp_k - 273.15
elif output_unit == "R":
new_temp = temp_k * (9 / 5)
elif output_unit == "K":
new_temp = temp_k
return new_temp, output_unit
temp, unit = convert_temp(5)
print(f"Temp in {unit}:", round(temp,1))
Temp in K: 258.1
As seen above, our function takes in three arguments. Notice that two of the arguments are assigned values in the
def
line by using the keyword argument notation from earlier (i.e., output_unit = "K"
and input_unit = "F"
).
It is through this process that we can declare a default value for an argument. Notice though that the argument temp
has not been assigned a default value. Therefore, any time we want to call convert_temp()
, we will need to provide an
argument for temp
. This can be done using a positional argument, like shown in the example above, or using a keyword
argument:
temp, unit = convert_temp(temp = 10)
print(f"Temp in {unit}:", round(temp,1))
Temp in K: 260.9
Even though we have defined default values to both output_unit
and input_unit
, we can override them during a
function call by either using a positional or keyword argument. An example of this is shown below:
temp, unit = convert_temp(5, "F", "C")
print(f"Temp in {unit}:", round(temp,1))
Temp in F: 41.0
Here, the function call convert_temp(5, 'F', 'C')
assigns 5
to temp
, 'F'
to output_unit
, and C
to
input_unit
, which follows the argument order of the function. The function then returns the value 41.0
, which
makes sense since \(5 \ ^o C = 41 \ ^o F\). However, overriding default values is not an “all or nothing” situation. We
can also selectively choose which argument values to override while retaining the default state for other arguments.
An example of this is shown in the code below:
temp, unit = convert_temp(5, input_unit = "C")
print(f"Temp in {unit}:", round(temp,1))
Temp in K: 278.1
In this example, we choose to only override the default value for input_unit
while still using the default value
for output_unit
. There are limits to how the Python shell will accept a mixed ordering of default and non-default
arguments. For example, all arguments that do NOT have a default value must be listed prior to the arguments that will
have a default value. This requirement in Python prevents possible positional argument errors from originating during
later function calls as the shell will not be able to link a positional argument to the appropriate non-default valued
argument. The example below shows what will happen if you fail to do this:
def convert_temp(temp = 10, output_unit, input_unit = "F"):
# Convert input temp to Kelvin
if input_unit == "F":
temp_k = (temp - 32) * (5 / 9) + 273.15
elif input_unit == "C":
temp_k = temp + 273.15
elif input_unit == "R":
temp_k = temp * (5 / 9)
# Convert Kelvin to desired output
if output_unit == "F":
new_temp = ((temp_k - 273.15) * (9 / 5)) + 32
elif output_unit == "C":
new_temp = temp_k - 273.15
elif output_unit == "R":
new_temp = temp_k * (9 / 5)
elif output_unit == "K":
new_temp = temp_k
return new_temp, output_unit
temp, unit = convert_temp("C")
print(f"Temp in {unit:}:", round(temp,1))
Input In [21]
def convert_temp(temp = 10, output_unit, input_unit = "F"):
^
SyntaxError: non-default argument follows default argument
Here, the error SyntaxError: non-default argument follows default argument
occurring in Line 1 (i.e., during the
creation of the function using the def
keyword) indicates that an argument without a default value is being listed
prior to an argument that has a default value. A simple fix to this error is to switch the order of the arguments in
the def
line so that output_unit
(i.e., the argument without a default value) is listed first:
def convert_temp(output_unit, temp = 10, input_unit = "F"):
# Convert input temp to Kelvin
if input_unit == "F":
temp_k = (temp - 32) * (5 / 9) + 273.15
elif input_unit == "C":
temp_k = temp + 273.15
elif input_unit == "R":
temp_k = temp * (5 / 9)
# Convert Kelvin to desired output
if output_unit == "F":
new_temp = ((temp_k - 273.15) * (9 / 5)) + 32
elif output_unit == "C":
new_temp = temp_k - 273.15
elif output_unit == "R":
new_temp = temp_k * (9 / 5)
elif output_unit == "K":
new_temp = temp_k
return new_temp, output_unit
temp, unit = convert_temp("C")
print(f"Temp in {unit:}:", round(temp,1))
Temp in C: -12.2
Now the function works according to plan!
Hey! Listen!
When looking through Python code, you sometimes may see function definitions that include the syntaxes *args
and/or
**kwargs
, like for example,
def do_stuff(a, b = 3, *args, **kwargs):
.
Both of these syntaxes are known as
arbitrary argument lists, and allow
a function to be called with any number of arguments. The *args
syntax allows for a list
of
positional arguments and the **kwargs
syntax allows for a dict
of keyword arguments. Arbitrary argument
lists are useful in situations where functions are calling other functions, which then call even more functions.
The use of *args
or **kwargs
allows arguments to pass through multiple functions so each
function can get the arguments it needs.
7.5. Variable scoping in code blocks#
A typical Python program will use many variables across many code blocks, so it is important to keep in mind the scope of a variable’s name across blocks of code. The scope represents how visible a variable’s name is seen throughout the code. Depending on how a variable is defined, the scope of a variable may be visible throughout the entire code or only within a small code block. This is demonstrated in the follow example:
num = 1 #### Start code block 1, global scope
def multi_twenty(num): #### Start code block 2, local scope
# multiply num by 20 # local scope
print("local num:", num) #
print("id num:", id(num)) #
num = num * 20 # local scope
return num #### End of code block 2, local scope
big_num = multi_twenty(5) #
print("Big num", big_num) #
print("global num:", num) #
print("id num:", id(num)) #### End of code block 1, global scope
local num: 5
id num: 140693339324784
Big num 100
global num: 1
id num: 140693339324656
In this example, we assign a variable named num
in two places. We first assign num
the value 1
in code block 1,
and then assign num
a different value (via a recursive value of num * 20
) in the function multi_twenty
, which is
part of code block two. Each of these code blocks have a different variable scope for num
. Code block one, has a
global variable scope as it is the “outermost” code block.
Code block two, which is an “inner” code block, has a local variable scope inside the code
block. When we call multi_twenty(5)
, we assign 5
to num
in the function, which is technically a different
variable named num
from the globally scoped num
variable in the first line of code. This is proven using the
function id()
that shows each num
variable is referencing two different memory locations.
Definition: scope
How visible a variable’s name is seen throughout the code.
It is important to note that variables assigned in a higher scope can be read in a local scope. The example below
demonstrates with the globally scoped variable C_RATIO
:
# global scope
C_RATIO = 5/9
# code block scope (functional scope)
def convert_f_to_c(temp):
celsius = (temp - 32) * C_RATIO
return celsius
temp_c = convert_f_to_c(5)
print("Temp in C:", temp_c)
Temp in C: -15.0
Here, we see that C_RATIO
is read inside the function convert_f_to_c()
even though it was not passed as an
argument. If we created a new variable called C_RATIO
inside of convert_f_to_c()
, this new variable would have
been used instead of the original value (i.e., see the previous example using our multi_twenty()
function).
All in all, failure to keep the scope of variables in mind for your code can lead to unintended consequences.
Hey! Listen!
While not required for a program to work, it is recommended to name global variables using all uppercase letters.
For instance, in the above example we wrote C_RATIO = 5/9
instead of c_ratio = 5/9
. While there is no
functional difference between uppercase and lowercase variable names, uppercasing global variables makes it easier
to understand which variables are intended to be global in scope.
7.6. Docstrings and help()
#
It is important to document how your function operates in case another user (or even yourself) would like to reuse
your function on a later date. A docstring is a string
that follows after the function definition statement (i.e., the line with def
) and provides a place to describe
what a function does, the arguments that are passed into the function, details about the arguments, and the function
returns.
Docstrings are built into all functions in Python. To create a docstring we use the multi-line string notation
(i.e., a str
that starts and ends with three single or double quotes) on the line after the def
line. The code
below demonstrates how a docstring can be used with our convert_temp()
function from earlier:
def convert_temp(temp, output_unit='K', input_unit='F'):
"""
Convert temperature from one unit to another. Returns temperature and output_unit.
Arguments:
temp: Numeric temperature to be converted
output_unit: String designating the output unit. Can be one of 'F', 'C', 'R', 'K'. Default is 'K'
input_unit: String designating the input unit. Can be one of 'F', 'C', 'R', 'K'. Default is 'F'
Returns:
new_temp: New temperature
output_unit: Unit of the new temperature
"""
# Convert input temp to Kelvin
if input_unit == "F":
temp_k = (temp - 32) * (5 / 9) + 273.15
elif input_unit == "C":
temp_k = temp + 273.15
elif input_unit == "R":
temp_k = temp * (5 / 9)
# Convert Kelvin to desired output
if output_unit == "F":
new_temp = ((temp_k - 273.15) * (9 / 5)) + 32
elif output_unit == "C":
new_temp = temp_k - 273.15
elif output_unit == "R":
new_temp = temp_k * (9 / 5)
elif output_unit == "K":
new_temp = temp_k
return new_temp, output_unit
As mentioned above, docstrings utilize the multi-line string format in which the string content is bounded between
triple quotes (here we used """
). As a side note, besides being used for docstrings, the multi-line string format
is a useful format whenever you need to create a string that needs to span multiple lines of code:
multi_line_string = """
We can type
multiple lines
in a triple quoted string.
"""
print(multi_line_string)
We can type
multiple lines
in a triple quoted string.
Docstrings act as the documentation for a function, so accessing this documentation is important when coding. One easy
way to access a function’s docstring is to utilize the built-in Python function
help()
. The help()
function is an extremely useful
tool when trying to understand how a function works. We will utilize help()
many times going forward, but for now
let’s try using help()
on our convert_temp()
function by issuing the following command:
help(convert_temp)
Help on function convert_temp in module __main__:
convert_temp(temp, output_unit='K', input_unit='F')
Convert temperature from one unit to another. Returns temperature and output_unit.
Arguments:
temp: Numeric temperature to be converted
output_unit: String designating the output unit. Can be one of 'F', 'C', 'R', 'K'. Default is 'K'
input_unit: String designating the input unit. Can be one of 'F', 'C', 'R', 'K'. Default is 'F'
Returns:
new_temp: New temperature
output_unit: Unit of the new temperature
Here, you can see that the return is the entire docstring for the function! There are numerous ways to format a docstring, and sometimes when browsing Python source code, you may see docstrings in this format:
def convert_temp_docs(temp, output_unit='K'):
"""
Convert temperature from one unit to another. Returns temperature and output_unit.
:param temp: Temperature that will be converted
:type: float
:param output_unit: String designating the output unit. Can be one of 'F', 'C', 'R', 'K'. Default is 'K'
:type: str
"""
pass
This is an example of the ReStructuredText
format for styling docstrings. By developing a docstring format, documentation generators can automatically
create documentation based on the docstring of the functions and classes. It is important to note the
ReStructuredText keywords :param
, :type
, and :return:
are not part of the function definition, they are just
helpful hints for documentation generation. There are several other style guides that exist for Python docstrings,
and you can search for them online to find one that works for you. By following the rules of a docstring style guide
will allow clear and readable documentation of your code.
7.6.1. Example: Documenting your work#
Using what you have learned so far with this guide, create a function that converts a force between one of the three most commonly used force units (i.e., newtons (N), pound-force (lbf), and dyne (dyn)). The conversion between the three unit scales is,
1 N = 0.225 lbf = 100,000 dyn
Input arguments should include the starting force’ value, the starting force’s units, and the desired units. Set default values for the initial units and the final units to be newtons and pound-force, respectively. Include a way for the function to display an error if the starting or desired units are not one of the three units. Finally, include a docstring that follows the ReStructuredText format.
Solution:
There are a few ways to code this function. The example code below builds off of the
earlier temperature conversion function by first converting the starting force to newtons and then
converting to the desired force. A chain of if
, elif
, and else
keywords are used for the logic checks. Error
handling is done by passing strings through the function that state that an error has been caused. These can be
registered by viewing the returned variables. While this is works for our needs, there are more effective ways to
address error states using logging reports called tracebacks. An
upcoming lesson will show you how to utilize tracebacks for documenting errors. Finally,
note the use of the ReStructuredText documentation format for the docstring. While not mandatory when creating
function, adding a docstring, even if it is written in plain text, is useful for explaining how function operates.
def convert_force(initial_force, initial_units="N", converted_units="lbf"):
"""
Convert force between newtons, pound force, and dynes. Returns the
converted force and units.
:param initial_force: Force to be converted
:type: float
:param initial_units: Initial units of force. Allowable values are
"N", "lbf", and "dyn". Default value is "N"
:type: str
:param converted_units: Units of force to be converted to. Allowable
values are "N", "lbf", and "dyn". Default value is "N"
:type: str
:return:
- converted_force - converted force value (type: float)
- converted_units - final units (type: str)
"""
# Convert force to N to standardize
if initial_units == "N":
force_N = initial_force
elif initial_units == "lbf":
force_N = initial_force / 0.225
elif initial_units == "dyn":
force_N = initial_force / 100000
else:
force_N = "\"incorrect initial force units\""
# Convert to new units
if force_N == "\"incorrect initial force units\"":
converted_force = force_N
elif converted_units == "N":
converted_force = force_N
elif converted_units == "lbf":
converted_force = force_N * 0.225
elif converted_units == "dyn":
converted_force = force_N * 100000
else:
converted_force = "\"incorrect converted force units\""
converted_units = ""
return converted_force, converted_units
To test the basic “functionality” of this function, the code below converts 10 N of force to pounds-force. We should get 2.25 lbf.
converted_force, converted_units = convert_force(10)
print(f"The converted force is {converted_force} {converted_units}")
The converted force is 2.25 lbf
Since we are using the default values for initial_units
and converted_units
, we do not need to include them in
the argument list. For readability, however, it is sometimes better to include them:
converted_force, converted_units = convert_force(10, initial_units="N", converted_units="lbf")
print(f"The converted force is {converted_force} {converted_units}")
The converted force is 2.25 lbf
Let’s now try converting 2,536.2 dyn to newtons. We should get 0.025362 N, which is shown in the code below:
converted_force, converted_units = convert_force(2536.2, initial_units="dyn", converted_units="N")
print(f"The converted force is {converted_force} {converted_units}")
The converted force is 0.025362 N
The code block below demonstrates how the function handles an incorrect desired unit:
converted_force, converted_units = convert_force(2536.2, initial_units="dyn", converted_units="bad")
print(f"The converted force is {converted_force} {converted_units}")
The converted force is "incorrect converted force units"
Finally, to show that the docstring works for this function, we issue the help()
command:
help(convert_force)
Help on function convert_force in module __main__:
convert_force(initial_force, initial_units='N', converted_units='lbf')
Convert force between newtons, pound force, and dynes. Returns the
converted force and units.
:param initial_force: Force to be converted
:type: float
:param initial_units: Initial units of force. Allowable values are
"N", "lbf", and "dyn". Default value is "N"
:type: str
:param converted_units: Units of force to be converted to. Allowable
values are "N", "lbf", and "dyn". Default value is "N"
:type: str
:return:
- converted_force - converted force value (type: float)
- converted_units - final units (type: str)
Depending on your programming environment, your help()
return may display the docstring in either plain text or as
ReStructuredText format. Here, the shell returns the docstring in a plain text format.
7.7. Conclusion#
An important “Pythonic” principle is to avoid having duplicated code throughout a program. With a function, we
define a reusable code block that accepts input arguments and returns an output. From here, we can call this code
block many times throughout a program and issue different arguments to this code block without having to rewrite
code. Functions can have variables passed into them using both positional arguments and keyword arguments, and we
can also define default values for arguments. Each function’s code block has its own variable scope in which it
operates, which is important to track in order to prevent unintended behavior from a program. Finally, documenting
how a function works is an extremely important part of function creation. The use of docstrings in Python makes
function documentation easy to create, and the built-in function help()
makes it very easy to read a function’s
docstring.