need guidance on easiest way to do this. i have multiple assets, each with multiple data points. I’m looking to assign a value to each asset based on decisions on each of these data points. As an example, each asset being a house, and data points including number of windows, garage door, broken fence, etc., each house would have a score.
Is there a recommended way of coding this besides the hundreds of if statements and adding/subtracting from a score?
Example of how I plan to do this
def score_house(house):
# score house
score = 0
if (house.windows > 2): score += 10
if (house.garage): score += 10
if (house.fence == 'broken'): score += 80
return score
I think you can also use the "chain of responsibility" pattern here:
The pattern allows multiple objects to handle the request without coupling sender class to the concrete classes of the receivers. The chain can be composed dynamically at runtime with any handler that follows a standard handler interface.
What is good about using this pattern is that you can define and extend different scorers in separate modules and combine them dynamically at runtime based on problem conditions. Here is how you can do it. First, define a parent scorer class:
from functools import reduce
class BaseScorer(object):
def __init__(self):
self._next_scorer = None
def set_next(self, scorer):
self._next_scorer = scorer
return scorer
def _call_next(self, house, score):
if self._next_scorer is None:
return score
return self._next_scorer.score(house, score)
def score(self, house, score=0):
raise NotImplementedError
@staticmethod
def chain(scorers):
reduce(lambda x, y: x.set_next(y), scorers)
return scorers[0]
Then, define various scorer classes, for example:
class WindowScorer(BaseScorer):
def score(self, house, score=0):
if house.windows > 2:
score = score + 10
return self._call_next(house, score)
class GarageScorer(BaseScorer):
def score(self, house, score=0):
if house.garage:
score = score + 10
return self._call_next(house, score)
class FenceScorer(BaseScorer):
def score(self, house, score=0):
if house.fence == 'broken':
score = score - 5
return self._call_next(house, score)
And this is how it can be used:
scorer = BaseScorer.chain([
WindowScorer(),
GarageScorer(),
FenceScorer()
])
house = House(windows=4, garage=True, fence='nice')
score = scorer.score(house)