Python __init__ method

I have a class like this:


class someClass():

     list_of_stuff = []

     def __init__(self, *args):
          print('length of list is ' + str(len(self.list_of_stuff)))
          #LIST SHOULD BE EMPTY, RIGHT????
          append stuff to the list...

I’m creating these objects in a for each loop, and the printout reveals that the list isn’t empty with each iteration.


for item in another_list:
     temp_obj = someClass()
     temp_obj.do_stuff()

What’s going on here? Isn’t a NEW object being created in each run of the for loop, therefore its data members should be empty? Am I mis-using init?

You’re declaring list_of_stuff as a class attribute, not as an instance attribute. Therefore, list_of_stuff is the shared across all instances of someClass. If you want list_of_stuff to be unique per class instance you need to add it to self in the init method:


class someClass():
  def __init__(self):
    self.list_of_stuf = []

just move list_of_stuff inside the init as self.list_of_stuff

see:

http://www.ibiblio.org/g2swap/byteofpython/read/class-and-object-vars.html

WHAT!!???

This is nuts!!! Declaring them outside of init makes them static, and inside ‘regular’? I’m a python noob, but this is craziness!!

As far as I understand it, it’s because the class is not a function, it’s a collection/object. So if it’s not inside a function that’s being called, it just floats around existing and isn’t reset.
init is a function that’s being executed, so it’ll reset the list to [], whereas having it outside will just have it reference the variable that already exists.

What’s happening is that you are adding a variable that points to your list in memory to the class when you define it. Since that pointer is identical on all your instances, when you mutate it, all the other instances are still pointing to the mutated list.

Python doesn’t automatically copy/unlink your list for you, although if you assign over the shared one from the class either in init or in your do_stuff function, it will no longer be pointing at the original list.

The same thing can bite you if you ever do this:

def function(someList=[]):
    someList.append('stuff')

every time you run the function, it mutates the list that was created as the default arg for that function, changing future calls to it.

To be honest, this is one of the coolest things about python, although it can bite you if you aren’t expecting it. (It’s really handy if you need/want to share data among class instances, like cache data for example)

Thanks for the quick responses.

It’s pure luck that anything I’ve written up to this point actually works!!!

It makes more sense when you recognize that classes (meaning, their definitions) are objects in Python, too. They are different than objects that are instances of those classes. Both of them can have attributes.

Haha, if you have trouble with init wait till you get to the really crazy stuff!