- Mastering Objectoriented Python
- Steven F. Lott
- 392字
- 2021-11-12 16:25:19
Complexities and the callable API
Let's see how well this API holds up as our processing becomes more complex. The following is the double-up on each loss strategy (also known as the Martingale betting system):
class BettingMartingale( BettingStrategy ): def __init__( self ): self._win= 0 self._loss= 0 self.stage= 1 @property def win(self): return self._win @win.setter def win(self, value): self._win = value self.stage= 1 @property def loss(self): return self._loss @loss.setter def loss(self, value): self._loss = value self.stage *= 2 def __call__( self ): return self.stage
Each loss doubles the betting by multiplying the stage by two. This goes on until we win and recoup our losses, reach the table limit, or go broke and can no longer place any bets. Casinos prevent this by imposing table limits.
Whenever we win, the betting is reset to the base bet. The stage is reset to have a value of one.
In order to keep the attribute interface—code such as bet.win += 1
—we need to create properties to make the state changes correctly based on the wins and losses. We only really care about the setter properties, but we must define getter properties in order to clearly create setter properties.
We can see this class in action as follows:
>>> bet= BettingMartingale() >>> bet() 1 >>> bet.win += 1 >>> bet() 1 >>> bet.loss += 1 >>> bet() 2
The API is still quite simple. We can either count the wins and reset the bet to the base, or we can count the losses, and the bets will double.
The use of properties made the class definition long and hideous. We're really only interested in the setters and not the getters, so we can use __setattr__()
to streamline the class definition somewhat, as shown in the following code:
class BettingMartingale2( BettingStrategy ): def __init__( self ): self.win= 0 self.loss= 0 self.stage= 1 def __setattr__( self, name, value ): if name == 'win': self.stage = 1 elif name == 'loss': self.stage *= 2 super().__setattr__( name, value ) def __call__( self ): return self.stage
We used __setattr__()
to monitor the updates to win
and loss
. In addition to setting the instance variables using super().__setattr__()
, we also updated the internal state for the betting amount.
This is a nicer looking class definition, and it retains the simple API as a callable object with two attributes.