5.4 可调用API和复杂性

    我们一起看一下这个API是如何应对逻辑由简单变为复杂的。如下是对于输策略的加注逻辑(也称为鞅投注系统)。

    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

    通过将loss方法中的stage乘2来完成加注逻辑。加注操作会一直进行,直到赢一局,补偿之前的损失;或者达到了下注的最大值;或者破产了。玩牌时通常添加下注最大值来阻止不断的加注。

    每当赢一局,重置为第1次的下注数额。相应地,stage变量也会被重置为1。

    为了维护接口的稳定。需要完成如bet.win += 1这样的代码逻辑时,可通过创建特性来根据输赢的变化维护状态值的改变。我们只关心setter特性,可为了更清晰地创建setter特性,需要定义getter特性。

    可根据如下代码这样使用此类。

    >>> bet= BettingMartingale()
    >>> bet()
    1
    >>> bet.win += 1
    >>> bet()
    1
    >>> bet.loss += 1
    >>> bet()
    2

    API的逻辑仍然很简单:如果赢了,赢的数量累加并重置下注对象;如果输了,输的数量累加并翻倍下注。

    特性的加入使得类的定义看起来很臃肿。我们只关心setter而非getter,因此可像如下代码使用setattr()()函数来简化类定义。

    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

    我们使用了setattr()函数来监控winloss值的变化。另外,使用了super().setattr()函数设置了实例变量值,同时也更新了下注数额。

    这个类定义更好一些。使用了可调用对象中的两个属性来作为API。