Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.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_Generator - Fatal编程技术网

Python 如何编写一个好的生成器链接函数

Python 如何编写一个好的生成器链接函数,python,generator,Python,Generator,我有以下职能: def read_data(file_location): for line in open(file_location): # pre-process the line yield line def transform_1(data): for line in data: # change line in some way yield line def transform_2(data):

我有以下职能:

def read_data(file_location):
    for line in open(file_location):
        # pre-process the line  
        yield line

def transform_1(data):
    for line in data:
        # change line in some way
        yield line

def transform_2(data):
    for line in data:
        # change line in some other way
        yield line

def process_file(file_location):
    # Some description
    #
    # returns:
    #     generator
    data = read_data(file_location)
    data = transform_1(data)
    data = transform_2(data)
    return data
我试图做的是从一个文件中读取行,用一些函数转换每一行,然后用结果行做一些事情。我不想一次读所有的行,因为文件太大了

我的问题是我这样做是否正确。代码执行正确,但我脑子里的程序执行感觉很复杂,以至于我不知道我是否能在一个月左右处理好这段代码


所以我想知道的是:是否有某种编程模式可以显示如何正确地将生成器链接到彼此中?

假设每一行都以相同的方式进行转换,您可以将转换函数应用到每一行,并使用生成器迭代所有行,我个人认为这更具可读性

def transform_1(line):
    return line.replace(' ','') # example of transformation

def transform_2(line):
    return line.strip('#')

def process_file(file_location):
    with open(file_location) as in_f:
        for line in in_f:
            yield transform_2(transform_1(line))

根据转换的功能,它们可能被组合成一个函数,但如果没有更多的上下文,就很难知道了。

实际上,这做得很好。我不知道为什么你觉得代码很复杂。关键是每个函数只做一件事是一个加号。显然,函数名应该反映正在进行的转换的类型。这样的代码是非常可测试和可维护的。当您需要在六个月后对管道进行更改时,您可能会惊讶地发现,找到零件比调整并进行更改要容易得多

我建议修改您的read_数据生成器,如下所示:

def read_data(file_location):
    with open(file_location) as f:
        for line in f:
            yield line

首先:简化此操作:
读取数据(文件位置)
=>
打开(文件位置)
将执行完全相同的操作。这是我实际代码的简化版本。它在现实生活中的作用要大得多。@arnerecnangel这基本上就是Python的
map
的目的(这适用于Python 3,其中
map
是惰性的)。然后,转换函数将应用于数据集的元素,而不是整个集合,因为这是生成器生成的结果。对于一个非内置工具,你可以看一下。我不喜欢所有东西都是
data=…
。给事物起描述性的名字。戴夫·比兹利有一个朋友。主要示例从幻灯片34开始,为了便于阅读,变压器被分开。因此,您建议使用最外层的函数
yield
而不是返回生成器?嗯
yield
确实创建了一个生成器,所以我不确定我是否理解您所做的区分。当然,您可以简单地使用生成器表达式,如
return(transform_2(transform_1(line))for line in in_f)
在数据生成器内部对转换进行硬编码不是一个好主意。这会妨碍您要应用的转换的灵活性。然而,将转换应用于项(而不是完整的集合)是一个好主意,这可以通过
map
巧妙地实现:
map(transform\u 2,map(transform\u 1,process\u file(…))
@a\u guest如果没有更多上下文,很难知道,当然,您可以将转换函数解析为
process\u file
的参数。我不认为使用
map()
更像python,但也许这太过分了subjective@ArneRecknagel我的意思是,当您已经在函数中应用了应该产生数据的转换时,那么仅仅获取未转换的数据(如果您需要的话)就不容易了。最好将事情分开:一个函数生成数据,另一个函数转换数据。这样,您就可以选择要应用哪些转换,并且这些转换也是可以单独维护的。另外,我觉得i.m.o.感觉更自然,因为对象被重新分配了好几次,但顶部的分配仍然会影响其行为。我想我觉得在我做了
data=x(data)
之后,我不需要知道调用之前
data
是什么,只需要知道
x()
做了什么。我通常每次都会更改数据的名称,以反映它是如何更改的,特别是因为它可能会经历类型更改,例如它可能是字符串,但接下来的生成器可能会生成元组。