【问题标题】:Order of iteration through dict.items()通过 dict.items() 的迭代顺序
【发布时间】:2021-12-11 11:06:16
【问题描述】:

TLDR: 如果我在两个不同的时间从以相同方式处理的相同数据构建字典,dictionary.items() 的顺序是否应该每次都相同?

你好,

我有字典 linked_strain_acc,它有大约 2000 个键(菌株名称),每个键都有另一个字典作为值(data)。

linked_strain_acc = {'strain1' : {'gcf' : ['gcf1', 'gcf'..],
                                  'key2' : val2,
                                  .........},
                    'strain2' :  {.........},
                    ..........
                    'strain2000' :  {.........}}
          

我正在遍历每个 data 字典中的一个键 ('gcf'),其中包含 gcf id 的列表。我正在使用gcf ids 来构建一个用于抓取的 url,在测试它尚未被抓取之后。

directory = r'C:\Users\u03132tk\.spyder-py3\scrape_dsmz\zip_files'
count = 0
start = time.time()
#allows you to stop and start
current_files = os.listdir(directory)
for strain,data in linked_strain_acc.items():
    for gcf in data['gcf']:
        count+=1
        filename = f'{strain}__{gcf}.zip'
        if filename not in current_files:
            download_url = f'https://antismash-db.secondarymetabolites.org/output/{gcf}/{gcf}.zip'
            response = requests.get(download_url)
            with open(fr'{directory}\{filename}', "wb") as infile:
                infile.write(response.content)
            print (f'downloaded {strain}, {gcf}')
        else:
            print (f'{strain}, {gcf} already scraped')
        if count%50 == 0:
            print (f'downloaded {count} jsons - script has been running for {round((time.time() - start)/60, 1)} minutes')

问题

我已经抓取了大约 1500 个 gcf 网址并下载了这些文件(总共 2000 个)。今天早上我再次运行它时,前 1500 个打印语句没有打印“{strain}, {gcf} already scraped”,而是在几个“{strain}, {gcf} already scraped”打印消息和“下载 {strain}, {gcf}' 打印语句。这意味着linked_strain_acc 字典的顺序发生了变化。

我从一个 CSV 文件制作了这本字典,每次都以完全相同的方式处理该文件以制作 linked_strain_acc。为什么 dict 的顺序会改变,或者我错过了什么?我知道 dict key/val order 不是按例如排序的。字母或大小,但我认为当它由完全相同的数据构建时会被维护。

谢谢!

【问题讨论】:

  • 您使用的是哪个版本的 Python?字典在 3.7 之后按插入顺序排列。
  • 嗨,谢谢您的回复 - 我是 3.7,插入顺序是什么意思?
  • 您确定您的网址正确吗?例如。 {gcf}/{gcf} 在下载结束时其他字符串似乎都是 {strain} {gcf}。项目的 Python 字典顺序现在已针对多个版本进行了修复;在构建 URL 或重建 CSV 或将 os.listdir() 用于其他具有任意顺序的东西时,手动抓取网页似乎更有可能产生问题。
  • 嗨,kcsquared,我很确定 - 我正在使用具有“...../gcf/gcf”选项的“下载文件”选项从在线数据库中抓取它们.zip' 网址格式。我从同一个数据库输出的查询结果摘要 csv 文件中获取 gcfs 本身,并且我的所有文件似乎都下载得很好(因为我有 1500 个文件,并且手动检查了几个看起来还不错)。令人困惑的是,在这些情况下甚至不应该启动网络抓取 - 目录中文件的存在应该阻止它启动(并且 os.listdir() 的顺序不应该影响存在测试)。
  • 另外,我没有重建 csv,它总是从同一个文件中工作并以相同的方式处理它(我只是重新运行相同的脚本,所以没有任何变化 - 它只是检查它已经找到了)。

标签: python python-3.x dictionary


【解决方案1】:

在旧版本中,python 使用字符串池通过池化较短的公共段来有效地存储较长的字符串。每次创建字符串时,它都可能更改池,从而更改顺序。您在其中动态创建的字符串

download_url = f'https://antismash-db.secondarymetabolites.org/output/{gcf}/{gcf}.zip'

可能会根据您的起点更改池。供参考:https://en.wikipedia.org/wiki/String_interning

【讨论】:

  • 嗨 Oguzkhan,谢谢你的有趣想法——我必须在谷歌上搜索一下关于池的信息,但从未听说过。但是,这肯定不是问题,因为 gcf 是在 f 字符串之前定义的?并且 f 字符串不能确定 dict 的迭代顺序?
  • 仍然可以更改顺序。我不确定是否有办法可视化/调试实习池。我很高兴能够提供帮助!
猜你喜欢
  • 2021-03-27
  • 2018-07-14
  • 1970-01-01
  • 2017-01-12
  • 2016-01-18
  • 2012-12-28
  • 2011-02-11
  • 2012-10-31
  • 1970-01-01
相关资源
最近更新 更多