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.

  1. They have a name by which you refer to them, e.g. print or type

  2. You “invoke” or “call” a function using () after the name. Hence print().

  3. 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:

  1. You access them (which is also known as referencing them) using the "." notation, e.g. some_variable.a_bound_method where the instance is some_variable and the method is a_bound_method.

  2. 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

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).

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.

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#

  1. For the built-in len, is it a function or a method? Demonstrate its usage.

  2. Join the data variable from above with the new line character.

  3. Construct an example that shows how to use sum()

  4. The variable data is defined above as a list of two trinucleotides. Using range(), print each element of data and its index. Your output should look like

    AAA 0
    CCC 1
    
  5. 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?