Python: Как обрабатывать вызовы методов для класса, который не может правильно инициализироваться? - PullRequest
1 голос
/ 09 декабря 2011

Если объект полагается на модуль, который не включен в Python (например, win32api, gstreamer, наборы инструментов gui и т. Д.), И класс / функция / метод из этого модуля может дать сбой, что должен делать объект?

Вот пример:

import guimodule  # Just an example; could be anything

class RandomWindow(object):

    def __init__(self):
        try:
            self.dialog = guimodule.Dialog()  # I might fail
        except: guimodule.DialogError:
            self.dialog = None  # This can't be right

    def update(self):
        self.dialog.prepare()
        self.dialog.paint()
        self.dialog.update()

    # ~30 more methods

Этот класс будет лишь крошечной (и ненужной, но полезной) частью большой программы.

Давайте предположим, что у нас есть воображаемый модуль с именем guimodule, с классом с именем Dialog, который может не быть создан. Если наш класс RandomWindow имеет, скажем, 30 методов, которые манипулируют этим окном, проверка if self.dialog is not None будет болезненной и замедлит программу при реализации в постоянно используемых методах (например, метод update в примере выше). Вызов .paint() для NoneType (когда Dialog не удается загрузить) вызовет ошибку, и создание фиктивного класса Dialog со всеми методами и атрибутами оригинала будет абсурдным.

Как я могу изменить свой класс для обработки неудачного создания класса Dialog?

Ответы [ 4 ]

3 голосов
/ 09 декабря 2011

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

См. Также Python: нехорошо ли создавать исключения в __init __?

1 голос
/ 09 декабря 2011

Может оказаться полезным иметь два его подкласса; тот, который использует этот модуль, а другой - нет. «Фабричный» метод может определить, какой подкласс является подходящим, и вернуть экземпляр этого подкласса.

Подклассами вы позволяете им обмениваться кодом, который не зависит от того, доступен ли этот модуль.

0 голосов
/ 09 декабря 2011

Создание фиктивного Dialog класса не так абсурдно, как вы могли бы подумать, если бы вы решили использовать функцию Pythons __getattr__.Эта следующая пустышка полностью соответствует вашим потребностям:

class DummyDialog:
  def __getattr__(self, name):
    def fct(*args, **kwargs):
      pass
    return fct 
0 голосов
/ 09 декабря 2011

Я согласен с тем, что «проверка того, что self.dialog не равен None, будет болью», но я не согласен с тем, что это замедлит ход событий, потому что если существует self.dialog, это будет медленнее.Так что забудьте о медлительности на время.поэтому один из способов справиться с этим - создать MockDialog, который ничего не делает при вызове функций, например

class RandomWindow(object):

    def __init__(self):
        try:
            self.dialog = guimodule.Dialog()  # I might fail
        except: guimodule.DialogError:
            self.dialog = DummyDialog() # create a placeholder

class DummyDialog(object):
    # either list all methods or override __getattr__ to create a mock object
...