2015-11-05 45 views
0

我想修改一些基本的代碼來下載和解析SEC文件,但是有些事情在解析我發現完全令人困惑的頭文件。我不明白這是怎麼回事以下代碼的字典創建和頭分配:在Python中的字典分配和返回混淆

def download_filing(filing): 
    data=None 
    try: 
     data=open(filing).read() 
    except: 
     print 'Failed to get data...' 

    if data==None: return None 

    headers={} 

    docs=[] 
    docdata={} 
    intext=False 
    inheaders=False 
    headerstack=['','','','',''] 

    for line in data.split('\n'): 
     if line.strip()=='<DOCUMENT>': 
      # Beginning of a new document 
      docdata={'type':None,'sequence':-1,'filename':None,'description':None,'text':''} 
     elif line.strip()=='</DOCUMENT>': 
      # End of a documents 
      docs.append(docdata) 
     elif line.strip()=='<TEXT>': 
      # Text block 
      intext=True 
     elif line.strip()=='</TEXT>': 
      # End of the text block 
      intext=False 
     elif line.strip().startswith('<SEC-HEADER>'): 
      inheaders=True 
     elif line.strip().startswith('</SEC-HEADER>'): 
      inheaders=False 
     elif inheaders and line.strip()!='': 
      # Number of tabs before desc 
      level=line.find(line.strip()) 
      sline=line.strip().replace(':','',1) 

      # Find the dictionary level 
      curdict=headers 
      for i in range(level): 
       curdict=curdict[headerstack[i]] 

      # Determine if this is a field or a another level of fields 
      if sline.find('\t')!=-1: 
       curdict[sline.split('\t')[0]]=sline.split('\t')[-1] 
      else: 
       headerstack[level]=sline 
       curdict.setdefault(sline,{}) 

     elif intext: 
      docdata['text']+=line+'\n' 
     else: 
      # See if this is document metadata 
      for header in DOC_HEADERS: 
       if line.startswith(header): 
        field=DOC_HEADERS[header] 
        docdata[field]=line[len(header):] 

    return headers,docs 

的目標是通過美國證券交易委員會提交這樣解析:http://www.sec.gov/Archives/edgar/data/356213/0000898430-95-000806.txt

,並返回包含一個元組作爲「標題」的字典字典和「文檔」中的字典列表。它大部分對我來說很簡單。打開文件,逐行閱讀,並生成一些控制流程,告訴函數是否位於文檔的標題部分或文檔的文本部分。我也理解最後的列表創建算法,它將所有的「docdata」附加在一起。

然而,標題部分正在讓我大開眼界。我或多或少地理解標題解析器如何基於每個塊項目之前的標籤數量創建詞典巢,然後確定每個鍵的粘貼位置。我不明白的是它是如何填充到「標題」變量中的。它似乎是分配標題的結果,這似乎完全倒退給我。該程序將標題定義爲頂部的空白字典,然後對於每一行,賦值將這個空字典分配給結果,然後出現。然後它返回看起來再也沒有被正式操縱過的標題。

我猜,這我完全缺乏的對象分配Python中是如何工作的理解。我確定這真的很明顯,但我沒有看到用這種方式編寫的程序。

+0

看起來備案是XML。沒有可以使用的XML解析模塊而不是編寫自己的代碼? – Barmar

+0

這不是正式的XML。這是美國證券交易委員會在90年代初提出的一個非常古老的SGML規範。它完全抵制任何正式的XML/HTML解析器或像BeautifulSoup這樣的模糊解析器的解析。你基本上必須寫自己的。 – WildGunman

回答

1

headers是詞典的嵌套樹。指定給curdict的循環在該樹中下降到第N級,使用headerstack[i]作爲每個級別的關鍵字。它通過初始化curdict到頂層headers開始,然後在每次迭代時將其重置爲基於headerstack中下一項的子字典。

在Python中,與大多數面嚮對象語言一樣,對象分配是通過引用而不是通過複製來實現的。所以一旦完成curdict的最終分配,它就包含對其中一個嵌套字典的引用。然後,當它:

curdict[sline.split('\t')[0]]=sline.split('\t')[-1] 

它在字典元素,這仍然是完整的樹headers是指一部分罷了。

例如,如果headerstack包含['a', 'b', 'c', 'd']level = 3,則環路將設置curdict到一個參考headers['a']['b']['c']。如果slinefoo\tbar,上述分配隨後將等同於:

headers['a']['b']['c']['foo'] = 'bar'; 

我會告訴這是如何發生的,一步一步的。在循環的開始,我們有:

curdict == headers 

在循環的第一次迭代:

i = 1 
curdict = curdict[headerstack[i]] 

等同於:

curdict = headers['a'] 

在接下來的迭代:

i = 2 
curdict = curdict[headerstack[i]] 

相當於:

curdict = curdict['b'] 

這相當於:

curdict = headers['a']['b'] 

在下一(最終)環ieration:

i = 3 
curdict = curdict[headerstack[i]] 

這相當於:

curdict = curdict['c'] 

它是:

curdict = headers['a']['b']['c'] 

所以在這一點上,curdict相同字典,headers['a']['b']['c']一樣。你對curdict字典所做的任何事情也發生在headers的字典中。所以,當你這樣做:

curdict['foo'] = 'bar' 

這相當於做:

headers['a']['b']['c']['foo'] = 'bar' 
+0

我爲開始緻密道歉,但我仍然不太明白。 「結果」的分配,我完全理解。我不明白的是,每次讀取新行時,按引用分配的內容是如何填充「標題」的。 – WildGunman

+0

呃,有點。我瞭解'headers'的嵌套和字典的分配,但我仍不明白的是代碼中物理上發生了什麼。特別是爲什麼不在實際的任務中寫下'headers ['a'] ['b'] ['c'] ['foo'] ='bar''。代碼如何通過引用創建此分配?我相信這是最好的OO,而我只是沒有受過很好的教育而已。 – WildGunman

+0

它不會被寫入任何地方,因爲它使用變量'headerstack'和'level'動態地確定嵌套層次。 – Barmar