Скажем, у нас есть два класса: Class A
с особой ошибкой, которая часто возникает и является частью ее функциональности.Python, IoC, Исключения и свободная связь
#a.py
class AError(Exception):
"""This exception flags a functional error"""
pass
class A(object):
def work(self):
"""Throws AError when it is tired"""
raise AError() #This exception is raised eventually, business code removed for clarity
Class B
, который использует класс A для выполнения некоторых операций.
#b.py
import a
class B(object):
def make_him_work(self, afected):
try:
afected.work()
except a.AError:
pass #This was expected, here will go some business logic
Это прекрасно работает, но это становится проблемой, когда у меня есть различные типы A. В идеале, я хотел бы, чтобы полностью отделить А от В, так что я могу пройти любой класс, как А, удовлетворяет тот же интерфейс, но я не могу из-за исключения (поскольку он не является частью самого интерфейса)
В C++ у меня будет файл заголовка с определением моего интерфейса плюс исключения, которые будут реализованы конкретными классами. Как это обычно решается в Python? Или сказал другой путь, какой самый пифонический подход?
Я думал, что следующие варианты:
1. создать модуль с исключениями и, возможно, базовый класс/метакласса (С ++/Java путь)
#common.py
class AErrorBase(Exception):
pass
class AIface(object):
def work(self):
raise NotImplemented()
.
#a.py
import common
class AError(common.AErrorBase):
pass
class A(common.AIface):
def work(self):
"""Throws AError when it is tired"""
raise AError()
.
#b.py
import common
class B(object):
def make_him_work(self, afected):
try:
afected.work()
except common.AErrorBase:
pass #This was expected
2. Исключение передачи в качестве аргумента
#a.py
class AError(Exception):
pass
class A(object):
def work(self):
"""Throws AError when it is tired"""
raise AError()
.
#b.py
class B(object):
def make_him_work(self, afected, ex_type):
try:
afected.work()
except ex_type:
pass #This was expected
3. Исключение в качестве атрибута класса, так что становится частью интерфейса.
#a.py
class A(object):
def work(self):
"""Throws AError when it is tired"""
raise AError()
class AError(Exception):
pass
.
#b.py
class B(object):
def make_him_work(self, afected):
try:
afected.work()
except afected.AError:
pass #This was expected
4. Использование исключение Dont, только код возврата. ! C дней назад!
Любой другой вариант? Что вы находите более «pythonic»?
Редактировать: Добавлены комментарии, разъясняющие цель исключения. Он должен быть обработан в B
Примечание: Это может быть совершенно так, что я приближаюсь к проблеме с моим старым фоном C++, я просто хочу знать, как вы применяете IoC в python, когда у нас есть исключения.Вы можете сказать, все мои подходы мусор, и я должен делать это по-другому
Учитывая, что вы просто 'pass' после ошибки, почему бросить его на всех? Обрабатывайте его в 'A' и, например, return 'True' (завершено) или' False' (по какой-то ожидаемой причине) остановлен вызывающим абонентом из 'work'. Тогда вы знаете, что любая ошибка, которая делает ее «B», является неожиданным. Подобных вопросов довольно сложно ответить в абстрактном/общем случае. – jonrsharpe
примечание бизнес-кода удаляется для простоты, '' A'' бросает, потому что он не может обработать ошибку, а просто сообщить об этом, и он находится в '' B'', где у нас будет некоторый бизнес-код для обработки такого исключения. –
Без конкретного примера на этот вопрос нельзя ответить, и с ним я подозреваю, что это все равно будет на стороне мнения. Если вы посмотрите на стандартные библиотечные модули с определенными ошибками, вы можете сделать хуже, чем принять соглашение, которое они используют. – jonrsharpe