2014-06-26 18 views
1

考慮以下(非工作)示例代碼生成器功能:如何創建調用發電機功能

class MyGenerator: 
    def test_gen(self): 
     for i in range(1,5): 
      if i % 2: 
       self.foo(i) 
      else: 
       self.bar(i) 

    def foo(self, i): 
     yield i 

    def bar(self, i): 
     yield i**2 

g = MyGenerator() 
for i in g.test_gen(): 
    print i 

這是行不通的,因爲test_gen沒有yield,不再發電機的功能。在這個小例子中,我只能返回foobar的值,並將yield轉換爲test_gen,但是我有一種情況,那是不可能的。我怎樣才能再次將test_gen變成一個生成器函數?

回答

5

您需要循環委派生成的結果和產生的:

def test_gen(self): 
    for i in range(1,5): 
     if i % 2: 
      for res in self.foo(i): 
       yield res 
     else: 
      for res in self.bar(i): 
       yield res 

如果您正在使用Python 3.3或者,你應該使用yield from expression做適當的發電機代表團:

def test_gen(self): 
    for i in range(1,5): 
     if i % 2: 
      yield from self.foo(i) 
     else: 
      yield from self.bar(i) 

兩者都將yield重新引入到函數中,再一次使其成爲生成函數。

+0

哈,Python的3路正是我一直在尋找!甜美簡潔。不幸的是,我使用的是Python 2.7 :-( – chiborg

+1

)在這個特殊的例子中,子生成器只會在用盡之前產生一個簡單的項目,所以''yield''例子很好,但是使用它的人們必須嘗試它們會導致耗盡的子生成器,而不是一個單一的項目 - 只有在控制器回到主生成器之後(否則它們將不能與普通的「yield」區分開來) – jsbueno

0

爲什麼不乾脆:

class MyGenerator: 
    def test_gen(self): 
     for i in range(1,5): 
      if i % 2: 
       yield next(self.foo(i)) 
      else: 
       yield next(self.bar(i)) 

    def foo(self, i): 
     yield i 

    def bar(self, i): 
     yield i**2