Можно ли вызывать __init__ из __setstate__

Я улучшаю существующий класс, который делает некоторые вычисления в __init__ функция для определения состояния экземпляра. Это нормально звонить __init__() от __getstate__() чтобы повторно использовать эти расчеты?

3 ответа

Решение

Подводя итог реакции от Kroltan и Jonsrharpe:

Технически это нормально

Технически это будет работать, и если вы сделаете это правильно, это можно считать ОК.

Практически это сложно, избегайте этого

Если вы измените код в будущем и коснитесь __init__тогда легко (даже вам) забыть об использовании в __setstate__ и тогда вы попадаете в сложную для отладки ситуацию (спрашиваете себя, откуда она).

class Calculator():
    def __init__(self):
        # some calculation stuff here
    def __setstate__(self, state)
        self.__init__()

Все расчеты лучше изолировать в другом общем методе:

class Calculator():
    def __init__(self):
        self._shared_calculation()   

    def __setstate__(self, state)
        self._shared_calculation()

    def _shared_calculation(self):
        #some calculation stuff here

Таким образом, вы заметите.

Примечание: использование "_" в качестве префикса для общего метода является произвольным, вам не нужно это делать.

Обычно предпочтительнее написать метод __getnewargs__ вместо. Таким образом, механизм травления будет вызывать __init__ для вас автоматически.

Другой подход заключается в настройке класса конструктора __init__ в подклассе. В идеале лучше иметь один класс конструктора и менять его в соответствии с вашими потребностями в подклассе.

class Person:
    def __init__(self, name, job=None, pay=0):
        self.name = name
        self.job = job
        self.pay = pay

class Manager(Person):
    def __init__(self, name, pay):                   
        Person.__init__(self, name, 'title', pay)  # Run constructor with 'title'

Вызов класса конструкторов таким способом оказывается очень распространенным шаблоном кодирования в Python. Сам Python использует наследование для поиска и вызова только одного __init__ метод во время построения - самый низкий в дереве классов.

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

Как предположил Ян, это сложно, и вы попадете в сложную ситуацию отладки, если вы вызовете его в том же классе

Другие вопросы по тегам