Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/api/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:使用“生成树”;“收益率”;_Python_Yield_Itertools - Fatal编程技术网

Python:使用“生成树”;“收益率”;

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

我试图建立一个系统来生成一组“配置”。 这些配置是存储在python dict中的简单键/值对

这些配置是通过一系列功能转换dict的结果,这就是我所说的工作流

下面是一个简单的例子,说明了我的结论:

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