5.18. Functions and methods#
This is a central concept in programming. It provides a means of encapsulating several lines of code (that do something useful) and providing a reference such that this block can be called in multiple places in a larger program.
5.18.1. Builtin functions#
We have already been using some built-in functions. These are print()
, type()
, int()
, etc.
Here are the key patterns to using functions that you need to remember.
They have a name by which you refer to them, e.g.
print
ortype
You “invoke” or “call” a function using
()
after the name. Henceprint()
.Typically, functions take “arguments”. An argument, is a variable that will be operated on by the function. For example:
text = "Hello World"
print(text)
Hello World
In the above, the argument is text
.
The built in functions range()
and sum()
are widely used. The former for generating the range of indices required to loop over elements in a series. The latter is as the name implies.
Note
Use help()
for more detailed information about how to use range()
and sum()
.
Another useful builtin function is sorted()
. As the name implies, this takes a series and returns a copy with the elements ordered [1].
nums = [3, 0, 6, 1]
sorted(nums)
[0, 1, 3, 6]
The original object is left unmodified.
nums
[3, 0, 6, 1]
5.18.2. Python is an object oriented language#
A precursor to understanding methods is to understand what is meant by an “object”.
As the title states, Python belongs to a class of programming languages called “object oriented”. The success of “object oriented” programming languages (there are many) arise (at least in part) from the fact they encourage modularisation of code. This modularisation reduces the number of lines of code and makes the resulting programs easier to write, to check for bugs, and thus to maintain.
So what is an “object”? It’s an abstract concept, but in essence an object represents something. It can be a number, a string, a file, etc.. Thus “objects” are instances of a type of data.
So what’s an instance? An instance is an occurrence of a type of data, which will have a location in memory that is different to other occurrences of the same type of data. I’ll use the built-in function id()
(which returns a unique identifier, related to the address in memory):
a = [3, 0, 6, 1]
id(a)
140711733282432
b = [3, 0, 6, 1]
id(b)
140711733096064
Although a
and b
are equivalently defined – both lists of exactly the same integers – they are not the same instance.
5.18.3. Methods#
Which leads us to methods. A method is a function bound to a specific object that applies to the data encapsulated in that instance.
This means that when you call a method on one object, it only operates on that object. I’ll demonstrate that by using a method on lists to sort the elements.
a.sort()
a
[0, 1, 3, 6]
b
[3, 0, 6, 1]
You can see that a
was affected, while b
was not.
So with a method, it operates on the specific instance of data to which it’s bound. For a function, you need to explicitly provide the data to the function as an argument as we did in our above usage of the builtin function sorted()
. To use a method, you don’t need to provide the data it will operate on, but for a function you do.
Here are the key patterns for using a method:
You access them (which is also known as referencing them) using the
"."
notation, e.g.some_variable.a_bound_method
where the instance issome_variable
and the method isa_bound_method
.You use them like all functions (see the above), except you do not provide the data, e.g.
some_variable.a_bound_method()
.
Simple!
5.18.4. So how do I use methods and functions?#
There are some general principles in how to use functions and methods. First, using help()
will show you what arguments a function or method can take
The function signature lists the required and optional arguments.
Required arguments are listed first. In this case, the name of that argument tells you it must be an “iterable” object.
Optional arguments are listed as <argumemt name>=<default value>. In this case, there are two optional arguments. One called
key
, another calledreverse
.Return value. The help text tells us this function will return a new list with members sorted in ascending order.
5.18.4.1. Functions#
Focussing on functions first. If a function is what we call a void function then it operates only on the arguments you give it and returns nothing [2]. The obvious example of this is print()
. Fruitful functions actually return a value. You can establish what type that value will be by either reading help (see Interpreting help() for a function) or running an experiment (calling the function with some data).
Actually, in Python every function and method returns something. Void functions and methods return None
(try it on print()
).
While functions and methods are very similar they have a very important difference. Functions nearly always require the data they will operate on be provided as an argument. (In the following, the reversed()
function returns a generator. Wrapping it in a call to list()
is necessary to complete the statement.)
data = [0, 1, 2, 3]
list(reversed(data))
[3, 2, 1, 0]
Methods, on the other hand, are already bound to the data they operate on.
data = [0, 1, 2, 3]
data.reverse()
data
[3, 2, 1, 0]
5.18.4.2. Methods#
It becomes a little bit trickier when we talk about methods. That said, the strategy suggested above of using help()
or simple experiments applies here too.
Recalling that methods are bound to the data they operate on, we can divide methods into those which:
describe the data
transform the data
Consider the string "GGTCATGAAGGTC"
. Example string methods that describe the data are find()
, startswith()
. In these cases, the method will return a value.
seq = "GGTCATGAAGGTC"
seq.find("ATG")
4
In an interactive interpreter (like Jupyter which we’ve used here), the returned value is displayed. In order to use the information, we have to assign it to a variable which we now do.
orf_start = seq.find("ATG")
These descriptive methods are pretty simple to comprehend. The challenge comes when you start using methods that transform the data. Again, using help()
on the object is the most reliable approach.
The help indicates the return value will be a string transformed such that the all characters are lower case except the first character.
In this example given in Interpreting help() for a method, a new string will be returned. This means the original instance will be unchanged.
text = "HELLO WORLD"
capitalized = text.capitalize()
text
'HELLO WORLD'
capitalized
'Hello world'
If we were working on a list
type, however, transforming methods do not return a value and in fact are void methods. Instead the data in the instance is modified itself.
words = ["HELLO", "WORLD"]
words.reverse() # reverse the item order
words
['WORLD', 'HELLO']
This leads us to a general principle
Note
If a data type is immutable (e.g. strings, tuples), then any transformation methods will return a new instance of the same type. Thus you must assign the returned value of a method call on an immutable type in order to use it! If instead the type is mutable (e.g. lists, dicts) then the data of the existing instance is modified in-place.
5.18.5. A useful trick for concatenating strings#
Getting help on a string method that can be used to concatenate.
help("".join)
Help on built-in function join:
join(iterable, /) method of builtins.str instance
Concatenate any number of strings.
The string whose method is called is inserted in between each given string.
The result is returned as a new string.
Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs'
Note
All elements of the series must be of type str
.
data = ["AAA", "CCC"]
"".join(data)
'AAACCC'
"-".join(data)
'AAA-CCC'
"\t".join(data)
'AAA\tCCC'
5.19. Exercises#
For the built-in
len
, is it a function or a method? Demonstrate its usage.Join the
data
variable from above with the new line character.Construct an example that shows how to use
sum()
The variable
data
is defined above as a list of two trinucleotides. Usingrange()
, print each element ofdata
and its index. Your output should look likeAAA 0 CCC 1
The code snippets in Functions versus Methods both result in a reversed ordering of their input. What are all the other differences between the two?