Python – Assigning Instance Variables in `__init__` vs Called Function

python

If I need to have a function do some processing in order to initialize multiple of the object's variable (I'm having a hard time coming up with a simple example that doesn't seem weird).

Which of the following patterns is preferable?

class foo( object ):
    def __init__(self, bar, bar2):
        self.bar = bar
        self.baz, self.square_baz = self.func(bar2)

    def func(self, bar2):
        return self.bar + bar2, bar2 * ba2

Or

class foo( object ):
    def __init__(self, bar, bar2):
        self.bar = bar
        self.func(bar2)

    def func(self, bar2):
        self.baz = self.bar + bar2
        self.square_baz = bar2 * bar2

I feel like in the first pattern, the __init__ constructor and the processing func are nicely decoupled. And it's easy to tell what variables each instance of foo will contain. On the other hand, having to return multiple variables from a function to assign them to an object seems… ugly, yet this seems to be a consequence of the library I'm using.

Best Answer

There is no official place to register all instance variables in Python, nor can there be, since one can add new instance variables dynamically, at any point in the object's lifetime.

Still, it's nice to have a single place to look (and for IDEs to look, as @RemcoGerlich says) to identify what instance variables are typically in play. My solution is to initialize all common instance variables in __init__, even if just to a dummy None value that will be quickly overwritten. This avoids the uglier multiple value assignment, yet gives humans and IDEs alike a single place to look for an overview of values.

class foo(object):
    def __init__(self, bar, bar2):
        self.bar = bar
        self.baz = None
        self.square_baz = None
        self.func(bar2)

    def func(self, bar2):
        self.baz = self.bar + bar2
        self.square_baz = bar2 * bar2

This example uses a standard, "public" method name func as the initializer. If func would normally be called from outside the class, this makes sense. Often, however, the function called from __init__ will be private (usually called only by the class, and either just once or infrequently). In that case, you can give further clarity by giving it a more indicative name, and by using an underscore prefix to the method name, which conventionally means "this is a private method." So I might call it _initialize or _finish_initialization for example. (Technically speaking, Python doesn't have "private methods," at least not in the enforced-scope way languages like Java do. Private methods are managed by convention/idiom, even if unenforced.)

Related Topic