Плохая Практика для выполнения кода в конструкторе это, вероятно, перестанет работать?

Ключевое слово float:

<h1 style="text-align:left;float:left;">Title</h1> 
<h2 style="text-align:right;float:right;">Context</h2> 
<hr style="clear:both;"/>
15
задан lispmachine 7 June 2009 в 09:07
поделиться

8 ответов

Я не разработчик Python, но в целом лучше избегать сложных / подверженных ошибкам операций в вашем конструкторе. Один из способов обойти это - добавить в класс метод «LoadFromFile» или «Init» для заполнения объекта из внешнего источника. Затем этот метод загрузки / инициализации должен быть вызван отдельно после создания объекта.

4
ответ дан 30 November 2019 в 23:57
поделиться

По крайней мере, в C ++ нет ничего плохого в том, чтобы помещать в конструктор код, подверженный сбоям - вы просто генерируете исключение, если возникает ошибка. Если код необходим для правильного конструирования объекта, альтернативы действительно нет (хотя вы можете абстрагировать код на подфункции или, что лучше, на конструкторы подобъектов). Худшая практика - построить объект наполовину, а затем ожидать, что пользователь вызовет другие функции, чтобы каким-то образом завершить построение.

20
ответ дан 30 November 2019 в 23:57
поделиться

Одним из распространенных шаблонов является двухэтапное построение, также предложенное Энди Уайтом.

Первая фаза: Обычный конструктор.

Вторая фаза: Операции, которые могут потерпеть неудачу.

Интеграция два: добавить фабричный метод для выполнения обеих фаз и сделать конструктор защищенным / частным, чтобы предотвратить создание за пределами фабричного метода.

О, и я не являюсь разработчиком Python.

3
ответ дан 30 November 2019 в 23:57
поделиться

Само по себе это неплохая практика.

Но я думаю, вы можете здесь чего-то другого. В вашем примере метод doSomething () не будет вызываться при сбое конструктора MyClass. Попробуйте ввести следующий код:

class MyClass:
def __init__(self, s):
    print s
    raise Exception("Exception")

def doSomething(self):
    print "doSomething"

try:
    someInstance = MyClass("test123")
    someInstance.doSomething()
except:
    print "except"

Он должен напечатать:

test123
except

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

  • Какой должна быть область видимости переменной someInstance? Кто его пользователи? Каковы их требования?

  • Где и как следует обрабатывать ошибку в случае, если одно из ваших 10 значений недоступно?

  • Должны ли все 10 значений кэшироваться во время построения или кэшироваться одно за другим, когда они необходимы в первый раз?

  • Можно ли преобразовать код ввода-вывода во вспомогательный метод, чтобы выполнение чего-то похожего 10 раз не приводило к повторению кода?

  • ...

4
ответ дан 30 November 2019 в 23:57
поделиться

Опять же, у меня мало опыта работы с Python, однако в C # лучше попробовать Избегайте наличия конструктора, который генерирует исключение. Пример того, почему это приходит на ум, - если вы хотите разместить свой конструктор в месте, где его невозможно окружить блоком try {} catch {}, например, инициализация поля в классе:

class MyClass
{
    MySecondClass = new MySecondClass();
    // Rest of class
}

Если конструктор MySecondClass генерирует исключение, которое вы хотите обработать внутри MyClass, тогда вам нужно провести рефакторинг вышеупомянутого - это, конечно, не конец света, но желательно иметь.

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

0
ответ дан 30 November 2019 в 23:57
поделиться

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

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

0
ответ дан 30 November 2019 в 23:57
поделиться

Существует разница между конструктором в C ++ и __ init __ метод в Python. В C ++ задача конструктора - создать объект. Если не получится, деструктор не вызывается. Следовательно, если какие-либо ресурсы были приобретены до было выброшено исключение, очистка должна быть выполнена перед выходом из конструктора. Таким образом, некоторые предпочитают двухфазное строительство, при этом большая часть строительства уже выполнена. вне конструктора (тьфу).

Python имеет гораздо более чистую двухфазную конструкцию (конструкция, затем инициализировать). Однако многие путают метод __ init __ (инициализатор) с конструктором. Фактический конструктор в Python называется __ new __ . В отличие от C ++, он не принимает экземпляр, а возвращает один. Задача __ init __ - инициализировать созданный экземпляр. Если исключение возникает в __ init __ , деструктор __ del __ (если есть) будет вызываться, как ожидалось, потому что объект уже был создан (даже если он не был должным образом инициализирован) к моменту вызова __ init __ .

Отвечая на ваш вопрос:

В Python, если код в ваш "конструктор" не работает, объект заканчивается вверх не определено.

Это не совсем так. Если __ init __ вызывает исключение, объект созданы, но не инициализированы должным образом (например, некоторые атрибуты не назначено). Но в то время, когда он возник, у вас, вероятно, не было никаких ссылок на этот объект, поэтому тот факт, что атрибуты не назначены, не имеет значения. Только деструктор (если есть) должен проверять, существуют ли атрибуты на самом деле.

Как правильно это сделать?

В Python инициализируйте объекты в __ init __ и не беспокойтесь об исключениях . В C ++ используйте RAII .


Обновление [об управлении ресурсами]:

В языках со сборкой мусора, если вы имеете дело с ресурсами, особенно с ограниченными, такими как соединения с базой данных, лучше не выпускать их в деструкторе. Это связано с тем, что объекты уничтожаются недетерминированным образом, и если вы чтобы иметь цикл ссылок (что не всегда легко определить), и по крайней мере один из объектов в цикле имеет определенный деструктор, они никогда не будут уничтожены. У языков со сборкой мусора есть другие средства работы с ресурсами. В Python это с оператором .

35
ответ дан 30 November 2019 в 23:57
поделиться

кажется, Нейл был прав: мой друг только что указал мне на это:

http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

, что в основном и сказал Нил ...

0
ответ дан 30 November 2019 в 23:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: