使用 Python 时如何在另一个函数中传递一个函数

How to pass a function within another function when using Python

这是我正在使用的 CSV 文件:

`"A","B","C","D","E","F","G","H","I","J"

"88",18,1,"<Req TID=""34"" ReqType=""MS""><IISO /><CID>2</CID><MemID>0000</MemID><MemPass /><RequestData><S>[REMOVED]</S><Na /><La /><Card>[REMOVED]</Card><Address /><HPhone /><Mail /></ReqData></Req>","<Response T=""3"" RequestType=""MS""><MS><Memb><PrivateMembers /><Ob>0-12-af</Ob><Locator /></Memb><S>[REMOVED]</S><CNum>[REMOVED]</CNum><FName /><LaName /><Address /><HPhone /><Email /><IISO /><MemID /><MemPass /><T /><CID /><T /></MS></Response>",0-JAN-10 12.00.02 AM,27-JUN-15 12.00.00 AM,"26",667,0
"22",22,1,"<Req TID=""45"" ReqType=""MS""><IISO /><CID>4</CID><MemID>0000</MemID><MemPass /><RequestData><S>[REMOVED]</S><Na /><La /><Card>[REMOVED]</Card><Address /><HPhone /><Mail /></ReqData></Req>","<Response T=""10"" RequestType=""MS""><MS><Memb><PrivateMembers /><Ob>0-12-af</Ob><Locator /></Memb><S>[REMOVED]</S><CNum>[REMOVED]</CNum><FName /><LaName /><Address /><HPhone /><Email /><IISO /><MemID /><MemPass /><T /><CID /><T /></MS></Response>",0-JAN-22 12.00.02 AM,27-JUN-22 12.00.00 AM,"26",667,0
"32",22,1,"<Req TID=""15"" ReqType=""MS""><IISO /><CID>45</CID><MemID>0000</MemID><MemPass /><RequestData><S>[REMOVED]</S><Na /><La /><Card>[REMOVED]</Card><Address /><HPhone /><Mail /></ReqData></Req>","<Response T=""10"" RequestType=""MS""><MS><Memb><PrivateMembers /><Ob>0-12-af</Ob><Locator /></Memb><S>[REMOVED]</S><CNum>[REMOVED]</CNum><FName /><LaName /><Address /><HPhone /><Email /><IISO /><MemID /><MemPass /><T /><CID /><T /></MS></Response>",0-JAN-20 12.00.02 AM,27-JUN-34 12.00.00 AM,"26",667,0`

下面的函数有注释。简而言之,函数 get_clientresponses_two 读取上面的 CSV,选择列 E 的数据实例(XML 数据)。有两个两个生成器函数来解析 **列 E ** 中的 XML 数据为了将 XML 标签及其文本转换为 Python 字典。具体来说,flatten_dict() 函数 returns 一个可迭代的(键,值)对序列。可以将其转换为包含 list(flatten_dict(root)).

的对列表

到目前为止所写的输出是生成字典。然后,def allocate_and_write_data_ 然后获取这些并创建两个不同的 collections。一个是使用 flatten_dict() 中的键更新的集合。这是为了确保 XML 中的元素标签包含在新编写的 CSV 中的 headers 中(连同它们的相应值)。编写代码是为了保持 headers 的完整性(无重复),并允许将新元素标签转换为 headers(连同它们的值)。此外,headers 和已经存在的值应该足够灵活,以便使用新实例进行更新(同样 - 也是唯一的)。此外,所有其他行都旨在存储和更新。然后,我将 headers 转换为一个列表,并确保使用列表理解 data

来说明所有缺失的数据实例(带有“”)
import csv
from collections import OrderedDict
from xml.etree.ElementTree import ParseError
import collections 
from __future__ import print_function

