Доступ к функциям класса осуществляется с помощью декоратора класса

#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 для удобства.