2015-11-05 38 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