如何用参数修饰类方法?当前代码是
def establish_con(func):
con, meta = db.connect(config.user, config.password, config.db)
meta.reflect(bind=con)
def inner(self, query, con, *args, **kwargs):
return func(self, query, con, *args, **kwargs)
con.close()
return inner
class DataReader:
def __init__(self):
self.data = {}
@establish_con
def execQuery(self, query, con):
# con, meta = db.connect(config.user, config.password, config.db)
# meta.reflect(bind=con)
result = pd.read_sql(query, con)
# con.close()
return result
test = DataReader()
df = test.execQuery("Select * from backtest limit 10")
print(df)
当前,第一个参数似乎是类实例。我尝试了不同的代码变体,但总是遇到太多/不足/未定义参数的问题。
我读过其他帖子
How do I pass extra arguments to a Python decorator?
和其他人,但仍然无法弄清楚。
编辑:不是Python decorators in classes的重复项,因为在此答案中,无需向函数传递任何参数。
答案 0 :(得分:1)
@madjardi从this post改编答案以使用参数。
import functools
class Example:
con = "Connection"
def wrapper(func):
@functools.wraps(func)
def wrap(self, *args, **kwargs):
print("inside wrap")
return func(self, Example.con, *args, **kwargs) # use *args to pass objects down
return wrap
@wrapper
def method(self, con, arg):
print("METHOD {0} {1}".format(con, arg))
wrapper = staticmethod(wrapper)
e = Example()
e.method(1) # METHOD Connection 1
答案 1 :(得分:1)
您应该替换:
def inner(self, query, con, *args, **kwargs):
return func(self, query, con, *args, **kwargs)
使用:
def inner(self, query, *args, **kwargs): # no 'con' here
return func(self, query, con, *args, **kwargs)
使用您的策略的一个最小的工作示例将是(实现目标所没有的目标)
def add_arg(method):
def decorated_method(self, *args):
return method(self, 10, *args)
return decorated_method
class Data:
@add_arg
def summation(self, *args):
return sum(args)
d = Data()
print(d.summation(1, 2)) # prints 13, not 3
答案 2 :(得分:1)
这就是我认为您需要这样做的方式。为了将代码更清楚,我将代码分成两个单独的块。
Just的第一部分建立了一个最小的脚手架,以使其可以运行(并跟随执行)第二个块中的代码,并使它尽可能地接近问题所在。它本身并不十分重要。
带有参数的装饰器有效地成为了装饰器工厂,从某种意义上说,它们必须创建一个返回的装饰器函数,然后将其应用于目标函数或方法。
# Scaffolding
class Pandas:
@staticmethod
def read_sql(query, con):
print(f'in Pandas read_sql({query!r}, {con})')
return 'pandas_dataframe'
class Connection:
def close(self):
print('in Connection.close()')
def __repr__(self):
return '<Connection object>'
con = Connection()
class Meta:
def reflect(self, bind=con):
print(f'in Meta.reflect(bind={bind}')
class Database:
def connect(self, user, password, db):
print(f'in Database.connect({user}, {password}, {db})')
return Connection(), Meta()
def __repr__(self):
return '<Database object>'
class Config:
def __init__(self, user, password, db):
self.user = user
self.password = password
self.db = db
# Set up a framework for testing.
pd = Pandas()
meta = Meta()
db = Database()
config = Config('username', 'secret', db)
在建立该环境之后,这就是装饰器的编写方式。
# Decorator
def establish_con(config):
def wrapper(method):
def wrapped(*args, **kwargs):
con, meta = db.connect(config.user, config.password, config.db)
meta.reflect(bind=con)
args = args + (con,)
result = method(*args, **kwargs)
con.close()
return result
return wrapped
return wrapper
class DataReader:
def __init__(self):
self.data = {}
@establish_con(config)
def execQuery(self, query, con):
return pd.read_sql(query, con)
test = DataReader()
df = test.execQuery("Select * from backtest limit 10")
print(df)
输出:
in Database.connect(username, secret, <Database object>)
in Meta.reflect(bind=<Connection object>
in Pandas read_sql('Select * from backtest limit 10', <Connection object>)
in Connection.close()
pandas_dataframe