我正在使用python,并试图找到一种优雅地将多个生成器链接在一起的方法。例如,有一个根生成器,它提供某种类型的数据,每个值都像级联一样传递给它的“子对象”,而级联又可以修改它们接收到的对象。我可以走这条路:
for x in gen1:
gen2(x)
gen3(x)但它既丑陋又不优雅。我在想一种更实用的做事方式。
发布于 2017-08-29 01:10:50
管道可能看起来更像这样:
for x in gen3(gen2(gen1())):
print x例如:
for i, x in enumerate(range(10)):
print i, x在Python中,没有一种方法可以分叉(或"tee")管道。如果您想要多个管道,则必须复制它们:gen2(gen1())和gen3(gen1())。
发布于 2017-08-29 01:19:44
Dave Beazley gave this example in a talk he did in 2008。目标是对Apache web服务器日志中传输的数据字节数进行求和。假设日志格式如下:
81.107.39.38 - ... "GET /ply/ HTTP/1.1" 200 7587
81.107.39.38 - ... "GET /favicon.ico HTTP/1.1" 404 133
81.107.39.38 - ... "GET /admin HTTP/1.1" 403 -传统的(非生成器)解决方案可能如下所示:
with open("access-log") as wwwlog:
total = 0
for line in wwwlog:
bytes_as_str = line.rsplit(None,1)[1]
if bytes_as_str != '-':
total += int(bytes_as_str)
print("Total: {}".format(total))使用生成器表达式的生成器管道可以可视化为:
access-log => wwwlog => bytecolumn => bytes => sum() => total可能看起来像这样:
with open("access-log") as wwwlog:
bytecolumn = (line.rsplit(None,1)[1] for line in wwwlog)
bytes = (int(x) for x in bytecolumn if x != '-')
print("Total: {}".format(sum(bytes)))Dave Beazley的幻灯片和更多的例子可以在on his website上找到。His later presentations elucidate this further。
如果不知道你到底想做什么,就很难说得更多了,所以我们可以评估你所做的每件事是否都需要一个自定义的生成器(生成器表达式/理解在许多事情上都可以很好地工作,而不需要声明生成器函数)。
发布于 2017-08-29 03:15:03
下面是一个简明的例子:
def negate_nums(g):
for x in g:
yield -x
def square_nums(g):
for x in g:
yield x ** 2
def half_num(g):
for x in g:
yield x / 2.0
def compose_gens(first_gen,*rest_gens):
newg = first_gen(compose_gens(*rest_gens)) if rest_gens else first_gen
return newg
for x in compose_gens(negate_nums,square_nums,half_num,range(10)):
print(x)在这里,您正在组合生成器,以便在最后的compose_gens调用中从右向左调用它们。您可以通过反转args将其更改为管道。
https://stackoverflow.com/questions/45924087
复制相似问题