Python 装饰中的自我参照
我正在用python实现一个数据库连接器类。我将使用韧性库中的Python 装饰中的自我参照,python,python-3.x,python-decorators,python-tenacity,Python,Python 3.x,Python Decorators,Python Tenacity,我正在用python实现一个数据库连接器类。我将使用韧性库中的retrydecorator在数据库连接超时时重试连接 我想将self.retry\u count和self.retry\u interval传递给retry装饰器中的参数 ## etl_connect.py from sqlalchemy import create_engine import pymysql import logging from tenacity import * class Connector():
retry
decorator在数据库连接超时时重试连接
我想将self.retry\u count
和self.retry\u 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\u connect
函数:
## call.py
from etl_connect import *
mysql_connector = Connector('mysql', 'mysql database string here', 5, 10)
engine, conn = mysql_connector.mysql_connect()
但它显示:name错误:未定义名称“self”
回溯(最近一次呼叫最后一次):
文件“call.py”,第5行,在
从etl_连接导入*
文件“/home/developer/ETL_modules/ETL_connect.py”,第19行,在
类连接器():
文件“/home/developer/ETL_modules/ETL_connect.py”,第56行,在连接器中
@重试(等待=等待\u固定(自重试间隔),停止=尝试后停止(自重试计数))
NameError:未定义名称“self”
有没有什么方法可以将self.retry\u count&
self.retry\u 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
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
decorator并阻止对其进行编辑,则可以从类定义中定义一个变量。或者,您可以在设置的文件中定义此基本配置,然后导入它。请看这个:
## 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
我知道这种方法很可靠,但这些选项应该在您的设置中定义,并且无需在每次创建类实例时都传递它们。假设您无法轻松重新定义韧性重试
装饰器,您可以使用自己的一个选项来包装它,该选项引用连接器
实例中的值
我的意思是:
# 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)
答案如下:请注意,答案假设您正在编写装饰程序;如果要导入retry
,则需要定义自己的包装器。这是否回答了您的问题?这对我有用。你能解释一下为什么需要“(self)”吗?你说的是哪一个self
?很抱歉没有澄清--mysql\u connect的return语句中的(self)
。在这两种情况下,\u mysql\u connect
都是一个实例方法,因此需要在Connector
的实例上调用。您是显式地传递它,还是将绑定方法传递给retry
,取决于retry
(在原始问题中未定义)是采用零参数还是1参数可调用。