Search code examples
pythonclassconstructorinstance-variables

Instance variables in methods outside the constructor (Python) -- why and how?


My questions concern instance variables that are initialized in methods outside the class constructor. This is for Python.

I'll first state what I understand:

  1. Classes may define a constructor, and it may also define other methods.
  2. Instance variables are generally defined/initialized within the constructor.
  3. But instance variables can also be defined/initialized outside the constructor, e.g. in the other methods of the same class.
  4. An example of (2) and (3) -- see self.meow and self.roar in the Cat class below:

    class Cat():
    
        def __init__(self):
            self.meow = "Meow!"
        def meow_bigger(self):
            self.roar = "Roar!"
    

My questions:

  1. Why is it best practice to initialize the instance variable within the constructor?

  2. What general/specific mess could arise if instance variables are regularly initialized in methods other than the constructor? (E.g. Having read Mark Lutz's Tkinter guide in his Programming Python, which I thought was excellent, I noticed that the instance variable used to hold the PhotoImage objects/references were initialized in the further methods, not in the constructor. It seemed to work without issue there, but could that practice cause issues in the long run?)

  3. In what scenarios would it be better to initialize instance variables in the other methods, rather than in the constructor?


  1. To my knowledge, instance variables exist not when the class object is created, but after the class object is instantiated. Proceeding upon my code above, I demonstrate this:

    >> c = Cat() 
    >> c.meow
    'Meow!'
    >> c.roar
    Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
    AttributeError: 'Cat' object has no attribute 'roar'
    >>> c.meow_bigger()
    >>> c.roar
    'Roar!'
    

    As it were:

    • I cannot access the instance variable (c.roar) at first.
    • However, after I have called the instance method c.meow_bigger() once, I am suddenly able to access the instance variable c.roar.
    • Why is the above behaviour so?

Thank you for helping out with my understanding.


Solution

  • Why is it best practice to initialize the instance variable within the constructor?

    Clarity.

    Because it makes it easy to see at a glance all of the attributes of the class. If you initialize the variables in multiple methods, it becomes difficult to understand the complete data structure without reading every line of code.

    Initializing within the __init__ also makes documentation easier. With your example, you can't write "an instance of Cat has a roar attribute". Instead, you have to add a paragraph explaining that an instance of Cat might have a "roar" attribute, but only after calling the "meow_louder" method.

    Clarity is king. One of the smartest programmers I ever met once told me "show me your data structures, and I can tell you how your code works without seeing any of your code". While that's a tiny bit hyperbolic, there's definitely a ring of truth to it. One of the biggest hurdles to learning a code base is understanding the data that it manipulates.

    What general/specific mess could arise if instance variables are regularly initialized in methods other than the constructor?

    The most obvious one is that an object may not have an attribute available during all parts of the program, leading to having to add a lot of extra code to handle the case where the attribute is undefined.

    In what scenarios would it be better to initialize instance variables in the other methods, rather than in the constructor?

    I don't think there are any.

    Note: you don't necessarily have to initialize an attribute with it's final value. In your case it's acceptable to initialize roar to None. The mere fact that it has been initialized to something shows that it's a piece of data that the class maintains. It's fine if the value changes later.