I do not like object-oriented programming
I started my career writing Smalltalk programs. It is a language with the purest object-oriented style. Everything's an object of some class. I strongly believed it was a proper way to represent reality. Later I changed my mind dramatically. Now I think the proper way to write code is to keep it minimalistic and practical.
To demonstrate the idea I have written two versions of Conway's Game of Life in python. The first one follows the object-oriented style.
import random
class Cell(object):
? ? def __init__(self, x, y, val, field):
? ? ? ? self.x, self.y = x, y
? ? ? ? self.val = val
? ? ? ? self.field = field
? ? def get_new_value(self):
? ? ? ? neighbors = field.get_neighbors(self.x, self.y)
? ? ? ? neighbors_alive = 0
? ? ? ? for cell in neighbors:
? ? ? ? ? ? neighbors_alive += cell.val
? ? ? ? if neighbors_alive == 2:
? ? ? ? ? ? val = self.val
? ? ? ? elif neighbors_alive == 3:
? ? ? ? ? ? val = 1
? ? ? ? else:
? ? ? ? ? ? val = 0
? ? ? ? return val
class Field(object):
? ? def __init__(self, h, w):
? ? ? ? self.h, self.w = h, w
? ? ? ? self.cells = [[None] * w for i in range(h)]
? ? ? ? for i in range(h):
? ? ? ? ? ? for j in range(w):
? ? ? ? ? ? ? ? val = random.randint(0, 1)
? ? ? ? ? ? ? ? self.cells[i][j] = Cell(i, j, val, self)
? ? def step(self):
? ? ? ? new_cells = [[None] * self.w for i in range(self.h)]
? ? ? ? for i in range(self.h):
? ? ? ? ? ? for j in range(self.w):
? ? ? ? ? ? ? ? val = self.cells[i][j].get_new_value()
? ? ? ? ? ? ? ? new_cells[i][j] = Cell(i, j, val, self)
? ? ? ? self.cells = new_cells
? ? def get_neighbors(self, x, y):
? ? ? ? neighbors = []
? ? ? ? for i in range(-1, 2):
? ? ? ? ? ? for j in range(-1, 2):
? ? ? ? ? ? ? ? # sentinel
? ? ? ? ? ? ? ? if (
? ? ? ? ? ? ? ? ? ? x + i < 0
? ? ? ? ? ? ? ? ? ? or y + j < 0
? ? ? ? ? ? ? ? ? ? or x + i == self.h
? ? ? ? ? ? ? ? ? ? or y + j == self.w
? ? ? ? ? ? ? ? ? ? or (i == 0 and j == 0)
? ? ? ? ? ? ? ? ):
? ? ? ? ? ? ? ? ? ? continue
? ? ? ? ? ? ? ? neighbors.append(self.cells[x + i][y + j])
? ? ? ? return neighbors
field = Field(10, 10)
for t in range(100):
? ? field.step()
Here I aggressively follow the object-oriented paradigm and represent classes of the Field and the Cell. The first problem here is that the Cell class is too simplistic. By introducing it we inject redundant methods and unnecessary complexity. The second problem is that these classes have to keep references to each other. It complicates the logic as well.
Let's move to the second version.
领英推荐
import numpy as np
from scipy.signal import convolve2d
field = np.random.randint(0, 2, size=(10, 10))
kernel = np.ones((3, 3))
for i in range(100):
? ? new_field = convolve2d(field, kernel, mode="same")
? ? field = (new_field == 3) + (new_field == 4) * field
That's it. 9 lines of code to do the same job. There are few ideas to explain:
Moreover, the second version is more efficient. Convolution uses matrix dot product implicitly which is formally and practically faster.
I save shareholders from headaches and sleepless nights by bringing order and subordinating chaos to rules. I solve problems, motivate teams to achieve goals, and streamline processes to deliver outstanding results.
3 个月??