Makoto Kuwata <k...@kuwata-lab.com> writes: > On Thu, Feb 16, 2017 at 6:53 AM, Erik <pyt...@lucidity.plus.com> wrote: >> >> (Python code examples of what you think is "bad" vs "good" would be >> useful). > > You are right. > > Bad code Example: > > # > https://codewords.recurse.com/issues/one/an-introduction-to-functional-programming > > from random import random > > def move_cars(car_positions): > return map(lambda x: x + 1 if random() > 0.3 else x, > car_positions) > > def output_car(car_position): > return '-' * car_position > > def run_step_of_race(state): > return {'time': state['time'] - 1, > 'car_positions': move_cars(state['car_positions'])} > > def draw(state): > print '' > print '\n'.join(map(output_car, state['car_positions'])) > > def race(state): > draw(state) > if state['time']: > race(run_step_of_race(state)) > > race({'time': 5, > 'car_positions': [1, 1, 1]})
Here's a rewrite in functional style, which I consider somewhat better than the original: from random import random def move(positions): return [ pos + bool(random() > 0.3) for pos in positions ] def race(positions, steps): for step in range(steps): positions = move(positions) yield positions def draw(positions): print(*('-' * pos for pos in positions), sep = '\n') if __name__ == '__main__': for step, positions in enumerate(race([1,1,1], 5)): step and print() draw(positions) I did a number of things, but mainly I reconceptualized the race itself explicitly as a sequence of positions. While a Python generator is an extremely stateful object, with some care it works well in functional style. > Refactoring example: > > from random import random > > class Car(object): > > def __init__(self): > self.position = 1 > > def move(self): > if random() > 0.3: > self.position += 1 > return self.position > > class Race(object): > > def __init__(self, n_cars=3): > self._cars = [ Car() for _ in range(n_cars) ] > > def round(self): > for car in self._cars: > car.move() > > def report(self): > print("") > for car in self._cars: > print('-' * car.position) > > def run(self, n_rounds=5): > self.report() > for _ in range(n_rounds): > self.round() > self.report() > > if __name__ == '__main__': > Race(3).run(5) If you want to refactor bad code into better code, it would be more honest to start with code that is already in your preferred style. That would be a good lesson. Now you've taken questionable code in a somewhat functional style and refactored it into object-oriented style. But you don't call them that. You call them bad code and good code. That's a bad lesson. It conflates issues. Take good functional code, refactor it into your preferred style. Also do the reverse. That would be a good lesson, assuming your students are ready for such discussion. -- https://mail.python.org/mailman/listinfo/python-list