将实例变量传递给装饰器
Passing instance variables to a decorator
我发现这个有用的装饰器允许你传入一些可选参数
def mlflow_experiment(
_func=None,
*,
experiment_name=None
):
def experiment_decorator(func):
@functools.wraps(func)
def experiment_wrapper(self, *args, **kwargs):
nonlocal experiment_name
experiment_id = (
mlflow.set_experiment(experiment_name)
if experiment_name is not None
else None
)
...
value = func(self, *args, **kwargs)
return value
return experiment_wrapper
if _func is None:
return experiment_decorator
else:
return experiment_decorator(_func)
所以在这样的用例中,我只是将一个字符串传递给 experiment_name
,代码可以完美运行。
@mlflow_experiment(autolog=True, experiment_name = 'blarg')
def train_mlflow(self, maxevals=50, model_id=0):
...
我一直很难弄清楚装饰器的范围,但我并不惊讶使用传递在 __init__
中定义的实例变量不起作用。
class LGBOptimizerMlfow:
def __init__(self, arg):
self.arg = arg
@mlflow_experiment(autolog=True, experiment_name = self.arg)
def train_mlflow(self, maxevals=50, model_id=0):
...
>>> `NameError: name 'self' is not defined`
为了查看作用域是否是一个问题,我在 class 之外声明了变量并且它起作用了。
我决定在 class 中声明一个全局变量,它也可以工作,但不太理想,特别是如果我想将它传递到 class 或作为可选参数的方法。
class LGBOptimizerMlfow:
global arg
arg = 'hi'
@mlflow_experiment(autolog=True, experiment_name = arg)
def train_mlflow(self, maxevals=50, model_id=0):
...
任何帮助修改代码以便装饰器接受实例变量的帮助都会很好。
谢谢!
装饰器在 class 被 定义时被调用 ,并且 self
只是用于每个实例方法的参数,而不是 class 本身提供。因此 self
在您需要它用作装饰器的参数时未定义。
您需要修改 experiment_wrapper
以直接从 its self
参数中获取名称,而不是从 mflow_experiment
的参数中获取名称。像
def mlflow_experiment(
_func=None,
*,
<strike>experiment_name=None,</strike>
tracking_uri=None,
autolog=False,
run_name=None,
tags=None,
):
def experiment_decorator(func):
@functools.wraps(func)
def experiment_wrapper(self, *args, **kwargs):
nonlocal tracking_uri
<b>experiment_name = getattr(self, 'experiment_name', None)</b>
experiment_id = (
mlflow.set_experiment(experiment_name)
if experiment_name is not None
else None
)
...
with mlflow.start_run(experiment_id=experiment_id
, run_name=run_name
, tags=tags):
value = func(self, *args, **kwargs)
return value
return experiment_wrapper
if _func is None:
return experiment_decorator
else:
return experiment_decorator(_func)
然后您需要确保每个实例都有一个与之关联的实验名称(或None)。
class LGBOptimizerMlfow:
def __init__(self, arg, experiment_name=None):
self.arg = arg
<b>self.experiment_name = experiment_name</b>
@mlflow_experiment(autolog=True<strike>, experiment_name = self.arg</strike>)
def train_mlflow(self, maxevals=50, model_id=0):
...
另一种方法是使 experiment_name
成为 train_mflow
的参数,这样可以更容易地使用相同的方法创建不同的名称。 (这可能更接近您的意图。)
class LGBOptimizerMlfow:
def __init__(self, arg):
self.arg = arg
@mlflow_experiment(autolog=True)
def train_mlflow(self, maxevals=50, model_id=0<b>, experiment_name=None):
if experiment_name is None:
self.experiment_name = self.arg</b>
...
装饰器的定义同上。
我发现这个有用的装饰器允许你传入一些可选参数
def mlflow_experiment(
_func=None,
*,
experiment_name=None
):
def experiment_decorator(func):
@functools.wraps(func)
def experiment_wrapper(self, *args, **kwargs):
nonlocal experiment_name
experiment_id = (
mlflow.set_experiment(experiment_name)
if experiment_name is not None
else None
)
...
value = func(self, *args, **kwargs)
return value
return experiment_wrapper
if _func is None:
return experiment_decorator
else:
return experiment_decorator(_func)
所以在这样的用例中,我只是将一个字符串传递给 experiment_name
,代码可以完美运行。
@mlflow_experiment(autolog=True, experiment_name = 'blarg')
def train_mlflow(self, maxevals=50, model_id=0):
...
我一直很难弄清楚装饰器的范围,但我并不惊讶使用传递在 __init__
中定义的实例变量不起作用。
class LGBOptimizerMlfow:
def __init__(self, arg):
self.arg = arg
@mlflow_experiment(autolog=True, experiment_name = self.arg)
def train_mlflow(self, maxevals=50, model_id=0):
...
>>> `NameError: name 'self' is not defined`
为了查看作用域是否是一个问题,我在 class 之外声明了变量并且它起作用了。
我决定在 class 中声明一个全局变量,它也可以工作,但不太理想,特别是如果我想将它传递到 class 或作为可选参数的方法。
class LGBOptimizerMlfow:
global arg
arg = 'hi'
@mlflow_experiment(autolog=True, experiment_name = arg)
def train_mlflow(self, maxevals=50, model_id=0):
...
任何帮助修改代码以便装饰器接受实例变量的帮助都会很好。
谢谢!
装饰器在 class 被 定义时被调用 ,并且 self
只是用于每个实例方法的参数,而不是 class 本身提供。因此 self
在您需要它用作装饰器的参数时未定义。
您需要修改 experiment_wrapper
以直接从 its self
参数中获取名称,而不是从 mflow_experiment
的参数中获取名称。像
def mlflow_experiment(
_func=None,
*,
<strike>experiment_name=None,</strike>
tracking_uri=None,
autolog=False,
run_name=None,
tags=None,
):
def experiment_decorator(func):
@functools.wraps(func)
def experiment_wrapper(self, *args, **kwargs):
nonlocal tracking_uri
<b>experiment_name = getattr(self, 'experiment_name', None)</b>
experiment_id = (
mlflow.set_experiment(experiment_name)
if experiment_name is not None
else None
)
...
with mlflow.start_run(experiment_id=experiment_id
, run_name=run_name
, tags=tags):
value = func(self, *args, **kwargs)
return value
return experiment_wrapper
if _func is None:
return experiment_decorator
else:
return experiment_decorator(_func)
然后您需要确保每个实例都有一个与之关联的实验名称(或None)。
class LGBOptimizerMlfow:
def __init__(self, arg, experiment_name=None):
self.arg = arg
<b>self.experiment_name = experiment_name</b>
@mlflow_experiment(autolog=True<strike>, experiment_name = self.arg</strike>)
def train_mlflow(self, maxevals=50, model_id=0):
...
另一种方法是使 experiment_name
成为 train_mflow
的参数,这样可以更容易地使用相同的方法创建不同的名称。 (这可能更接近您的意图。)
class LGBOptimizerMlfow:
def __init__(self, arg):
self.arg = arg
@mlflow_experiment(autolog=True)
def train_mlflow(self, maxevals=50, model_id=0<b>, experiment_name=None):
if experiment_name is None:
self.experiment_name = self.arg</b>
...
装饰器的定义同上。