2012-12-07 82 views
5

我對編程相當陌生,並且製作了一個程序從Team Fortress 2玩家獲取庫存數據,並將庫存物品放入字典中,其中steamid作爲關鍵字,項目列表作爲值。Python字典吃掉內存

我遇到的問題是,大約6000條輸入字典後,程序已經吸收了我係統上基本上所有的RAM並關閉。

我猜字典變得太大了,但是根據我從類似的問題中讀到的6000個條目的字典不應該佔用我的RAM大部分。

我一直在尋找其他解決方案,但我可以爲我的代碼使用一些具體的例子。

import re, urllib.request, urllib.error, gzip, io, json, socket, sys 

with open("index_to_name.json", "r", encoding=("utf-8")) as fp: 
    index_to_name=json.load(fp) 

with open("index_to_quality.json", "r", encoding=("utf-8")) as fp: 
    index_to_quality=json.load(fp) 

with open("index_to_name_no_the.json", "r", encoding=("utf-8")) as fp: 
    index_to_name_no_the=json.load(fp) 

with open("steamprofiler.json", "r", encoding=("utf-8")) as fp: 
    steamprofiler=json.load(fp) 

inventory=dict() 
playerinventories=dict() 
c=0 

for steamid in steamprofiler: 
    emptyitems=[] 
    items=emptyitems 
    try: 
     url=urllib.request.urlopen("http://api.steampowered.com/IEconItems_440/GetPlayerItems/v0001/?key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&steamid="+steamid+"&format=json") 
     inv=json.loads(url.read().decode("utf-8")) 
     url.close() 
    except (urllib.error.HTTPError, urllib.error.URLError, socket.error) as e: 
     c+=1 
     print("URL/HTTP error, continuing") 
     continue 
    try: 
     for r in inv["result"]["items"]: 
      inventory[r["id"]]=r["quality"], r["defindex"] 
    except KeyError: 
     c+=1 
     print(steamid, "didn't have an inventory") 
     continue 
    for key in inventory: 
     try: 
      if index_to_quality[str(inventory[key][0])]=="": 
       items.append(
        index_to_quality[str(inventory[key][0])] 
        +""+ 
        index_to_name[str(inventory[key][1])] 
        ) 
      else: 
       items.append(
        index_to_quality[str(inventory[key][0])] 
        +" "+ 
        index_to_name_no_the[str(inventory[key][1])] 
        ) 
     except KeyError: 
      print("Key error, uppdate def_to_index") 
      c+=1 
      continue 
playerinventories[int(steamid)]=items 
items=emptyitems 
c+=1 
print(c, "inventories fetched") 

我真的不知道任何其他方式做到這一點,同時保留字典appearence,這是因爲我希望能告訴他們的庫存還是比較重要的。如果我在任何的這個不清楚,只是這麼說,我會盡力解釋

回答

4

我認爲你的代碼有一些邏輯錯誤。例如,您將每個玩家的庫存項添加到inventory字典中,然後遍歷它以填充其他內容。

但是,你永遠不會重置inventory字典,因此它會繼續積累物品(所以除了他們自己之外,第二個玩家似乎擁有第一人的庫存)。

你有類似的問題,你稍後會用到的items字典。您將其重置爲emptyitems,它最初是一個空列表,但因爲Python中的賦值是通過引用的方式進行的,所以這不起作用(itemsemptyitems已經是同一個對象)。

有了這兩個修復程序,您可能會有更好的機會不使用所有系統的內存。

另一個雜項改進代碼(可能不相關的內存使用情況):

在你遍歷inventory,你重複訪問相同的兩個值,而不是使用key任何東西。而不是for key in inventory嘗試for value1, value2 in inventory.itervalues()(或in inventory.values(),如果您使用的是Python 3)。然後用value1代替inventory[key][0]value2代替inventory[key][1](或者更好,給他們更有意義的名字)。

編輯:這裏的循環會如何看(我在的是,在inventory[key][0]以前兩個值和inventory[key][1]名稱排序的猜測):

for quality, name in inventory.itervalues(): 
    try: 
     if index_to_quality[str(quality)]=="": 
      items.append(
       index_to_quality[str(quality)] 
       +""+ 
       index_to_name[str(name)] 
       ) 
     else: 
      items.append(
       index_to_quality[str(quality)] 
       +" "+ 
       index_to_name_no_the[str(name)] 
       ) 
+0

因此,加入:「0121」一定程度上?我不太瞭解庫存循環的問題,庫存中的關鍵值與index_to_name和index_to_quality中的名稱相對應,您的解決方案如何做得更好?我不會在這裏說話,我真的很好奇,因爲我很新。 – Tenbin

+0

關於庫存循環,我只是在訪問'inventory [key] [0]'和'inventory [key] [0]'而不訪問其他地方的'key'時有點奇怪。如果這些是你需要使用的值(用於索引你的其他字典),我建議你直接循環迭代它們。如果'inventory [key]'是一個兩元組元組或列表,可以在'for'語句中將其解壓縮爲兩個變量。我會編輯我的答案,以顯示如何看起來,適當的縮進。 – Blckknght

1

我認爲這說明了你的代碼有問題:

>>> emptyitems=[] 
>>> a=emptyitems 
>>> a.append("hello") 
>>> a.append("bar") 
>>> a 
['hello', 'bar'] 
>>> emptyitems 
['hello', 'bar'] 

換句話說,你捕捉對emptyitems列表的引用,其實際上將繼續增長非常大。這可能不是你的意思,我可以想象它變得相當記憶強烈,以處理一個非常大的名單。

+0

想我固定,通過添加項目=在steamprofiler循環中爲蒸汽開始的列表(),乾杯 – Tenbin