【问题标题】:Retrieving dict value via hardcoded key, works. Retrieving via computed key doesn't. Why?通过硬编码键检索 dict 值,有效。通过计算键检索不会。为什么?
【发布时间】:2018-12-22 01:16:04
【问题描述】:

我通过比较两组 ID(ID 集来自字典 {ID: XML "RECORD" element})来生成一个通用 ID 列表。一旦我有了公共列表,我想遍历它并从字典中检索与 ID 对应的值(我将写入磁盘)。

当我使用 diff_comm_checker 函数计算公共 ID 列表时,我无法检索 ID 对应的 dict 值。但是,它不会因 KeyError 而失败。我也可以把身份证打印出来。

当我将 ID 硬编码为 common_id 值时,我可以检索 dict 值。

common_ids = diff_comm_checker( list_1, list_2, "text")
# does nothing - no failures

common_ids = ['0603599998140032MB']
#gives me:

0603599998140032MB {'R': '0603599998140032MB'} <Element 'RECORD' at 0x04ACE788>
0603599998140032MB {'R': '0603599998140032MB'} <Element 'RECORD' at 0x04ACE3E0>

所以我怀疑字符串之间存在一些差异。我检查了函数输出并将其与硬编码值进行了比较:

print [(_id, type(_id), repr(_id)) for _id in common_ids][0]

我得到的结果完全一样:

>>> ('0603599998140032MB', <type 'str'>, "'0603599998140032MB'")

我也听从了另一个问题的建议,使用了 difflib.ndiff:

common_ids1 = diff_comm_checker( [x.keys() for x in to_write[0]][0], [x.keys() for x in to_write[1]][0], "text")
common_ids = ['0603599998140032MB']
print "\n".join(difflib.ndiff(common_ids1, common_ids))
>>>  0603599998140032MB

同样,两者之间似乎没有任何区别。

这是一个完整的代码示例:

from StringIO import StringIO
import xml.etree.cElementTree as ET
from itertools import chain, islice

def diff_comm_checker(list_1, list_2, text):
    """Checks 2 lists. If no difference, pass. Else return common set between two lists"""

    symm_diff = set(list_1).symmetric_difference(list_2)
    if not symm_diff:
        pass
    else:
        mismatches_in1_not2 = set(list_1).difference( set(list_2) )
        mismatches_in2_not1 = set(list_2).difference( set(list_1) )

        if mismatches_in1_not2:
            mismatch_logger(
                mismatches_in1_not2,"{}\n1: {}\n2: {}".format(text, list_1, list_2), 1, 2)
        if mismatches_in2_not1:
            mismatch_logger(
                mismatches_in2_not1,"{}\n2: {}\n1: {}".format(text, list_1, list_2), 2, 1)

    set_common = set(list_1).intersection( set(list_2) )
    if set_common:
        return sorted(set_common)
    else:
        return "no common set: {}\n".format(text)


def chunks(iterable, size=10):
    iterator = iter(iterable)
    for first in iterator:
        yield chain([first], islice(iterator, size - 1))

def get_elements_iteratively(file):
    """Create unique ID out of image number and case number, return it along with corresponding xml element"""

    tag = "RECORD"

    tree = ET.iterparse(StringIO(file), events=("start","end"))
    context = iter(tree)
    _, root = next(context)

    for event, record in context:
        if event == 'end' and record.tag == tag:
            xml_element_2 = ''
            xml_element_1 = ''
            for child in record.getchildren():
                if child.tag == "IMAGE_NUMBER":
                    xml_element_1 = child.text
                if child.tag == "CASE_NUM":
                    xml_element_2 = child.text
            r_id = "{}{}".format(xml_element_1, xml_element_2)
            record.set("R", r_id)
            yield (r_id, record)
            root.clear()

