When trying to invoke def, I get: parameter 'self' unfilled

Thom Ernst picture Thom Ernst · Feb 23, 2017 · Viewed 25.3k times · Source

I'm trying to write a class to randomly pick a number of songs from a dictionary. The whole point of it is to be able to simply type DJ.chooseListing() for example to execute the random selection. Alas it gives me an error I can't really find anywhere else on the web, and I feel the answer is very simple.

class DJ:
     # put song variables here in this format: trackName = Track("string of song to be displayed", 'music/filename.ogg')
     trackRickAstleyNever = Track("Never gonna give you up", 'music/rick.ogg')
     trackShootingStars = Track("Shooting Stars", 'music/shoot.ogg')

     dictSongs = {
         # put songs here like this: 'name': varName,
         'nevergonnagiveyouup': trackRickAstleyNever,
         'shootingstars': trackShootingStars,

     }
     """
     arrayRandomized = [
         # Put future songs here in this format: songs['name'],
     ]
     """
     arrayChosen = []
     trackChosen = ""

     def chooseListing(self):
         for i in xrange(4):
             self.arrayChosen.append(random.choice(self.dictSongs))

     def chooseTrack(self):
         self.trackChosen = random.choice(self.arrayChosen)

DJ.chooseListing()

Answer

Blckknght picture Blckknght · Feb 23, 2017

A function defined in a class is a method. A method's first argument will be filled automatically when you call it on an instance of the class. You're defining a chooseListing method, but when you call it, you're not creating an instance. If there's no instance, there's nothing that can be passed as self, which leads to your exception. Try:

dj = DJ()
dj.chooseListing()

You may still need to make some other fixes to your class though, since currently all of its attributes are class attributes (which are shared by all instances). If you create mutltiple DJ instances, they will all share the same arrayChosen list, which is probably not what you intend. You should move your assignments to an __init__ method, where you can make them instance attributes (by assigning on self):

def __init__(self):
    self.dictSongs = {  # this might still make sense as a class attribute if it is constant
        'nevergonnagiveyouup': trackRickAstleyNever,
        'shootingstars': trackShootingStars,
        }
    self.arrayChosen = [] # these however should certainly be instance attributes
    self.trackChosen = ""

I left the Track instances out of the __init__ method, but that might not be correct if they have internal state that shouldn't be shared between DJs.