Определение свойства класса в __init__, а не в другом методе класса python

РЕДАКТИРОВАТЬ

Обратите внимание, что мое внимание было обращено на то, что Атрибут экземпляра attribute_name, определенный вне __init__, является возможным дубликатом, с которым я в основном согласен (я не не наткнулся на это, потому что я не знал, что нужно искать pylint). Однако я хотел бы оставить этот вопрос открытым из-за того, что я хочу иметь возможность повторно инициализировать свой класс, используя тот же метод. Общий консенсус в предыдущем вопросе заключался в том, чтобы вернуть каждый параметр из сценария loadData, а затем проанализировать его в объекте self. Это нормально, однако мне все равно придется сделать это снова в другом методе, чтобы иметь возможность повторно инициализировать мой экземпляр класса, что все еще кажется дополнительной работой только для немного большей читабельности. Возможно, дело в моем примере. В реальной жизни процедура loadData считывает около 30 параметров, поэтому я не решаюсь анализировать их в двух разных местах.

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


Оригинал

Это что-то вроде вопроса о "лучших практиках". В последнее время я изучаю python (частично, чтобы узнать что-то новое и частично, чтобы уйти от MATLAB). Работая в python, я создал класс, который был структурирован следующим образом:

class exampleClass:
    """
    This is an example class to demonstrate my question to stack exchange
    """

    def __init__( self, fileName ):
        exampleClass.loadData( self, fileName )

    def loadData( self, fileName ):
        """
        This function reads the data specified in the fileName into the 
        current instance of exampleClass.
        :param fileName: The file that the data is to be loaded from
        """

        with open(fileName,'r') as sumFile:
            self.name = sumFile.readLine().strip(' \n\r\t')

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

Однако, когда я помещаю этот код в свою IDE (pycharm), он выдает предупреждение о том, что атрибут экземпляра был определен за пределами __init__. Теперь очевидно, что это не влияет на работу кода, все работает нормально, но мне интересно, есть ли смысл обращать внимание на предупреждение в этом случае. Я мог бы сделать что-то, где я инициализирую все свойства некоторым значением по умолчанию в методе init перед вызовом loadData method, но это просто кажется мне ненужной работой и замедлит выполнение (хотя и очень небольшое количество). Я также мог бы иметь по существу две копии метода loadData, одну в методе __init__ и одну в качестве фактического метода, но опять же это просто кажется ненужной дополнительной работой.

В целом мой вопрос заключается в том, что было бы наилучшей практикой в ​​​​этой ситуации. Есть ли какая-то причина, по которой мне следует реструктурировать код одним из способов, упомянутых в предыдущем абзаце, или это просто экземпляр IDE со слишком широким предупреждением о проверке кода. Я, очевидно, вижу некоторые случаи, когда это предупреждение нужно учитывать, но, исходя из моего текущего опыта, в этом случае это не похоже на проблему.


person Andrew    schedule 16.11.2015    source источник
comment
Возможный дубликат атрибута атрибута attribute_name, определенного вне __init__   -  person Joshua Grigonis    schedule 16.11.2015
comment
self.name = self.loadData(...) и вернуть данные из loadData   -  person Peter Wood    schedule 16.11.2015


Ответы (1)


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

Если неудобно или невозможно присвоить атрибуту его окончательное значение, я рекомендую хотя бы инициализировать его значением None. Это сигнализирует читателю, что объект включает этот атрибут, даже если он будет переопределен позже.

class exampleClass:
    """
    This is an example class to demonstrate my question to stack exchange
    """

    def __init__( self, fileName ):
        # Note: this will be modified when a file is loaded
        self.name = None

        exampleClass.loadData( self, fileName )

Другим вариантом было бы, чтобы loadData возвращало значение, а не устанавливало его, поэтому ваша инициализация может выглядеть так:

def __init__(self, fileName):
    self.name = self.loadData(fileName)

Я склонен думать, что второй метод лучше, но любой метод хорош. Суть в том, чтобы сделать ваши классы и объекты максимально простыми для понимания.

person Bryan Oakley    schedule 16.11.2015
comment
Спасибо @Bryan, я согласен с мнением здесь. Как я только что упомянул в своем редактировании, единственная причина, по которой я не решаюсь сделать вторую, заключается в том, что есть много параметров, и необходимость дважды их анализировать кажется чрезмерной. Возможно, я просто пойду с инициализацией переменных в их типы по умолчанию и пойду оттуда. Я немного подумаю и подожду, ответит ли кто-нибудь еще, прежде чем принять ваш ответ. - person Andrew; 16.11.2015
comment
Просто для тех, кто наткнется на это. Я решил сначала инициализировать все свойства, как в предложении Брайана. Я пошел по этому пути, потому что не хотел дважды анализировать выходные данные loadData. Если администратор считает, что это дубликат, и хочет закрыть его, у меня нет проблем с этим, но сейчас я думаю, что это полезно в дополнение к другому вопросу. - person Andrew; 16.11.2015