Python:使用“生成树”;“收益率”;
我试图建立一个系统来生成一组“配置”。 这些配置是存储在python dict中的简单键/值对 这些配置是通过一系列功能转换dict的结果,这就是我所说的工作流 下面是一个简单的例子,说明了我的结论:Python:使用“生成树”;“收益率”;,python,yield,itertools,Python,Yield,Itertools,我试图建立一个系统来生成一组“配置”。 这些配置是存储在python dict中的简单键/值对 这些配置是通过一系列功能转换dict的结果,这就是我所说的工作流 下面是一个简单的例子,说明了我的结论: global_data = [dict()] def workflow_step1(data): results = [] for i in range(1,4): data['key'] = i results.append(copy.deepc
global_data = [dict()]
def workflow_step1(data):
results = []
for i in range(1,4):
data['key'] = i
results.append(copy.deepcopy(data))
return results
def workflow_step2(data):
results = []
for i in range(1,3):
data['otherkey'] = i
results.append(copy.deepcopy(data))
return results
def workflow_step3(data):
data['yetanotherkey'] = 42
return [copy.deepcopy(data)]
def list_workflow():
return [workflow_step1, workflow_step2, workflow_step3]
def merge(lhs,rhs):
return lhs+rhs
def run(data):
for step in list_workflow():
data = reduce(lambda lhs, rhs: lhs+rhs, [step(d) for d in data])
return data
print run(global_data)
这很有效,我得到:
[{'yetanotherkey': 42, 'otherkey': 1, 'key': 1},
{'yetanotherkey': 42, 'otherkey': 2, 'key': 1},
{'yetanotherkey': 42, 'otherkey': 1, 'key': 2},
{'yetanotherkey': 42, 'otherkey': 2, 'key': 2},
{'yetanotherkey': 42, 'otherkey': 1, 'key': 3},
{'yetanotherkey': 42, 'otherkey': 2, 'key': 3}]
如您所见,目标是获得dict的所有可能组合。工作流的每个步骤都会返回一组可能的组合,这将为后续步骤创建一个新的可能性分支
我面临的问题是,用户现在正在创建越来越多的工作流步骤,从而导致组合爆炸
我天真的设计中的问题是,我一次生成所有可能性的整个树
我希望使用yield
和生成器来解决这个问题,一次生成一个可能性,这样就不会同时存储所有内容
我当然能够使用yield重写工作流步骤:
def workflow_step1(data):
for i in range(1,4):
data['key'] = i
yield copy.deepcopy(data)
def workflow_step2(data):
for i in range(1,3):
data['otherkey'] = i
yield copy.deepcopy(data)
def workflow_step3(data):
data['yetanotherkey'] = 42
yield copy.deepcopy(data)
def list_workflow():
yield workflow_step1
yield workflow_step2
yield workflow_step3
但是我无法让我的大脑思考如何重写run
函数来按顺序处理每个步骤。我迷失在产量和发电机的大脑迷宫中
任何想法都更受欢迎 我认为,
itertools.product
将完全满足您的需求。这里有一种方法返回一个生成器,它一次生成三个步骤的一个组合。即使在一个步骤中有更多的选项,也不会占用大量的时间或内存
def step1():
return [("key", i) for i in range(1,4)]
def step2():
return [("otherkey", i) for i in range(1,3)]
def step3():
return [("yetanotherkey", 42)]
def workflow_generator():
return (dict(p) for p in itertools.product(step1(), step2(), step3()))
如果您希望能够处理数量可变的步骤,您可以稍加修改以使其正常工作:
def workflow_generator(steps):
return (dict(p) for p in itertools.product(*(step() for step in steps)))
使用
工作流生成器([step1,step2,step3])
调用此版本将得到与上一版本相同的结果,不过如果需要,可以用其他方式(例如从函数)组合参数。是的,数据结构混乱。下面的代码只是给出一个想法(就您当前的结构而言,并不是完全可操作的)。您应该基本上使用树,并创建一个类似于工作流管理器的类来注册步骤。阶梯是阶梯树。使用真实id而不是数字
两条建议
一,
二,
我建议您将循环从
workflow\u步骤
函数中取出,然后像这样使用itertools.product
:
import copy
import itertools
def workflow_step1(data, param):
data['key'] = param
def workflow_step2(data, param):
data['otherkey'] = param
def workflow_step3(data, param):
data['yetanotherkey'] = param
def list_workflow():
return ([workflow_step1, workflow_step2, workflow_step3],
[range(1,4), range(1,3), [42]])
def run(data):
steps, param_lists = list_workflow()
for params in itertools.product(*param_lists):
d = copy.deepcopy(data)
for step, param in zip(steps, params):
step(d,param)
yield d
for result in run({}):
print result
您可能可以像以前那样编写
run()
。
class Step:
def __init__(self,name,extra=None):
self.steps = []
self.name = name
def addChild(self,child,repeat=1):
for j in range(1,repeat+1):
self.steps.append(child)
def __str__(self):
s = self.name + "\n"
for sub in self.steps:
s+=str(sub)
return s
step1 = Step("yetanotherkey",42) #root
step2 = Step("otherkey")
step3 = Step("key")
step2.addChild(step3,2)
step1.addChild(step2,3)
print step1
import copy
import itertools
def workflow_step1(data, param):
data['key'] = param
def workflow_step2(data, param):
data['otherkey'] = param
def workflow_step3(data, param):
data['yetanotherkey'] = param
def list_workflow():
return ([workflow_step1, workflow_step2, workflow_step3],
[range(1,4), range(1,3), [42]])
def run(data):
steps, param_lists = list_workflow()
for params in itertools.product(*param_lists):
d = copy.deepcopy(data)
for step, param in zip(steps, params):
step(d,param)
yield d
for result in run({}):
print result