Половина записей теряется при итерации по списку JSON

#python #json #iterator

#python #json #итератор

Вопрос:

 [{"attributes": {"type": "Silo__c", "url": "/services/data/v38.0/sobjects/Silo__c/b0L36000007xRItEAM"}, "Id": "a0M36000007xRItEAM", "OwnerId": "00536000002yKlTAAU", "IsDeleted": false, "Name": "Fresh", "Landing_Stop_Date__c": null, "Service_Exit_Date__c": null},{"attributes": {"type": "Silo__c", "url": "/services/data/v38.0/sobjects/Silo__c/b0L36000007xRItEAM"}, "Id": "a0M36000007xRItEAM", "OwnerId": "00536000002yKlTAAU", "IsDeleted": false, "Name": "Fresh", "Landing_Stop_Date__c": null, "Service_Exit_Date__c": null},{"attributes": {"type": "Silo__c", "url": "/services/data/v38.0/sobjects/Silo__c/b0L36000007xRItEAM"}, "Id": "a0M36000007xRItEAM", "OwnerId": "00536000002yKlTAAU", "IsDeleted": false, "Name": "Fresh", "Landing_Stop_Date__c": null, "Service_Exit_Date__c": null},{"attributes": {"type": "Silo__c", "url": "/services/data/v38.0/sobjects/Silo__c/b0L36000007xRItEAM"}, "Id": "a0M36000007xRItEAM", "OwnerId": "00536000002yKlTAAU", "IsDeleted": false, "Name": "Fresh", "Landing_Stop_Date__c": null, "Service_Exit_Date__c": null},{"attributes": {"type": "Silo__c", "url": "/services/data/v38.0/sobjects/Silo__c/b0L36000007xRItEAM"}, "Id": "a0M36000007xRItEAM", "OwnerId": "00536000002yKlTAAU", "IsDeleted": false, "Name": "Fresh", "Landing_Stop_Date__c": null, "Service_Exit_Date__c": null}]
  

Приведенное выше очень похоже на JSON, который я получаю из запроса из simple salesforce.

Предполагается, что приведенное ниже превращает его в jsonl, а также исправляет проблемы с датой и временем.

Проблема в том, что мне нужно избавиться от раздела атрибутов, поскольку он не используется. приведенный ниже код является последней попыткой, но все, что приводит к одной и той же записи снова и снова. (приведенные выше данные повторяются, поэтому я бы ожидал, что они будут такими же, если вы их прогоните)

 for element in data :

        item = data.pop()
        item.pop('attributes', None)

        tempdict = OrderedDict({})
        for k,v in item.items() :
            if 'date' in k.lower() or 'stamp' in k.lower() :
                if not v is None :
                    d = d_parse(v)
                    v = d.strftime('%Y-%m-%d %I:%M:%S')
                    tempdict[k.lower()] = v
            else :
                tempdict[k.lower()] = v

        with open(localFilePath fileName.format(nextObj,fileCount), 'a') as outfile :
            outfile.write(json.dumps(tempdict))
            outfile.write('n')
  

Проблема в том, что по какой-то причине теряется 1/2 записей. Я получаю только 384 из 767 записей в файл. Я подозреваю, что проблема связана с pop и где это происходит в коде. Как я могу избавиться от раздела атрибутов, не потеряв 1/2 записей в pop?

Редактировать:

Следующий код выдает ошибку (на основе комментария):

 for element in data :
data.pop('attributes', None)

tempdict = OrderedDict({})
for k,v in data.items() :
    if 'date' in k.lower() or 'stamp' in k.lower() :
        if not v is None :
            d = d_parse(v)
            v = d.strftime('%Y-%m-%d %I:%M:%S')
            tempdict[k.lower()] = v
    else :
        tempdict[k.lower()] = v

with open(localFilePath fileName.format(nextObj,fileCount), 'a') as outfile :
    outfile.write(json.dumps(tempdict))
    outfile.write('n')


Traceback (most recent call last):
  File "child_sfdc_etl.py", line 417, in <module>
    sfToS3(fileCount, sf, nextObj)
  File "child_sfdc_etl.py", line 206, in sfToS3
    send_temp_jsonl_to_s3(data, nextObj, s3, s3Destination, fileCount, s3Path)
  File "child_sfdc_etl.py", line 254, in send_temp_jsonl_to_s3
    data.pop('attributes', None)
TypeError: pop() takes at most 1 argument (2 given)
  

Код без None также выдает ошибку:

 for element in data :
data.pop('attributes')

tempdict = OrderedDict({})
for k,v in data.items() :
    if 'date' in k.lower() or 'stamp' in k.lower() :
        if not v is None :
            d = d_parse(v)
            v = d.strftime('%Y-%m-%d %I:%M:%S')
            tempdict[k.lower()] = v
    else :
        tempdict[k.lower()] = v

with open(localFilePath fileName.format(nextObj,fileCount), 'a') as outfile :
    outfile.write(json.dumps(tempdict))
    outfile.write('n')

Traceback (most recent call last):
  File "child_sfdc_etl.py", line 417, in <module>
    sfToS3(fileCount, sf, nextObj)
  File "child_sfdc_etl.py", line 206, in sfToS3
    send_temp_jsonl_to_s3(data, nextObj, s3, s3Destination, fileCount, s3Path)
  File "child_sfdc_etl.py", line 254, in send_temp_jsonl_to_s3
    data.pop('attributes')
TypeError: 'str' object cannot be interpreted as an integer
  

Комментарии:

1. Зачем вы item = data.pop() вообще это делаете? Я думаю, проблема в том, что вы изменяете коллекцию, которую повторяете, во время итерации по ней. Я бы просто удалил первый всплывающий вызов.

2. Если я попробую data.pop(‘attributes’, None), он выдает ошибку. Обратная трассировка опубликована в edit.

3. Вы перебираете вызываемую коллекцию data , для которой на каждый элемент ссылается переменная element , объявленная вами в цикле for , поэтому вам нужно сделать element.pop() , а не data.pop() .

Ответ №1:

Это связано с тем, как итерация реализована в Python. Как указывали другие, виновником является

 for element in data :
    item = data.pop()
    <...>
  

Итератор последовательности в Python сохраняет индекс текущего элемента, чтобы определить, что возвращать следующим (в общем случае невозможно корректно выполнить итерацию по последовательности, если она изменяется в процессе, так что это не ошибка).

Вы берете один элемент (начиная с начала списка) как element . Затем вы берете и удаляете последний элемент в списке как item и полностью игнорируете element . Следующая итерация element будет элементом после предыдущей element . И так далее. Как следствие, вы будете обрабатывать только вторую половину исходного списка в обратном порядке.


Удалите data.pop() и используйте element .

Комментарии:

1. Спасибо вам обоим; Я ценю урок.