def get_clientresponses_2(filename = 's.csv'):

    with open(filename, 'rU') as infile:
        reader = csv.DictReader(infile)         # read the file as a dictionary for each row ({header : value})
        data = {}
        for row in reader:
            for header, value in row.items():
                try:
                    data[header].append(value)
                except KeyError:
                    data[header] = [value]

        client_responses = data['E'] #returns a list
        for client_response in client_responses:
            xml_string = (''.join(client_response))
            xml_string = xml_string.replace('&amp;', '')
            try:
                root = ElementTree.XML(xml_string)
                print(root) 
            except ET.ParseError:
                print("catastrophic failure")
                continue

def allocate_and_write_2(get_clientresponses_2_gen):

    with open(filename, 'r') as infile:
        reader = csv.DictReader(infile)         # read the file as a dictionary for each row ({header : value})
        header = set()
        results = []
        #     data = {} # this is not needed for the purpose of this organization
        for row in reader:
            for get_clientresponses_2 in get_clientresponses_2_gen:
                xml_data = get_clientresponses_2()
                row.update(xml_data)        # just for XML data
                results.append(row)         # everything else
                header.update(row.keys())  # can't forget headers

    #     print(row) # returns dictionary of key values pairs (headers : values)
    #     print(results) # returns list wrapper for dictionary
    #     print(headers) #returns set of all headers
        headers_list = list(header)
    #     print(headers_list) #list form of set

        with open('csv_output.csv', 'wt') as f:
            writer = csv.writer(f)
            writer.writerow(headers_list)
            for row in results:
                data = [row.get(x, '') for x in headers_list]
                writer.writerow(data)
    #             writer.writerows(zip(headers_list, data))

输出如下:

C,HPhone,Locator,IISO,E,S,FName,LaName,J,D,MemID,ResponseRequestType,T,Email,I,Ob,G,MemPass,Address,A,PrivateMembers,H,CNum,ResponseT,CID,B,F
1,,,,"<Response T=""3"" RequestType=""MS""><MS><Memb><PrivateMembers /><Ob>0-12-af</Ob><Locator /></Memb><S>[REMOVED]</S><CNum>[REMOVED]</CNum><FName /><LaName /><Address /><HPhone /><Email /><IISO /><MemID /><MemPass /><T /><CID /><T /></MS></Response>",[REMOVED],,,0,"<Req TID=""34"" ReqType=""MS""><IISO /><CID>2</CID><MemID>0000</MemID><MemPass /><RequestData><S>[REMOVED]</S><Na /><La /><Card>[REMOVED]</Card><Address /><HPhone /><Mail /></ReqData></Req>",,MS,,,667,0-12-af,27-JUN-15 12.00.00 AM,,,88,,26,[REMOVED],10,,18,0-JAN-10 12.00.02 AM
1,,,,"<Response T=""10"" RequestType=""MS""><MS><Memb><PrivateMembers /><Ob>0-12-af</Ob><Locator /></Memb><S>[REMOVED]</S><CNum>[REMOVED]</CNum><FName /><LaName /><Address /><HPhone /><Email /><IISO /><MemID /><MemPass /><T /><CID /><T /></MS></Response>",[REMOVED],,,0,"<Req TID=""45"" ReqType=""MS""><IISO /><CID>4</CID><MemID>0000</MemID><MemPass /><RequestData><S>[REMOVED]</S><Na /><La /><Card>[REMOVED]</Card><Address /><HPhone /><Mail /></ReqData></Req>",,MS,,,667,0-12-af,27-JUN-22 12.00.00 AM,,,22,,26,[REMOVED],10,,22,0-JAN-22 12.00.02 AM
1,,,,"<Response T=""10"" RequestType=""MS""><MS><Memb><PrivateMembers /><Ob>0-12-af</Ob><Locator /></Memb><S>[REMOVED]</S><CNum>[REMOVED]</CNum><FName /><LaName /><Address /><HPhone /><Email /><IISO /><MemID /><MemPass /><T /><CID /><T /></MS></Response>",[REMOVED],,,0,"<Req TID=""15"" ReqType=""MS""><IISO /><CID>45</CID><MemID>0000</MemID><MemPass /><RequestData><S>[REMOVED]</S><Na /><La /><Card>[REMOVED]</Card><Address /><HPhone /><Mail /></ReqData></Req>",,MS,,,667,0-12-af,27-JUN-34 12.00.00 AM,,,32,,26,[REMOVED],10,,22,0-JAN-20 12.00.02 AM

