1

I have been trying to attempt a small program that will simulate Conway's game of Life. However the error TypeError: step() missing 1 required positional argument: 'self' keeps on appearing. I have looked for a solution but nothing I try seems to work.

Here is my code:

from tkinter import *
root = Tk()

class Cell (Button):
    Dead = 0
    Live = 1

    def __init__ (self,parent):
        Button.__init__(self,parent, relief = "raised" , width = 2 , borderwidth = 1 , command = self.onpress)
        self.displayState(Cell.Dead)

    def onpress (self):
        if self.state == Cell.Live:
            self.displayState(Cell.Dead)
        elif self.state == Cell.Dead:
            self.displayState(Cell.Live)

    def setNextState (self , Neighbours):
        if self.state == Cell.Live and (Neighbours < 2 or Neighbours > 3):
            self.nextState = Cell.Dead
        elif self.state == Cell.Dead and Neighbours == 3:
            self.nextState = Cell.Live
        elif self.state == Cell.Dead and Neighbours != 3:
            self.nextState = self.state

    def stepToNextState(self):
        self.displayState(self.nextState)

    def displayState (self , newstate):
        self.state = newstate
        if self.state == Cell.Live:
            self["bg"] = "black"
        if self.state == Cell.Dead:
            self["bg"] = "white"

class Grid:
    def __init__(self,parent,sizex,sizey):
        self.sizex = sizex
        self.sizey = sizey
        self.cells = []
        for a in range (0,self.sizex):
            rowcells = []
            for b in range (0, self.sizey):
                c = Cell(parent)
                c.grid(row=b , column=a)
                rowcells.append(c)
            self.cells.append(rowcells)

    def step (self):
        cells = self.cells
        for x in range (0,self.sizex):
            if x==0: x_down = self.sizex-1
            else: x_down = x-1
            if x==self.sizex-1: x_up = 0
            else: x_up = x+1
            for y in range(0,self.sizey):
                if y==0: y_down = self.sizey-1
                else: Y_down = y-1
                if y==self.sizey-1: y_up = 0
                else: y_up = y+1
                sum = cells[x_down][y].state + cells[x_up][y].state + cells[x][y_down].state + cells[x][y_up].state + cells[x_down][y_down].state +cells[x_up][y_up].state + cells[x_down][y_up].state + cells[x_up][y_down].state
            cells[x][y].setNextState(sum)
            for row in cells:
                for cell in row:
                    cell.stepToNextState()

    def clear(self):
        for row in self.cells:
            for cell in row:
                 cell.displayState(Cell.Dead)

def GridStep():
    Grid.step()

def GridClear():
    Grid.step()

if __name__ == "__main__":
    frame = Frame(root)
    frame.pack()
    grid = Grid(frame,25,25)
    bottomFrame = Frame(root)
    bottomFrame.pack (side = BOTTOM)
    buttonStep = Button(bottomFrame , text="Step" , command=GridStep)
    buttonStep.pack(side = LEFT)
    buttonClear = Button(bottomFrame, text = "Clear", command=GridClear)
    buttonClear.pack(side=LEFT , after=buttonStep)
    root.mainloop()
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Chubzorz
  • 135
  • 1
  • 2
  • 7
  • 1
    I'm not a Pythonista, but it looks like `step` is an instance method; you're calling it on the class `Grid`. – echristopherson Mar 19 '14 at 21:51
  • please [edit] your question will the **full text** of the error, so we can see where it's occuring. – MattDMo Mar 19 '14 at 21:51
  • possible duplicate of [Python: Call method by instance object: "missing 1 required positional argument: 'self'"](http://stackoverflow.com/questions/20023986/python-call-method-by-instance-object-missing-1-required-positional-argument) – Asad Saeeduddin Mar 19 '14 at 21:56

1 Answers1

4

You have two functions that call unbound methods, directly on the class:

def GridStep():
    Grid.step()

def GridClear():
    Grid.step()

Grid is the class itself, not an instance of the class, and calling Grid.step() will not supply the self parameter as there is no instance to bind self to. You'll need to provide an instance of Grid here and call the method on that.

Instead of using GridStep and GridClear on your buttons, you'll need to pass the methods from the grid object you created:

grid = Grid(frame,25,25)
bottomFrame = Frame(root)
bottomFrame.pack (side = BOTTOM)
buttonStep = Button(bottomFrame , text="Step" , command=grid.step)
buttonStep.pack(side = LEFT)
buttonClear = Button(bottomFrame, text = "Clear", command=grid.clear)
buttonClear.pack(side=LEFT , after=buttonStep)

Note that I am passing in the bound methods to command but they are not (yet) called.

You can remove the GridStep and GridClear functions entirely then.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Thanks for the help, but now I get a new error when I try this saying that `AttributeError: 'Cell' object has no attribute 'nextState'` in the stepToNext State Function Which I don't understand. – Chubzorz Mar 19 '14 at 23:30
  • Your `Cell` instances do not have a `nextState` attribute until `setNextState` has been called, and even then only if certain conditions have been met. If you don't fully understand how this is supposed to work, perhaps best ask a *new* question though. – Martijn Pieters Mar 19 '14 at 23:36