Python,为优化覆盖函数的最佳方式

Python, best way to override functions for optimization

不确定如何最好地描述这个问题,但我只是想优化事情,因为我执行了这 100 次上百万次。所以我试图尽可能地消除逻辑。所以为了简单起见,让我们在下面做一个简单的 class:

class Steps():
   def __init__(self, descending, value):
      self.descending = descending
      self.value = value

   def step(self):
      if self.descending:
         self.value -= 1
      else:
         self.value += 1

   def other_funcs1(self):
      pass

   def other_funcs2(self):
      pass

a = Steps(descending=True, value=0)
b = Steps(descending=False, value=0)

a.step() # say this is done 100 million times
b.step() # say this is done 100 million times

因为我们一开始就知道它是否是 descending/ascending,所以似乎没有必要在该 step() 中包含逻辑 'if self.descending',尤其是当我们调用它数百万次时。

改善这一点的一种方法是继承基础 class,例如:

class Steps():
   def __init__(self, value):
      self.value = value

   def other_funcs1(self):
      pass

   def other_funcs2(self):
      pass

class StepsInc(Steps):
   def __init__(self, value):
      Steps.__init__(self, value)
   
   def step(self):
      self.value += 1

class StepsDec(Steps):
   def __init__(self, value):
      Steps.__init__(self, value)
   
   def step(self):
      self.value -= 1

a = StepsDec(value=0)
b = StepsInc(value=0)

a.step() # say this is done 100 million times
b.step() # say this is done 100 million times

以上应该更优化,因为我们不再做不必要的 'if' 语句。但是如果我有多个函数,取决于不同的参数,我应该怎么做呢?因此,不仅仅是 'descending' 我还有其他可以具有不同功能的参数。我不想有太多 classes 并且看起来很乱。

我想到的一个解决方案是不用继承,我可以这样做,虽然不确定这是否是 pythonic:

class Steps():
       def __init__(self, descending, value):
          self.descending = descending
          self.value = value
          self.step = self.stepDec if self.descending else self.stepInc # can have multiple of this for different functions and parameters
          # more potential example
          #self.func = self.func1 if self.new_param else self.func2

       def stepInc(self):
          self.value += 1

       def stepDec(self):
          self.value -= 1

       def other_funcs1(self):
          pass

       def other_funcs2(self):
          pass

    
    
    a = Steps(descending=True, value=0)
    b = Steps(descending=False, value=0)
    
    a.step() # say this is done 100 million times
    b.step() # say this is done 100 million times

所以这个看起来比另一个继承基础 class 的 class 更干净。而且我可以拥有许多其他基于不同参数的功能。所以有两个问题:1) 这是 pythonic 吗?如果不是更好的方法是什么 2) 我如何覆盖默认函数,如“_ repr _”?

所以对于第二个问题,假设 print(a) 我想打印“我正在下降”,对于 print(b) 我想打印“我正在上升”。我知道这没有多大意义,但只是想知道如何覆盖这些。我绝对可以使用继承 class 示例来做到这一点,其中每个示例都有自己的“_ repr _”函数。但是有没有办法用我的最新示例来做到这一点?因为这看起来更干净,尤其是根据不同的参数有更多的功能。

希望这个问题很清楚。感谢帮助

好吧,有一个很好的方法可以解决您的问题。解决方案只是通过将方法注入构造函数来动态地向对象添加一个方法。因为,解决方案很简单,所以我只提供代码:

# note: in this approach the method only exists with object instance
#       the method has nothing to do with class

# note this import

import types

def desc(self):
    self.value -= 1

def inc(self):
    self.value += 1

class Steps():
    def __init__(self, func, descending, value):
        # add func as a method
        # where the method name is step
        self.step = types.MethodType(func, self)
        # nothing changes here
        self.descending = descending
        self.value = value

a = Steps(desc, True, 0)
b = Steps(inc, False, 0)

a.step();
print("value of a: {}".format(a.value));

b.step();
print("value of b: {}".format(b.value));

输出为:

value of a: -1
value of b: 1

现在,您可能会惊讶地听到:我不会向任何人推荐它

让我解释一下原因:

  1. 首先,如果您以这种方式创建了很多对象,则需要将很多方法与这些对象相关联。有可能你会浪费很多内存。
  2. 对象实例绑定的方法不属于 class。这可能会给正在阅读您的代码的人造成混淆。
  3. 如果您遵循严格的 oop 编码风格,您只是将这些函数公开,或者可能只是包裹在 class 中,但这不是解决此问题的可靠方法问题。

我知道,性能是您非常关心的问题,但我仍然建议您查看 strategy pattern。多几个 class 不会伤害你,只要你了解这几个 class 会给你多大的灵活性。懂模式的人一眼就能看懂你的代码。

到这里,我说了很多。但是,我想提最后一件事,如果您真的对 performance 非常感兴趣,您可以 write an extensionswitch to a compiled(faster) language