#python #exception #decorator #wrapper
Вопрос:
Я застрял на проблеме реализации.
class A(object): "class a variables" @execute def worker(self): try: "do an ETL operation" except Exception as e: raise ETL exception def letmehandleETLerrors(self): pass def letmehandleDataIntegrityErros(self): pass def letmehandleDataQualityErrors(self): pass def letmehandleDataUpdateErrors(self): pass def letmehandleDataDisplayErrors(self): pass
У меня есть класс, и внутри этого класса один из его методов называется worker, который вызывает другие методы, выполняющие некоторую обработку данных.
Чего я хотел бы добиться, так это иметь в своем приложении раздел централизованной обработки исключений, в который я мог бы загружать все свои действия по обработке исключений и публикации. У нас есть много шагов и споров для проверки данных, поэтому обработка исключений повсюду становится утомительной. Итак, в файле под названием someExternalFile я вкратце определил нашу централизованную обработку исключений как таковую:
class ETL_EXCEPTION(Exception): pass class execute(object): def __init__(self,*args,**kwargs): pass def __call__(self,f): @wraps(f) def wrapped_f(*args): try: r = f(*args) except ETL_EXCEPTION as etlEX: " i would like to call ClassA.letmehandleETLerrors()" pass
поэтому, по сути, в любое время, когда где-либо в других классах возникает исключение, я бы хотел, чтобы этот декоратор направлялся к соответствующим обработчикам для плавного выполнения действий после публикации. Проблема здесь в том, что я пытаюсь найти способ ссылаться на экземпляр класса f, который находится в области действия декоратора. Я могу получить ссылку на класс примерно так:
self.currentclass = f.__globals__[f.__qualname__.split('.')[0]]
но когда я делаю self.currentclass.letmehandleETLerrors, он говорит, что letmehandleETLerrors нуждается в позиционном аргументе под названием self, поэтому, по сути, он создал новый экземпляр ClassA, о котором я думаю.
Возможно ли это, или мне следует извлечь эту оболочку из класса, определить ее как метод и передать в нее класс A?
Комментарии:
1. Если вы ничего не делаете
execute.__init__
, вы также можете заменить классexecute
простой функцией, которая делает то же самое,execute.__call__
что и .2.
wrapped_f
уже получает значение типаClassA
, а именноargs[0]
.
Ответ №1:
Результирующая оформленная функция получает значение типа ClassA
в качестве своего первого аргумента, поэтому вы можете использовать его для доступа leetmehandleETLerrors
. Учитывая , что execute
это тесно связано A
, оно также может быть определено внутри класса: просто потому, что оно есть, не означает, что оно должно быть открыто или использоваться в качестве метода экземпляра.
class A: "class a variables" def _execute(f): @wraps(f) def wrapped_f(self, *args): try: r = f(self, *args) except ETL_EXCEPTION as etlEX: self.letmehandleETLerrors() @_execute def worker(self): try: "do an ETL operation" except Exception as e: raise ETL exception def letmehandleETLerrors(self): pass def letmehandleDataIntegrityErros(self): pass def letmehandleDataQualityErrors(self): pass def letmehandleDataUpdateErrors(self): pass def letmehandleDataDisplayErrors(self): pass
Комментарии:
1. Спасибо @chepner. Я тоже рассматривал эту модель. Я попробую ваш предыдущий комментарий по аргументам[0] или просто перейду к тому, что вы посоветовали.
2. Между ними нет большой разницы. Я просто перенес определение
execute
в класс и, исходя из предположения, что оно будет использоваться только для оформления методов экземпляра вA
(а не произвольных функций)self
, отделился отargs
для удобства.