Ссылка на себя в декораторе
Я реализую класс коннектора базы данных в python. Я буду использоватьretry
декоратор из библиотеки упорства, чтобы повторить попытку подключения к базе данных по истечении времени ожидания.
Я хочу передать self.retry_count
а также self.retry_interval
к аргументам в retry
декоратор.
## etl_connect.py
from sqlalchemy import create_engine
import pymysql
import logging
from tenacity import *
class Connector():
def __init__(self, mode, conn_str, retry_count, retry_interval):
self.mode = mode
self.conn_str = conn_str
self.retry_count = retry_count
self.retry_interval = retry_interval
self.engine = None
self.conn = None
@retry(wait=wait_fixed(self.retry_interval), stop=stop_after_attempt(self.retry_count))
def mysql_connect(self):
logging.info('Connecting to mysql. (retry count=%d)' % (self.mysql_connect.retry.statistics['attempt_number']))
mysql_engine = create_engine(self.conn_str)
mysql_conn = mysql_engine.connect()
logging.info('Connected to mysql successfully with %d attempt(s).' % (self.mysql_connect.retry.statistics['attempt_number']))
return (mysql_engine, mysql_conn)
Теперь позвоните в mysql_connect
функция:
## call.py
from etl_connect import *
mysql_connector = Connector('mysql', 'mysql database string here', 5, 10)
engine, conn = mysql_connector.mysql_connect()
Но это показывает: NameError: name 'self' is not defined
.
Traceback (most recent call last):
File "call.py", line 5, in <module>
from etl_connect import *
File "/home/developer/ETL_modules/etl_connect.py", line 19, in <module>
class Connector():
File "/home/developer/ETL_modules/etl_connect.py", line 56, in Connector
@retry(wait=wait_fixed(self.retry_interval), stop=stop_after_attempt(self.retry_count))
NameError: name 'self' is not defined
Есть ли способы пройти? self.retry_count
& self.retry_interval
декоратору?
4 ответа
Вместо того, чтобы украшать метод, вызовите retry
когда вы вызываете метод.
## etl_connect.py
from sqlalchemy import create_engine
import pymysql
import logging
from tenacity import *
class Connector():
def __init__(self, mode, conn_str, retry_count, retry_interval):
self.mode = mode
self.conn_str = conn_str
self.retry_count = retry_count
self.retry_interval = retry_interval
self.engine = None
self.conn = None
def _mysql_connect(self):
logging.info('Connecting to mysql. (retry count=%d)' % (self.mysql_connect.retry.statistics['attempt_number']))
mysql_engine = create_engine(self.conn_str)
mysql_conn = mysql_engine.connect()
logging.info('Connected to mysql successfully with %d attempt(s).' % (self.mysql_connect.retry.statistics['attempt_number']))
return (mysql_engine, mysql_conn)
def mysql_connect(self):
d = retry(
wait=wait_fixed(self.retry_interval),
stop=stop_after_attempt(self.retry_count)
)
# One of these two should work, depending on how
# retry is actually defined.
return d(Connector._mysql_connect)(self)
# return d(self._mysql_connect)
Если у вас нет доступа @retry
декоратор, и вы не можете его редактировать, вы можете определить переменную вне определения вашего класса. Или вы можете определить эту базовую конфигурацию в файле настроек, а затем импортировать ее. Посмотрите на это:
## etl_connect.py
from sqlalchemy import create_engine
import pymysql
import logging
from tenacity import *
base_config = {
'retry_count': 3,
'retry_interval': 30,
...
}
class Connector():
def __init__(self, mode, conn_str):
self.mode = mode
self.conn_str = conn_str
self.engine = None
self.conn = None
@retry(wait=wait_fixed(base_config['retry_interval']), stop=stop_after_attempt(base_config['retry_count']))
def mysql_connect(self):
logging.info('Connecting to mysql. (retry count=%d)' % (self.mysql_connect.retry.statistics['attempt_number']))
mysql_engine = create_engine(self.conn_str)
mysql_conn = mysql_engine.connect()
logging.info('Connected to mysql successfully with %d attempt(s).' % (self.mysql_connect.retry.statistics['attempt_number']))
return (mysql_engine, mysql_conn)
Или импортировать из файла настроек:
from sqlalchemy import create_engine
import pymysql
import logging
from tenacity import *
from settings import RETRY_COUNT
from settings import RETRY_INTERVAL
Я знаю, что это надежный способ, но эти параметры должны быть определены в ваших настройках, и нет необходимости передавать их каждый раз, когда вы хотите создать экземпляр вашего класса.
Предполагая, что вы не можете легко переопределить упорство retry
декоратор, вы можете обернуть его своим собственным, который ссылается на значения в Connector
пример.
Вот что я имею в виду:
# Wrapper for tenacity retry decorator
def my_retry(func):
def wrapped(conn, *args, **kwargs):
tdecorator = retry(wait=wait_fixed(conn.retry_interval),
stop=stop_after_attempt(conn.retry_count))
decorated = tdecorator(func)
return decorated(conn, *args, **kwargs)
return wrapped
class Connector():
def __init__(self, mode, conn_str, retry_count, retry_interval):
self.mode = mode
self.conn_str = conn_str
self.retry_count = retry_count
self.retry_interval = retry_interval
self.engine = None
self.conn = None
@my_retry
def mysql_connect(self):
logging.info('Connecting to mysql. (retry count=%d)' % (self.mysql_connect.retry.statistics['attempt_number']))
mysql_engine = create_engine(self.conn_str)
mysql_conn = mysql_engine.connect()
logging.info('Connected to mysql successfully with %d attempt(s).' % (self.mysql_connect.retry.statistics['attempt_number']))
return (mysql_engine, mysql_conn)
Если декоратор (повтор) не определен как часть класса (и не является статическим), вы не можете ссылаться на экземпляр объекта в нем.