Python, лучший способ переопределить функции для оптимизации - PullRequest
0 голосов
/ 05 августа 2020

Не уверен, как лучше всего описать эти вопросы, но я просто пытаюсь оптимизировать вещи, поскольку я выполняю эти сотни миллионов раз. Поэтому я стараюсь как можно больше исключить logi c. Итак, для простоты давайте возьмем простой класс ниже:

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

Поскольку мы уже знаем, идет ли он по убыванию / возрастанию в начале, кажется ненужным иметь logi c 'if self.descending' внутри этого step (), особенно если мы вызываем его миллионы раз.

Один из способов улучшить это - унаследовать базовый класс, например:

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

Вышеуказанное должно быть более оптимальным, поскольку мы больше не делают ненужных операторов «если». Но что, если у меня есть несколько функций, которые зависят от разных параметров, как мне это сделать? Так что вместо простого «по убыванию» у меня есть другие параметры, которые могут иметь разные функции. Я не хочу иметь слишком много классов, и это может показаться беспорядочным.

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

Итак, этот класс кажется чище, чем другой класс, наследующий базовый класс. И у меня может быть много других функций, которые могут основываться на разных параметрах. Итак, два вопроса: 1) это pythoni c?, Если не лучший способ сделать это 2) Как я могу переопределить функции по умолчанию, такие как «_ repr _»?

Итак, что касается второго вопроса, скажем, для print (a) я хочу напечатать «Я спускаюсь», а для print (b) я хочу напечатать «Я поднимаюсь». Я знаю, что в этом нет большого смысла, но мне просто интересно, как я могу их отменить. Я определенно могу сделать это с помощью примера наследующего класса, где у каждого будет своя собственная функция "_ repr _". Но есть ли способ сделать это с помощью последнего имеющегося у меня примера? Поскольку это кажется более чистым, особенно с большим количеством функций, зависящих от разных параметров.

Надеюсь, этот вопрос ясен. Спасибо за помощь

1 Ответ

1 голос
/ 05 августа 2020

Что ж, есть хороший способ решить вашу проблему. И решение - просто динамически добавить метод к объекту, внедрив его в конструктор. Поскольку решение простое, я просто предоставляю код:

# 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. Экземпляры объектов связаны с методами и не принадлежат классу. Это может создать путаницу для людей, читающих ваш код.
  3. Если вы следуете жесткому стилю кодирования oop, вы просто оставляете эти функции открытыми или можете просто обернуть их в class, но это не проверенный способ решения этой проблемы.

Я знаю, производительность очень важна для вас, но все же я бы рекомендовал взглянуть на strategy pattern. Еще несколько классов вам не повредит, если вы поймете, какую гибкость дадут вам эти несколько классов. И каждый, кто знает этот паттерн, поймет ваш код с первого взгляда.

Итак, я много сказал. Но, последнее, что я хотел бы упомянуть, если вас действительно очень интересует performance, вы можете write an extension или switch to a compiled(faster) language.

...