2014-09-20 2 views
0

Это, безусловно, вопрос новичка, мне просто трудно найти его.Как инициализировать данные для функции, которая неоднократно называется

Что я хочу сделать, так это рассчитать точки на круге для тысяч кругов, которые я позже вынести. Потому что я буду проводить много тысяч кругов в секунду, я думал, что постараюсь избежать лишних накладных расходов. Для этого я создал функцию, которая вычисляет количество точек (которые я хочу быть переменными, больший круг будет нуждаться в большем количестве вычислений) на единичном круге, а другая функция, которая может принимать эти точки, переводить их и затем масштабируйте радиус.

Мой исходный код в конечном итоге что-то вроде этого:

class Circle(): 
... 
def CalcCircle(segments): 
    does some stuff to calculate generic coordinates 

def CreateCircle(x, y, r, segments):   
    does some stuff to create a circle using CalcCircle(segments) 

Очевидно, что проблема заключалась в том, что даже если я мог бы только создавать круги с 20 сегментами, я звоню функцию CalcCircle (и повторяя одни и те же расчеты) каждый раз, когда я вызывал CreateCircle.

Единственный способ, которым я мог понять, как исправить это:

class Circle(): 
... 
def CalcCircle(segments): 
    does some stuff to calculate generic coordinates 

CreateCircle_has_not_been_run = True 

def CreateCircle(x, y, r, segments): 

    if Circle.TransCircle_has_not_been_run: 
     generic_circle = Circle.CalcCircle(segments) 
     Circle.CreateCircle_has_not_been_run = False 

    does some stuff to create a circle using generic_circle 

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

Редактировать: пример того, как будет выполнен вызов.

@window.event 
def on_draw(): 
    window.clear() 
    width = window.get_size()[0] 
    height = window.get_size()[1] 
    radius = int(width/50) 
    segments = int(radius*1.5) 
    for i in range(N): 
     pyglet.gl.glColor3f(0.05,0.2,0.9) 
     DrawCircle(positions[i][0],positions[i][1],width,segments) 
    DrawCage(width,height) 
    DrawLabel(width,height) 
    etc. 

Я знаю, что есть проблемы здесь, но я просто пытаюсь показать пример (позиция происходит от функции обновления, если кто-то интересно). Как я уже говорил ранее, это проблема, с которой я сталкиваюсь все время.

Я мог бы назвать Circle.CalcCircle() функцией on_resize() согласно предложению Ахима. Мне трудно поверить, однако, что стандартная практика состоит в том, чтобы вставить в класс две случайные функции (поскольку ни одна из них не обязана даже быть в классе Circle), одна из которых неявно зависит от другой, и обе из них вызывается в разных частях кода.

+0

Почему вы не называете 'CalcCircle', сохраняете результат и передаете его в' CreateCircle'? – Achim

+0

В этом случае, поскольку CreateCircle вызывается из функции on_draw, которая выполняет рендеринг каждые 16 миллисекунд или что-то еще. Кстати, у меня была точно такая же проблема с передачей 1000 ключевых слов в on_draw. Я хочу только изменить значения (и я не уверен, как это работает с памятью, если я повторно инициализирую 1000-клавишный словарь каждые 16 мс), в конце я использовал глобальный, который именно то, что я пытаюсь избежать , – user3573328

+0

В целом, однако, стандартная практика состоит в том, чтобы иметь одну функцию для инициализации данных, а другую - для ее изменения? Я пытаюсь освободиться от менталитета глобального состояния и просто его модифицировать. Это несколько раздражает меня наличием функций, которые изменяют данные дальше по иерархии, если это имеет смысл. Или я не понимаю, что представляет собой хороший дизайн? – user3573328

ответ

-1

Я хотел бы сделать что-то вроде этого:

class Circle: 

    def __init__(self): 
     self.unit_circle_points = None 

    def CalcCircle(self, segments): 
     # Do some stuff to calculate segments, 
     # assign calculated values to class attribute 
     self.unit_circle_points = calculated_points 

    def CreateCircle(self, X, y, r, segments): 
     # If circle points have not yet been calculated then calculate 
     # and store, else just load stored points 
     if self.unit_circle_points is None: 
      self.CalcCircle(segments) 
     unit_circle_points = self.unit_circle_points 

     # Now use unit_circle_points to do some calculations 

Каждый раз, когда вы экземпляр объекта круг он будет идти с атрибутом, именуемым unit_circle_points, который инициализируется None. Когда вы вызываете метод CreateCircle на этом объекте в первый раз, он увидит, что атрибут unit_circle_points равен None и выполняет необходимые вычисления, вызывая CalcCircle, сохраняя результаты. При последующих вызовах метода CreateCircle этого объекта Circle атрибут unit_circle_points больше не будет None, и метод будет просто использовать значения, хранящиеся в атрибуте.

Edit:

Если это требует много «неявного» поведения для вашего вкуса, вы можете переместить вещи вокруг так, что CalcCircle должен вызываться явно пользователем для генерации предварительно вычисленных данных.

class Circle: 

    def __init__(self): 
     self.unit_circle_points = None 

    def CalcCircle(self, segments): 
     # Do some stuff to calculate segments, 
     # assign calculated values to class attribute 
     self.unit_circle_points = calculated_points 
     return self 

    def CreateCircle(self, X, y, r): 
     # If circle points have not yet been calculated then raise an error, 
     # else load previously calculated points 
     if self.unit_circle_points is None: 
      raise Exception("You'd better explicitly call CalcCircle first.") 
     unit_circle_points = self.unit_circle_points 

     # Now use unit_circle_points to do some calculations 
+0

Я думаю, что это то, что я сделаю, это намного чище, чем то, что у меня было и что метод действия на экземпляре кажется намного более явный, чем вызов одной функции класса на данные из другой функции класса, особенно когда это может быть большой класс, и вы вызываете их обоих в очень разных местах вашего кода. Я все еще обнимаю ООП. – user3573328

+0

Я рассматриваю этот вид неявных побочных эффектов как очень плохое программирование OO. – Achim

+0

Wow harsh, мне кажется, что это обеспечивает точную функциональность, которую ищет OP. Ознакомьтесь с пересмотренной версией. – DavidS

Смежные вопросы