2015-11-05 1 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» вместе.

Однако часть заголовков дует мне в голову. Я более или менее понимаю, как анализатор заголовков пытается создать гнезда словарей на основе количества вкладок перед каждым элементом блока, а затем определить, где хранить каждую клавишу. Я не понимаю, как это заполняет эту переменную. Похоже, что он назначает заголовки для курения, которые кажутся мне полностью обратными. Программа определяет заголовки как пустой dict вверху, затем для каждой строки назначает присваивает этот пустой словарь curdict, а затем выходит вперед. Затем он возвращает заголовки, которые, как представляется, никогда не были формально манипулированы снова.

Я предполагаю, что это мое полное отсутствие понимания того, как назначение объектов работает на Python. Я уверен, что это действительно очевидно, но я недостаточно продвинутый, чтобы увидеть программы, написанные таким образом.

+0

Похоже, что подача является XML. Разве нет XML-синтаксического анализа, который вы могли бы использовать вместо написания собственного кода? – Barmar

+0

Это не формальный XML. Это очень старая спецификация SGML, которую SEC предложила в начале 90-х годов. Он полностью противостоит любой попытке формальных парсеров XML/HTML или нечетких, таких как BeautifulSoup, для его анализа. Вы, по сути, должны написать свое. – WildGunman

ответ

1

headers - это вложенное дерево словарей. Цикл, который назначает curdict, переходит на уровень N в этом дереве, используя headerstack[i] в качестве ключа для каждого уровня. Он начинается с инициализации curdict до верхнего уровня headers, затем на каждой итерации он сбрасывает его на дочерний словарь на основе следующего элемента в headerstack.

В Python, как и в большинстве языков OO, назначение объекта осуществляется по ссылке, а не путем копирования. Итак, как только окончательное назначение curdict сделано, оно содержит ссылку на один из вложенных словарей. Затем, когда он делает:

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

он заполняет этот элемент словаря, который до сих пор является частью полного дерева, которое headers ссылается.

Например, если headerstack содержит ['a', 'b', 'c', 'd'] и level = 3, то цикл будет установлен curdict к ссылке на headers['a']['b']['c']. Если sline является foo\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

Я извиняюсь за начало плотной, но я до сих пор не совсем понял. Назначение «curdict», я полностью понимаю. То, что я не понимаю, - это то, как присвоение по ссылке заполняет «заголовки» каждый раз, когда считывается новая строка. – WildGunman

+0

Ну, вроде. Я понимаю вложение «заголовков» и назначение словаря, что я до сих пор не понимаю, так это то, как это физически происходит внутри кода. В частности, почему нет фактического присвоения 'headers ['a'] ['b'] ['c'] ['foo'] = 'bar'', написанного где угодно. Как код создает это назначение через ссылку? Я уверен, что это OO в лучшем виде, и я недостаточно образован, чтобы получить его. – WildGunman

+0

Он не написан нигде, потому что он динамически определяет уровень вложенности, используя переменные 'headerstack' и' level'. – Barmar

Смежные вопросы