但是,当我尝试在 'allocate_and_write' 中调用 'get_clientresponses_two' 时收到以下错误:

<ipython-input-91-cfd866a1c0b6> in allocate_and_write_2(get_clientresponses_2_gen)
     37         #     data = {} # this is not needed for the purpose of this organization
     38         for row in reader:
---> 39             for get_clientresponses_2 in get_clientresponses_2_gen:
     40                 xml_data = get_clientresponses_2()
     41                 row.update(xml_data)        # just for XML data

TypeError: 'function' object is not iterable

根据我对生成器和该论坛上其他帖子的理解,我知道这是由于这个问题造成的。我想通过传入第一个函数的输出、get_clientresponses_two 的输出来迭代生成器输出,同时实现另一个函数。我想要指导和反馈,具体说明如何最好地纠正这个问题。

根据评论,似乎 get_clientresponses_2_gen 是一个生成器函数,如果是这样,那么这不是您遍历生成器函数的方式 -

for get_clientresponses_2 in get_clientresponses_2_gen:
    xml_data = get_clientresponses_2()

要遍历生成器函数并将每个值放入 xml_data ,请使用 -

for xml_data in get_clientresponses_2_gen():

(将其替换为上面给出的两行)。

感谢@AnandSKumar 的指导:

这确实是由于我在生成器函数的上下文中使用迭代器构造函数的方式。我用 Anand 的建议替换了我的原始脚本:

for xml_data in get_clientresponses_2():
     xml_dat =  dict(flatten_dict(xml_data))

但是,我还必须通过返回每个 XML 树的根并将其传递给 allocate_and_write()

来修改 get_clientresponses_2

为了防止任何副作用,我将它们作为两个相互排斥的函数保留。

您只需在

内调用 allocate_and_write()
if __name__ == "__main__":
    main()

我这样做的原因很详细here

以下是 2 个功能套件:

import csv
from collections import OrderedDict
from xml.etree.ElementTree import ParseError
import collections 
from __future__ import print_function


def get_clientresponses_2(filename = 's.csv'):

    with open(filename, 'rU') as infile:
        reader = csv.DictReader(infile)         # read the file as a dictionary for each row ({header : value})
        data = {}
        for row in reader:
            for header, value in row.items():
                try:
                    data[header].append(value)
                except KeyError:
                    data[header] = [value]

        client_responses = data['E'] #returns a list
        for client_response in client_responses:
            xml_string = (''.join(client_response))
            xml_string = xml_string.replace('&amp;', '')
            try:
                root = ElementTree.XML(xml_string)
#                 print(root)
                return root
            except ET.ParseError:
                print("catastrophic failure")
                continue

def allocate_and_write_2():

    with open(filename, 'r') as infile:
        reader = csv.DictReader(infile)         # read the file as a dictionary for each row ({header : value})
        header = set()
        results = []
        #     data = {} # this is not needed for the purpose of this organization
        for row in reader:
            for xml_data in get_clientresponses_2():
                xml_dat =  dict(flatten_dict(xml_data))
                row.update(xml_dat)        # just for XML data
                results.append(row)         # everything else
                header.update(row.keys())  # can't forget headers

        #     print(row) # returns dictionary of key values pairs (headers : values)
        #     print(results) # returns list wrapper for dictionary
        #     print(headers) #returns set of all headers
            headers_list = list(header)
        #     print(headers_list) #list form of set

            with open('csv_output.csv', 'wt') as f:
                writer = csv.writer(f)
                writer.writerow(headers_list)
                for row in results:
                    data = [row.get(x, '') for x in headers_list]
#                     print(data)
                    writer.writerow(data)
    #             writer.writerows(zip(headers_list, data))