Является ли хорошей практикой иметь интенсивный метод __init__ в классе python? - PullRequest
0 голосов
/ 05 февраля 2020

Я новичок в python классах. Я пишу класс, который принимает в качестве аргумента идентификатор, но затем он должен вычислить другой атрибут, который зависит от идентификатора, и это вычисление может быть интенсивным.

Мой подход состоял в том, чтобы вычислить все на этапе инициализации , хотя это требует времени, и для экономии времени сохраните все, что ранее было вычислено, в маринованном словаре, как показано ниже.

import pickle

def intensecomputation(id):
    # Compute otherattr, based on id
    ...
    ...
    return(otherattr)

class myclass:
    def __init__(self, id):
        self.id = id
        # Need to compute self.otherattr that depends on self.id
        # Check if I have computed that already
        mydict = pickle.load( open( "mydict.p", "rb" ) )
        if self.id in mydict:
            self.otherattr = mydict[self.id]
        else:
            self.otherattr = intensecomputation(id)
            # Save for later
            mydict[self.id] = self.otherattr
            pickle.dump( mydict, open( "mydict.p", "wb" ) )

myobject = myclass(10)
# Wait some time here (unless the id 10 is already precalculated in the past and is in the pickled dictionary)
print(myobject.id)
print(myobject.otherattr)

Является ли то, что я делаю, хорошей практикой? Есть ли причина, по которой __init__ не должно быть сложным и интенсивным? Я думал, что если это так, то я мог бы реализовать intensecomputation как метод myclass и вызвать его для заполнения self.otherattr, например так:

myobject = myclass(10)
# myobject.otherattr is empty
print(myobject.id)
myobject.intensecomputation()
# Now myobject.otherattr is created
print(myobject.otherattr)

В любом случае, учитывая мой сценарий Я был бы признателен, если бы вы могли объяснить мне наилучшую практику для реализации myclass.

1 Ответ

0 голосов
/ 05 марта 2020

Нет ничего плохого в задействованном методе init, особенно если вы пытаетесь не следовать стилю RAII, где конструирование объекта является инициализацией, что в целом является хорошей практикой. Таким образом, вы знаете, что объект действителен при строительстве, если это важно, в отличие от потенциально дорогостоящих операций, выполняемых позже, когда вы не ожидаете, что они будут дорогими.

Идея засолки хороша, однако я бы предложил что вы делаете mydict переменную класса, если она подходит для совместного использования между инициализациями или она выпадает из области видимости после вызова init каждый раз, и mydict.p не меняется. Единственное изменение, которое я могу сделать здесь, - это сделать инициализацию самой себя.therattr функцией. и измените структуру так, чтобы вы всегда делали один и тот же последний кусок

#snippet in your init

if myclass.mydict.empty() :
  ## load from the pickle so its shared for all class instantiations OR perhaps pull this out and make it part of class's init. otherwise every construction is reloading the pickle which could be as costly or more costly then your calculation itself. (File IO is slow) 

do_dump = false # track whether I make changes that require a pickle dump update
if self.id !not in mydict:
  mydict[self.id] = intensecomputation(id) # calc and memoize at once
  do_dump = true;
  pass

# now this is universal
self.otherattr = mydict[self.id] 

#other stuff... which might also need to be pickled

#before end
#re-pickle if important; ensuring to do so potentially via a try catch finally wrapper.

Другая упомянутая возможность - использовать декоратор вокруг геттера для члена otherattr, который возвращает или вызывает и запоминает результат там, когда и если его используемый. выгода действительно сводится к тому, как используются данные. если вы выполняете кучу пакетной обработки позже со многими экземплярами myclass в каком-то конвейере, это будет работать намного лучше, если значения будут готовы, если можно так выразиться, к go, поэтому кеш инструкций для вычисления любого конвейера, который у вас есть, может оставайтесь горячими, в отличие от прогнозирования пропущенных ветвлений каждые несколько раз, когда приходится прерывать конвейер и вычислять это значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...