Initializers, Methods, and Instance Variables

In Python, the class definition typically contains function definitions (“methods” in object-oriented parlance) that define the “behavior” of instances of the class. A special function, named __init__(...), is used to initialize new instances of the class when they are created.

class Horse:
    def __init__(self, color="sorrel"):
        self.color = color

The first parameter to all methods in a class is a reference to the instance (object) of the class being manipulated. By Python convention, this parameter is named self, but it doesn’t really matter to the Python compiler. In other object-oriented languages, like Java and C++, this parameter is implicit (not specified explicitly) and instead the reserved word this is used to reference the current object.

Using this very short class definition, it is possible to create multiple horses with different colors.

silver = Horse("white")
trigger = Horse("palomino")
wilbur = Horse("palomino")
buck = Horse("buckskin")
secretariat = Horse()

If the color is not specified in the contructor (e.g., the secretariat example), the default color (“sorrel”) is used.

The statement

        self.color = color

assigns to the instance of the variable color associated with the current object (self), the value of the specified parameter named color. Note that instance variable names and parameter names can be the same; using the dot notation is needed to disambiguate them.

The statement

print(trigger.color)

prints “palomino” to the console.

Instance variables are not declared in Python (unlike Java and C++). They are created automatically by references to self. These references can be in the initializer method (__init__), in some other method, or just in code that references an instance of that class.

Consider this expanded Horse example.

class Horse:
    def __init__(self, color="sorrel"):
        self.color = color

    def setBreed(self, breed):
        self.breed = breed;

silver = Horse("white")
trigger = Horse("palomino")
wilbur = Horse("palomino")
buck = Horse("buckskin")

print(trigger.color)

trigger.setBreed("grade")
print(trigger.breed)

trigger.gender = "stallion"
print(trigger.gender)

The color instance variable is set in the initializer method, so that all instances of the Horse class have a color, even if Horse() is called with no arguments (defaulting to “sorrel”).

The breed instance variable is created and set by the setBreed method.

The gender instance variable is created and set by this code inline.

Note that instance variables are created dynamically when assigned a value. If no value is assigned, no instance variable is created. So, for example, the code sequence:

flicka = Horse()
print(flicka.color)
print(flicka.breed)

Prints “sorrel”, but then crashes with the error “AttributeError: Horse instance has no attribute ‘breed'”. Since the setBreed(...) method was not called on the object referenced by flicka, nor was the breed variable explicitly set, the instance variable did not exist. Note that the error message says the Horse instance has no attribute ‘breed’. This phrasing is precise, since it says that the attribute is missing in this particular instance (object).

A typical convention is to assign values to all instance variables in the initializer, which forms a kind of documentation–identifying which variables the class is expecting to see in each instance. For example, the Horse initializer could be rewritten as

    def __init__(self, color="sorrel"):
        self.color = color
        self.breed = "unknown"
        self.gender = None

indicating that (1) the color can be specified as an initializer parameter, but defaults to “sorrel”, (2) the breed is “unknown”, and (3) the gender is not set to any value (None). Even though the gender is not set, it does exist as a variable in the class instances, so accessing it no longer gives an error, returning None instead.