Functions vs Methods in DNA Analysis Project (Learn Python 2)

Hi,

In the DNA analysis exercise (https://www.codecademy.com/courses/learn-python/projects/dna), why are they referring to functions as methods? And if read_dna(), match_DNA(), is_criminal() etc. really are methods instead of functions, why don’t we call them using dot notation?

Here’s the code I’m referring to:

sample = [‘GTA’,‘GGG’,‘CAC’]

def read_dna(dna_file):
dna_data = ‘’
with open(dna_file, ‘r’) as f:
for line in f:
dna_data += line
return dna_data

def dna_codons(dna):
codons =
for i in range(0, len(dna), 3):
if (i+3) < len(dna):
codons.append(dna[i:i+3])
return codons

def match_dna(dna):
matches = 0
for codon in dna:
if codon in sample:
matches += 1
return matches

def is_criminal(dna_sample):
dna_data = read_dna(dna_sample)
codons = dna_codons(dna_data)
num_matches = match_dna(codons)
if num_matches >= 3:
print ‘%s codons matched. Continue the investigation.’ % num_matches
else:
print ‘%s codons matched. Release suspect.’ % num_matches

is_criminal(‘suspect1.txt’)
is_criminal(‘suspect2.txt’)
is_criminal(‘suspect3.txt’)

I think that might be a rather generic description of what they do rather than the terminology you might find in the Python docs. In the same way they might call them operations, procedures, tasks or something in the vein. It’s an unfortunate fact of life many definitions are kind of muddy in programming.

So long as you can recognise the difference then you’re all good.

1 Like

When we consider that a function is a member of the class ‘function’ it gets even muddier, or, perhaps less muddy? Take Ruby, for instance. There are no functions, only methods, yet the code looks very similar to Python (in so many respects).

Whenever we define a new function we’re instantiating another member of the ‘function’ class.

>>> def foo():
	pass

>>> type(foo)
<class 'function'>
>>> bar = lambda x: x
>>> type(bar)
<class 'function'>
>>> 

In codespeak, in Python and JavaScript, a method is one that must be called on an object of which it is a member. A function is called with the object as its argument, not its execution context.

Eg.

str is a class. The tools we use to access them are largely methods of that class. .split, .join, .upper, .lower, and so on.

Being a form of iterable, a str object is subscriptable and so has a last index value, one more of which is the count, or length in character terms. Funny, though, it does not have a .length attribute. It doesn’t need it.

The len() function is able to take in any iterable and find the first non-existent index, which it is happy to return. Many objects are themselves valid arguments for this function.

len('some str object')    #  15

Furthermore, because a method has an execution context, it will have a self to which all the attributes of the given instance are bound. We won’t very often see the keyword used in a functional context.

>>> foobar = lambda self, x: self.x
>>> foobar(42)
Traceback (most recent call last):
  File "<pyshell#73>", line 1, in <module>
    foobar(42)
TypeError: <lambda>() missing 1 required positional argument: 'x'
>>> 
1 Like

My favourite bit of that is that Python actually has a method type but it’s rarely discussed as a method. Instead there are halfway houses like a method is a function owned or bound to a class.

But they’re still function types until that attribute lookup from an instance. Then they’re promoted to actually being “methods” (as far as types go).

I think I prefer the generic terminology of a method being a function being bound to some type (or at least I’m more used to it).

class SillyClass: def func(x): return x + 2 inst = SillyClass() print(f"The type of SillyClass.func is: {type(SillyClass.func)}") print(f"The type of inst.func is: {type(inst.func)}") print(f"Calling func bound to the class: {SillyClass.func(3)}") try: inst.func(3) except TypeError as err: print(f"Calling func from an instance... fails:\n{type(err)}... {err}") def monkey_patch(self, x): return x + 2 SillyClass.func = monkey_patch print( f"By virture of being called from an instance our monkey patch " f"is a method: {type(inst.func)}" ) print(inst.func(3)) method = inst.func print(method.__func__ == SillyClass.func)

Once we have a general idea (‘generic’) it’s all moot, it would seem. The writer simply loves threading words… (blush)

I think I’ve just accepted a compromise somewhere that no matter which way I choose to use it, which way the documentation states or what popular opinion of the day chooses there will always be someone who uses it in a completely different manner :sweat_smile:.

Sometimes the poking around and discussion is essential, even if only for this reason, to see what everyone else is thinking.

1 Like

Ah I see, I thought I’d misunderstood what was going on. Thanks for explaining!

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.