2012-11-02 2 views
1

"구성"세트를 생성하도록 시스템을 설정하려고합니다. 이러한 구성은 python dict에 저장된 간단한 키/값 쌍입니다.Python : "yield"를 사용하여 트리 생성

이러한 구성은 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과 발전기를 사용하여 이것을 해결하기를 바랬다.

나는 물론 워크 플로우 단계를 사용하여 수율을 다시 할 수 있었다 :

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 기능을 재 작성하는 방법을 생각 할 수 없습니다. 나는 수확량과 발전기의 두뇌에서 길을 잃는다.

더 많은 아이디어가 환영입니다!

+0

당신은 아마'실행을 쓸 수 있습니다()'당신이 이전과 같은 방식으로. – martineau

답변

3

나는 itertools.product이 원하는대로 정확하게 수행 할 것이라고 생각합니다. 한 번에 세 단계의 조합을 생성하는 생성기를 반환하는 접근 방식이 있습니다. 한 번에 더 많은 옵션이 있더라도 엄청난 시간이나 메모리가 필요하지 않습니다. 같은 결과를 얻을 수

def workflow_generator(steps): 
    return (dict(p) for p in itertools.product(*(step() for step in steps))) 

workflow_generator([step1, step2, step3])으로이 버전을 호출 : 당신이 단계의 변수 수를 처리 할 수있게하려면

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())) 

, 당신은 그 일을 단지 약간의 물건을 수정할 수 있습니다 (함수에서와 같이) 원하는 경우 다른 방법으로 인수를 어셈블 할 수 있지만 이전 버전을 사용합니다.

0

예, 데이터 구조가 엉망입니다. 다음 코드는 아이디어를 제공하는 것입니다 (현재 구조와 관련하여 완전히 작동하지는 않음). 기본적으로 트리를 사용하고 단계를 등록하는 워크 플로 관리자와 같은 클래스를 만들어야합니다. 단계는 계단의 나무입니다. 숫자 대신 실제 ID를 사용하십시오.

두 제안

1.

import copy 

global_data = [dict()] 

class workflowManager: 

    def __init__(self): 
     self.steps = [] 
     self.data = list() 

    def registerStep(self,step,stepNumber=1): 
     for i in range(1,stepNumber+1): 
      self.steps.append(step) 

    def registerSubStep(self,step,substep): 


    ''' 
    def hookToStep(self,step,hook): 
     #find all steps 
     indices = [i for i, x in enumerate(self.steps) if x == step] 
     print 'hooking at ',indices 
     for k in indices: 
      a = self.steps[:k] 
      b = self.steps[k:] 
      self.steps = a + [hook] + b 
    ''' 

    def performOnData(self): 
     print 'self.data ',self.data 
     for step in self.steps: 
      print 'performing step ',step 
      print 'data ',self.data 
      self.data = step(self.data) 

    def __str(self): 
     return str(data) 

def step1(data): 
    lastn = 0 
    try: 
     lastn = data[-1]['key'] 
    except: 
     pass 
    data.append({'key': lastn+1}) 
    return data 

def step2(data): 
    lastn = 0 
    try: 
     lastn = data[-1]['otherkey'] 
    except: 
     pass 

    data.append({'otherkey': lastn+1}) 
    return data 

def step3(data): 
    data.append({'yetanotherkey': 42}) 
    return data 


w = workflowManager() 
w.step_register(step1,4) 
#w.step_register(step2,3) 
#w.step_register(step3,1) 
w.hookToStep(step1,step3) 

print w 

w.performOnData() 

print w 

2

.

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 
0

난 당신이 workflow_step 기능에서 루프를 보시기 바랍니다,이 같은 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 
관련 문제