def get_chunks(file, chunk_size):
    """Breaks XML into chunks, yields dict containing unique IDs and corresponding xml elements"""

    iterable = get_elements_iteratively(file)

    for chunk in chunks(iterable, chunk_size):
        ids_records = {}
        for k in chunk:
            ids_records[k[0]]=k[1]

        yield ids_records

def create_new_xml(xml_list):

    chunk = 5000

    chunk_rec_ids_1 = get_chunks(xml_list[0], chunk)
    chunk_rec_ids_2 = get_chunks(xml_list[1], chunk)
    to_write = [chunk_rec_ids_1, chunk_rec_ids_2]

    ######################################################################################
    ### WHAT'S GOING HERE ??? WHAT'S THE DIFFERENCE BETWEEN THE OUTPUTS OF THESE TWO ? ###

    common_ids = diff_comm_checker( [x.keys() for x in to_write[0]][0], [x.keys() for x in to_write[1]][0], "create_new_xml - large - common_ids")
    #common_ids = ['0603599998140032MB']

    ######################################################################################

    for _id in common_ids:
        print _id
        for gen_obj in to_write:
            for kv_pair in gen_obj:
                if kv_pair[_id]:
                    print _id, kv_pair[_id].attrib, kv_pair[_id]


if __name__ == '__main__':

    xml_1 = """<?xml version="1.0"?><RECORDSET><RECORD><CASE_NUM>140032MB</CASE_NUM><IMAGE_NUMBER>0603599998</IMAGE_NUMBER></RECORD></RECORDSET>"""
    xml_2 = """<?xml version="1.0"?><RECORDSET><RECORD><CASE_NUM>140032MB</CASE_NUM><IMAGE_NUMBER>0603599998</IMAGE_NUMBER></RECORD></RECORDSET>"""
    create_new_xml([xml_1, xml_2])

【问题讨论】:

    标签: string python-2.7 list dictionary format


    【解决方案1】:

    问题不在于 diff_comm_checker 返回的 common_ids 的类型或值。问题是函数 diff_comm_checker 或在构造函数的参数时破坏了 to_write 的值

    如果你试试这个,你会明白我的意思

    common_ids = ['0603599998140032MB']
    diff_comm_checker( [x.keys() for x in to_write[0]][0], [x.keys() for x in to_write[1]][0], "create_new_xml - large - common_ids")
    

    这将在不使用 diff_comm_checker() 的返回值的情况下给出错误行为

    这是因为 to_write 是一个生成器,而对 diff_comm_checker 的调用会耗尽该生成器。当在循环中的 if 语句中使用时,生成器然后完成/清空。您可以使用 list 从生成器创建列表:

    chunk_rec_ids_1 = list(get_chunks(xml_list[0], chunk))
    chunk_rec_ids_2 = list(get_chunks(xml_list[1], chunk))
    

    但这可能有其他含义(内存使用...)

    另外,diff_comm_checker 中这个构造的目的是什么?

        if not symm_diff:
           pass
    

    在我看来,无论 symm_diff 是否为 None,都不会发生任何事情。

    【讨论】:

    • 我排除了一些我认为不相关的代码 - 现在已将其放回原处。如果集合之间没有差异,我想跳过 difference() 函数。
    • 那么有什么方法可以利用diff_comm_checker 函数而不破坏to_write 的值吗?我将尝试在ids_records dict 旁边返回一个列表,但如果有更好的方法,请告诉我
    • to_write 是一个生成器,而不是一个列表。您对 diff_com_checker 的调用会耗尽生成器中的项目。当您稍后尝试再次使用生成器时,它是空的
    • 谢谢 - 我现在明白这个问题了。我已尝试按照您的建议生成列表,但在构建列表期间确实存在内存问题。我会寻找另一种方法来做到这一点。如果允许,我会在 2 小时内奖励赏金。
    猜你喜欢
    • 2012-01-05
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 2011-12-05
    • 2012-05-11
    • 2021-03-03
    • 1970-01-01
    • 2020-10-26
    相关资源
    最近更新 更多