Functions, Classes, and Methods in Python

This is a brief note about the differences between functions and methods in Python, specifically with respect to the syntax of defining and calling them. It also reviews the various terms, ideas, and syntax related to classes and objects.

There is a glossary at the bottom of this page; please refer to it if you're confused by any of the phrasing used in the discussion below. I've tried to keep the discussion relatively concise, which means using shorthand terminology, so again, refer to the glossary if you need help decoding the shorthand.

Functions

In Python, the signature of a function (which is part of its definition) looks very similar to the code used to call that function.

def lineOverrun(text, line_length):
    return max(0, len(text) - line_length)

line = "The quick brown log rolled down the lazy stairs."
extra = lineOverrun(line, 80)

Note that the number of arguments specified in the signature is the same as the number of arguments we pass when we call the function. (To be really technical: the number of formal parameters is equal to the number of actual parameters.) When the function runs, the variable specified as the  first argument  in the function definition takes on the value of the variable given as the  first argument  in the call to the function. Same is true for the second argument. So the arguments exactly parallel each other in the call and the signature.

Classes and Objects

An object is an individual, distinct “thing” in the world of a program. Each object is an instance of a class — that is, it's a single entity with a distinct identity, but it is conceptually related to all other objects of that same class.

So one of the fundamental tasks of an object-oriented design process is to design and define classes, so that we can then solve problems with instances (objects) of those classes. In other words, before we can use a particular hammer to solve a problem, we must first define what a hammer is, conceptually.

A class describes a “conceptual bubble” — each instance of a class contains a number of data values, and is therefore in charge of them. The technical name for these data values is instance variables. (Member variables is an alternative name, particularly when we're talking about the formal members of a class, rather than things belonging to a particular instance of that class.)

Each instance of a class also carries along with it a selection of specialized capabilities — things that it can do, when asked by something on the outside, based on its knowledge and understanding of its member data. We express these capabilities by defining methods for the class. A method is just a specialized type of function that is part of a class.

Let's take a look at an example. Here we're defining the idea of a hammer that has a particular weight and a particular amount of wear. Every time we hit something with the hammer, the wear increases.

class Hammer:
    def __init__(self, initial_weight):
        self.weight = initial_weight
        self.wear = 0.0
    
    def hit(self, nail_height, speed):
        force = self.weight*speed
        self.wear = self.wear + force
        return nail_height / force

Note that, after Python has executed this code, no actual hammers exist in the program! All we've done is define a class; we've said what a hammer would be like if we ever chose to create one and use it.

We've defined two methods for the class Hammer: __init__() and hit().

Constructing Objects and Calling Methods

Though methods are really just functions defined as part of a class, we call them using a slightly different syntax. Here I've expanded the code above to include some client code that uses the class to create an object and then work with it.

class Hammer:
    def __init__(self, initial_weight):
        self.weight = initial_weight
        self.wear = 0.0
    
    def hit(self, nail_height, speed):
        force = self.weight*speed
        self.wear = self.wear + force
        return nail_height / force
    
    def getWear(self):
        return self.wear

sledge = Hammer(5.0)
nail = 2.0
print("Nail height:", nail)
for hit_number in range(5):
    nail = sledge.hit(nail, 3.0)
    print("After a hit:", nail)
print("Total wear:", sledge.getWear())

In this code, we first define the class Hammer, along with all its properties (the member variables) and capabilities (the methods). Note that we've defined an additional method, getWear(), in order to find out the wear on a given hammer once we've used it. (Stricly speaking, this method is unnecessary; we'll discuss this more in class. It's just here to provide an additional example of a method.)

After the class definition is some client code that uses this definition to create a Hammer object and work with it. Let's go line by line:

Glossary and Thesaurus of Object-Oriented Terms

There are a lot of equivalent terms or phrases used to express the same ideas when discussing topics related to objects and classes.

Class
A conceptual category or type of thing, as distinct from any specific individual thing that belongs to that class. The definition of a class describes the properties and capabilities that any particular instance of that class will have.
Object

An individual thing that belongs to some class. We call this an “instance” of that class. Equivalent phrases to describe a particular object include:

  • “An instance of the class Thingie
  • “an object of class Thingie
  • “a Thingie object”
  • “a Thingie
Member Variable

A variable stored as a part of an object. The class to which that object belongs is what defines the member variables that the object has. Member variables are also known as “data members” or “instance variables”, or collectively as “member data”.

No one on the outside should need to know or care about the internal details of the object's state; it is the responsibility solely of the object itself to keep track of its state and make sense of it. This is the essential purpose of object-oriented design: separation of concerns. Only the object needs to work with the member variables, and the logic of this work is encoded in the class's definition.

Has

When we say that a particular object “has” a particular data member, we mean that that data member is defined as a part of that object, with a name that is only accessible using the dot operator on that object.

We may also say that a class “has” a particular data member, when all objects of that class have that data member. We can see this in the definition of the class because we will have written self.bar to indicate the bar data member that this class (and therefore every object of this class) has.

Synonyms for saying that an object or class has something are to say that it “owns” or “contains” that thing.

State
In computing in general, the state of something at a particular moment is the value it has at that moment, or the values that each of its constituent parts has. So the state of a program is the collective term for the value that each variable in the program has at one particular moment. The state of an object is the collective term for the value that each of its member variables has.
Client
The client is the code that uses a class (or objects of that class) to solve some problem or engage in some action.
Method

A method is a function that is defined as part of a class; conceptually, it is a capability of every object of that class. The primary purpose of a method is for client code to be able to ask a specific object to perform some action. We'll refer to the “target” of a method to indicate the particular object that was asked to perform that method.

The particular actions taken by the target when it performs some method may depend on the state of the target. An object, as a “conceptual bubble”, is in charge of understanding what its state means, and interpreting that state accordingly to decide what to do when performing the method.

This means that the client must specify a particular object in order to run a method: different objects have their own separate state, and so the computations involved in a method may be different for one object than for another. The client specifies the target of a method by putting it before the . operator.

When the client specifies a target and asks the target to run some method, there are a variety of shorthand terminologies: we may say that it runs the method “on” the target, or “with” the target, or even “from” the target.

(There are a couple of exceptions to the “every-method-must-have-a-target” rule, but we won't really get into them.)

.

The . operator is the way we access things that are defined as a part of something else. So foo.bar means “the bar that is part of foo” or “the bar that is inside foo”.

The way you say . when reading code out loud is “dot”.

So far in this course we have seen two different things come before the dot: modules and objects. (Remember, a module is what you get when you say import such_and_so.)

We have also seen two different things come after the dot: variables and functions. When a function is defined as part of a class (and therefore is accessed by putting a dot after the name of an object of that class), we call it a “method”.