From lists to generators
I was working on a section of my Checkers game code a few days ago. It looked like this:
class Checkerboard(object): def legal_moves(self, state): return state.captures or state.moves
The behavior above mirrors the standard Checkers rule that if you have a capture, you must take it — otherwise, you can make a regular move. In my code, both state.captures and state.moves are properties that return Python lists. Since an empty list evaluates to False in an or statement, if state.captures is empty, then the return statement automatically uses state.moves list instead.
Now I was trying to make the legal_moves method work a bit faster and use less memory, so I switched to generators instead. Oops … now the code above fails since state.captures and state.moves now return generator objects. The legal_moves method above doesn’t work because state.captures is always a valid object instance and it always evaluates to True in the or statement — even when there are no actual captures available.
It took some thought to come up with an equivalent behavior for generator objects. In the new version, legal_moves becomes a wrapper method that returns one generator object or the other based on whether the first generator object yields at least one item.
class Checkerboard(object): def legal_moves(self, state): return state.captures if state.captures.next() else state.moves
It’s not as elegant as the version using lists, but it works.
No commentsNo comments yet. Be the first.
Leave a reply