链接嵌套收益率

时间:2019-05-01 16:01:51

标签: python yield

我想建立一个数据管道,对数据系列的行执行一系列操作。

大多数函数将在单行,单行的基础上工作,但是其中一些操作将“扩展”序列-我的意思是一行将进入该函数,而另一行将超过一行可能会由于该功能而产生。

我想设置一系列函数,这些函数足够健壮,可以自行处理此行为,而无需编写大量监督代码。

使用yield代表了一个机会-如果每个函数消耗了前一个函数的收益,并自己充当了生成器,那么我可以任意地将这些格式良好的函数链接在一起-从优雅的角度讲要好。

这是我的设置代码,其中func_x充当简单的1-1函数,func_y进行扩展。

from collections import OrderedDict
data_source = [ OrderedDict({"id" : "1", "name" : "Tom", "sync" : "a"}),
            OrderedDict({"id" : "2", "name" : "Steve", "sync" : "a"}),
            OrderedDict({"id" : "3", "name" : "Ulrich", "sync" : "b"}),
            OrderedDict({"id" : "4", "name" : "Victor", "sync" : "b"}),
            OrderedDict({"id" : "5", "name" : "Wolfgang", "sync" : "c"}),
            OrderedDict({"id" : "6", "name" : "Xavier", "sync" : "c"}),
            OrderedDict({"id" : "7", "name" : "Yves", "sync" : "c"}),
            OrderedDict({"id" : "8", "name" : "Zaphod", "sync" : "d"})]
def row_getter(source):
    for content in source:
        yield content.copy()

def func_x(row):
    try:
        q=next(row)
        if q['name']=="Tom":
            q['name']="Richard"
        yield q.copy()
    except StopIteration:
        print ("Stop x")


def func_y(row):
    try:
        q=next(row)
        for thingy in range(0,2):
            q['thingy']=thingy
            yield q.copy()
    except StopIteration:
        print ("Stop y")

rg = row_getter(data_source)
iter_func = func_y(func_x(rg))

现在,我可以通过遍历iter_func对象来获取第一组数据:

print (next(iter_func))
>> OrderedDict([('id', '1'), ('name', 'Richard'), ('sync', 'a'), ('thingy', 0)])

再次:

print (next(iter_func))
>> OrderedDict([('id', '1'), ('name', 'Richard'), ('sync', 'a'), ('thingy', 1)])

再一次,尽管这次,没有看到Steve的记录(即流中的下一个记录,现在对第一条记录的func_y的扩展已经完成),我遇到了StopIteration错误。

print (next(iter_func))
>> StopIteration                             Traceback (most recent call last)
<ipython-input-15-0fd1ed48c61b> in <module>()
----> 1 print (next(iter_func))

StopIteration: 

所以我不知道这是哪里来的,因为我试图将它们捕获在func_xfunc_y中。

2 个答案:

答案 0 :(得分:1)

您的func_x函数仅产生一项,因此在消耗完该项之后将最终确定。试试这样的东西:

def func_x(row):
    try:
        for q in row:
            if q['name']=="Tom":
                q['name']="Richard"
            yield q
    except StopIteration:
        print ("Stop x")

顺便说一句,请注意,每次屈服都不会复制对象。在许多情况下,这可能很好,但是请注意,在func_y中,每个相同的对象产生两次,并将'thingy'设置为不同的值。这意味着,例如,如果您这样做(在发布代码之后):

d1 = next(iter_func)
d2 = next(iter_func)

d1d2将是同一对象,尤其是它们都将'thingy'设置为1

答案 1 :(得分:1)

内置工具(特别是mapitertools.chain)可以为您做到这一点。

from collections import OrderedDict
from itertools import chain


data_source = [ OrderedDict({"id" : "1", "name" : "Tom", "sync" : "a"}),
            OrderedDict({"id" : "2", "name" : "Steve", "sync" : "a"}),
            OrderedDict({"id" : "3", "name" : "Ulrich", "sync" : "b"}),
            OrderedDict({"id" : "4", "name" : "Victor", "sync" : "b"}),
            OrderedDict({"id" : "5", "name" : "Wolfgang", "sync" : "c"}),
            OrderedDict({"id" : "6", "name" : "Xavier", "sync" : "c"}),
            OrderedDict({"id" : "7", "name" : "Yves", "sync" : "c"}),
            OrderedDict({"id" : "8", "name" : "Zaphod", "sync" : "d"})]


def rename(d):
    if d['name'] == "Tom":
        d['name'] = "Richard"
    return d


def add_thingy(d):
    for y in range(2):
        yield {'thingy': y, **d}

for x in chain.from_iterable(add_thingy(d) 
                             for d in map(rename,
                                          data_source)):
    print(x)

map并不是必须的;我们可以在生成器表达式中将rename传递到dict之前,将add_thingy应用于每个for x in chain.from_iterable(add_thingy(rename(d)) for d in data_source): print(x)

map

或以另一种方式使用for x in chain.from_iterable(map(add_thingy, map(rename, data_source))): print(x) 两次:

this.source.getAll().then(value => { 
  value.forEach(element => {
      this.precioTotal+= parseInt(_.get(element, 'price', 0));
  });
});