【发布时间】:2020-12-07 01:43:25
【问题描述】:
这是我第二次尝试理解如何在 Luigi 中将参数传递给依赖项。第一个是here。
想法是:我有TaskC,它依赖于TaskB,它依赖于TaskA,它依赖于Task0。我希望整个序列始终完全相同,除了我希望能够控制Task0 读取的文件,我们称之为path。 Luigi 的理念通常是每个任务应该只知道它所依赖的任务及其参数。这样做的问题是TaskC、TaskB 和TaskA 都必须接受变量path,其唯一目的是然后将其传递给Task0。
所以,Luigi 为此提供的解决方案称为Configuration Classes
下面是一些示例代码:
from pathlib import Path
import luigi
from luigi import Task, TaskParameter, IntParameter, LocalTarget, Parameter
class config(luigi.Config):
path = Parameter(default="defaultpath.txt")
class Task0(Task):
path = Parameter(default=config.path)
arg = IntParameter(default=0)
def run(self):
print(f"READING FROM {self.path}")
Path(self.output().path).touch()
def output(self): return LocalTarget(f"task0{self.arg}.txt")
class TaskA(Task):
arg = IntParameter(default=0)
def requires(self): return Task0(arg=self.arg)
def run(self): Path(self.output().path).touch()
def output(self): return LocalTarget(f"taskA{self.arg}.txt")
class TaskB(Task):
arg = IntParameter(default=0)
def requires(self): return TaskA(arg=self.arg)
def run(self): Path(self.output().path).touch()
def output(self): return LocalTarget(f"taskB{self.arg}.txt")
class TaskC(Task):
arg = IntParameter(default=0)
def requires(self): return TaskB(arg=self.arg)
def run(self): Path(self.output().path).touch()
def output(self): return LocalTarget(f"taskC{self.arg}.txt")
(忽略所有 output 和 run 内容。它们就在那里,因此示例成功运行。)
上面例子的重点是控制print(f"READING FROM {self.path}")这一行,没有任务A、B、C依赖path。
确实,通过配置类,我可以控制Task0 参数。如果Task0 没有传递path 参数,则它采用其默认值,即config().path。
我现在的问题是,在我看来,这似乎只在“构建时”工作,当解释器第一次加载代码时,而不是在运行时(我不清楚细节)。
所以这些都不起作用:
一)
if __name__ == "__main__":
for i in range(3):
config.path = f"newpath_{i}"
luigi.build([TaskC(arg=i)], log_level="INFO")
===== Luigi Execution Summary =====
Scheduled 4 tasks of which:
* 4 ran successfully:
- 1 Task0(path=defaultpath.txt, arg=2)
- 1 TaskA(arg=2)
- 1 TaskB(arg=2)
- 1 TaskC(arg=2)
This progress looks :) because there were no failed tasks or missing dependencies
===== Luigi Execution Summary =====
我不确定为什么这不起作用。
B)
if __name__ == "__main__":
for i in range(3):
luigi.build([TaskC(arg=i), config(path=f"newpath_{i}")], log_level="INFO")
===== Luigi Execution Summary =====
Scheduled 5 tasks of which:
* 5 ran successfully:
- 1 Task0(path=defaultpath.txt, arg=2)
- 1 TaskA(arg=2)
- 1 TaskB(arg=2)
- 1 TaskC(arg=2)
- 1 config(path=newpath_2)
This progress looks :) because there were no failed tasks or missing dependencies
===== Luigi Execution Summary =====
这实际上是有道理的。有两个 config 类,我只设法更改了其中一个的 path。
帮助?
编辑:当然,让path 引用全局变量是可行的,但它不是通常 Luigi 意义上的参数。
EDIT2:我尝试了以下答案的第 1) 点:
config 定义相同
class config(luigi.Config):
path = Parameter(default="defaultpath.txt")
我修正了指出的错误,即Task0 现在是:
class Task0(Task):
path = Parameter(default=config().path)
arg = IntParameter(default=0)
def run(self):
print(f"READING FROM {self.path}")
Path(self.output().path).touch()
def output(self): return LocalTarget(f"task0{self.arg}.txt")
最后我做到了:
if __name__ == "__main__":
for i in range(3):
config.path = Parameter(f"file_{i}")
luigi.build([TaskC(arg=i)], log_level="WARNING")
这不起作用,Task0 仍然得到path="defaultpath.txt"。
【问题讨论】: