Conway's Game of Life implemented in Python

I'm a Python novice and decided to give Game of Life a try in Python 3:

import os
import time
import curses

class Cell:
newlabel = ''
def __init__(self,row,col,label):
self.row = row
self.col = col
self.label = label

def updatecell(self,celllist, boardsize):
liveneighbours = self.getliveneighbours(celllist, boardsize)
if liveneighbours < 2 or liveneighbours > 3: #Kills cell if it has <2 or >3 neighbours
self.newlabel = ' '
elif liveneighbours == 2 and self.label == ' ': #Cell doesn't come alive if it is dead and only has 2 neighbours
self.newlabel = ' '
else: #Cell comes alive if it is already alive and has 2/3 neighbours or if it is dead and has 3 neighbours
self.newlabel = 0

def getliveneighbours(self,celllist,boardsize):
count = 0
for row in range(self.row-1,self.row+2):
try:
celllist[row]
except:    #Handles vertical wrapping. If there's an error, it checks the wrapped cell
if row < 0:
row += boardsize[0]
else:
row -= boardsize[0]
for col in range(self.col-1,self.col+2):
try: #Handles horizontal wrapping. If there's an error, it checks the wrapped cell
celllist[row][col]
except:
if col < 0:
col += boardsize[1]
else:
col -= boardsize[1]
if not celllist[row][col].label:
count += 1
if not self.label: #Subtracts the cell from the neighbours count
return count-1
else:
return count

def updatelabel(self): #Updates the cell's label after all cell updates have been processes
self.label = self.newlabel

class Board:
celllist = {} #Dict of rows
def __init__(self, rows, columns):
self.rows = rows
self.columns = columns
self.generate()

def printboard(self): #Prints the board to the terminal using curses
for num, row in self.celllist.items():
line = ''
for col, cell in enumerate(row):
line += str(cell.label)
terminal.refresh()

def generate(self): #Adds all the cells to the board
for row in range(self.rows-1):
self.celllist[row] = []
for col in range(self.columns):
self.celllist[row].append(Cell(row,col,' '))

def updateboard(self): #Prompts each cell to update and then update their label
for row in self.celllist:
for cell in self.celllist[row]:
cell.updatecell(self.celllist, (self.rows-1, self.columns))
for row in self.celllist:
for cell in self.celllist[row]:
cell.updatelabel()

if __name__ == "__main__":
terminal = curses.initscr() # Opens a curses window
curses.noecho()
curses.cbreak()
terminal.nodelay(1) #Don't wait for user input later
rows, columns = os.popen('stty size', 'r').read().split()
board = Board(int(rows), int(columns))
board.celllist[6][8].label = 0
board.celllist[7][9].label = 0
board.celllist[7][10].label = 0
board.celllist[8][8].label = 0
board.celllist[8][9].label = 0
while 1:
board.printboard()
time.sleep(0.1)
board.updateboard()
char = terminal.getch()
if char == 113: #Checks for ASCII Char code for q and then breaks loop
break
curses.endwin() #Closes curses window


I've written it to work based on your terminal size and I've made the sides wrap around because it was the only solution I could think of. Also, at the end, I've included a glider example as a test.

Questions:

1. Is my implementation pythonic enough (particularly concerning ranges and my constant use of iteration)?

2. Are the data structures that I've used for the celllist (arrays in a dict) suitable?

3. Is curses a good way of displaying the game? Would pyGame be better?

4. Is the overall code style good?

5. To further develop this, is there a better algorithm I could implement or a better method (other than wrapping the sides) of displaying all the cells?

1. Running your code through pycodestyle will highlight some issues to make the code more familiar to Pythonistas. Other than that:
• while 1 should be written as while True (Explicit is better than implicit)
• Rather than checking for a specific character to quit I would just assume that people know about Ctrl-c
• Use as easily readable names as possible. updatecell, for example, could be update_cell or even update since it's implicit that it's the Cell that's being updated.
• Usually if __name__ == "__main__": is followed by simply main() or sys.exit(main()) (probably not relevant in your case). This makes the code more testable. Aim to minimize the amount of top-level code in general.
2. The board is really a matrix, so it would IMO be better to represent it using a list of lists or ideally a matrix class. A dict has no intrinsic order, so semantically it's the wrong thing to use in any case.
3. Somebody else will have to answer this.
4. This is too subjective to answer.
5. Some suggestions:
• Try to take into account the fact that the Game of Life board is infinite in all directions. Ideally your implementation should handle this, but you could also use it as a stop condition - when things get too close to the edge to be able to figure out the next step with certainty the program could stop.
• You can avoid conversions between numbers and strings by using numbers or even booleans everywhere (for example stored in a value or state field rather than label). You can then write a separate method to display a Board, converting values to whatever pair of characters you want, and possibly with decorations.
• Rather than updating Cells individually by saving their new value you can replace the entire Board with a new one at each step.
• The time.sleep() currently does not take into account that the Board update time might change. This is unlikely to be a problem for a small board, but if you want completely smooth frames you'll want to either use threads or a tight loop which checks whether it's time to print the current Board yet.
• Thanks! How would I do this: "Rather than updating Cells individually by saving their new value you can replace the entire Board with a new one at each step." ? – HydraulicSheep Apr 3 '18 at 5:02
• You currently populate the newlabel field and then updatelabel once all the Cells are processed. You can avoid re-entering each Cell by creating the new Board based on the current Board, conceptually replacing newlabel with newboard. – l0b0 Apr 3 '18 at 6:18