2

I have a python object that looks like this. I am trying to parse this object and turn it to a human readable string which I need to put in the logs. How can I recursively loop through this considering the object could be nested dictionaries or nested lists or dictionaries inside lists inside dictionaries etc.

{"plugins": 
  [
    {"Chrome PDF Viewer": "mhjfbmdgcfjbbpaeojofohoefgiehjai"}, 
    {"Chrome PDF Viewer": "internal-pdf-viewer"}, 
    {"Native Client": "internal-nacl-plugin"}, 
    {"Shockwave Flash": "PepperFlashPlayer.plugin"}, 
    {"Widevine Content Decryption Module": "widevinecdmadapter.plugin"}
  ]
}

I want to possibly serialize the above to look something like this

"plugins: 
     Chrome PDF Viewer": "mhjfbmdgcfjbbpaeojofohoefgiehjai, 
     Chrome PDF Viewer": "internal-pdf-viewer, 
     Native Client": "internal-nacl-plugin, 
     Shockwave Flash": "PepperFlashPlayer.plugin, 
     Widevine Content Decryption Module": "widevinecdmadapter.plugin"

My code so far [this works for nested dictionaries but I am not sure how I can alter this to support lists in the above object]:

result_str = ""

def dictionary_iterator(results):
    global result_str
    for key, value in results.items():
        if isinstance(value, dict):
            result_str = result_str + key + ": \n \t"
            dictionary_iterator(value)
        else:
            result_str = result_str + key + ": " + str(value) + "\n"

    return result_str

I have looked over possible answers but could not find a solution.

14
  • The json library can do this for you: docs.python.org/2/library/json.html Commented Jul 18, 2017 at 20:50
  • Thanks for the suggestion but I don't want to use that cause I want to do additional things that json library wont let me. Commented Jul 18, 2017 at 20:53
  • 1
    Could you please fix indentation. Also please describe what do you want to iterate over. When you say "I am trying to parse this object and turn it to a human readable string..." it is not clear what are you trying to parse and how do you want parsed information to be assembled into a string. Is there anything wrong with your code? Does it work as expected but you would like to improve it? Commented Jul 18, 2017 at 20:54
  • Why do you need global result_str inside this function? You are explicitly returning it! Commented Jul 18, 2017 at 20:57
  • @smriti, post the desired result Commented Jul 18, 2017 at 20:58

3 Answers 3

2

The formatting might be a bit off

def humanizer(input, result=''):
    if type(input) == dict:
        for k, v in input.items():
            if type(v) == str:
                result += '%s:%s\n\t' % (str(k), str(v))
            elif type(v) in (dict, list):
                result += '%s:\n\t' % str(k)
                result = humanizer(v, result)
                result += '\n\t'
    elif type(input) == list:
        for item in input:
            if type(item) == str:
                result += item
                continue
            result = humanizer(item, result) + '\n\t'
    else:
        result += input + '\n\t'
    return result

Result:

plugins:
        Chrome PDF Viewer:mhjfbmdgcfjbbpaeojofohoefgiehjai

        Chrome PDF Viewer:internal-pdf-viewer

        Native Client:internal-nacl-plugin

        Shockwave Flash:PepperFlashPlayer.plugin

        Widevine Content Decryption Module:widevinecdmadapter.plugin
Sign up to request clarification or add additional context in comments.

1 Comment

You could also use isinstance to validate the type.
2

Maybe the output of pformat would suit you:

from pprint import pformat
results_str = pformat(results)

2 Comments

this wouldn't indent the serialized object though, correct?
It does indent nested structures
1

You need an elif-condition in case of type == list and a indentation tracker:

data = {"plugins": 
  [
    {"Chrome PDF Viewer": "mhjfbmdgcfjbbpaeojofohoefgiehjai"}, 
    {"Chrome PDF Viewer": "internal-pdf-viewer"}, 
    {"Native Client": "internal-nacl-plugin"}, 
    {"Shockwave Flash": "PepperFlashPlayer.plugin"}, 
    {"Widevine Content Decryption Module": "widevinecdmadapter.plugin"}
  ],
  "anotherLevel":
    {
        "sublevel": [
            {'item1': 'value1'}
        ]
    }
}

result_str = ""
def dictionary_iterator(indent, data):
    global result_str

    if isinstance(data, dict):
        for key, value in data.items():
            result_str += indent*'\t' + key + '\n'
            indent = indent + 1
            dictionary_iterator(indent, value)

    elif isinstance(data, list):
        for item in data:
            if isinstance(item, dict) and len(list(item.keys())) == 1:
                key = list(item.keys())[0]
                value = item[key]
                result_str += indent*'\t' + key + ': ' + value + '\n'
            else:
                indent = indent + 1
                dictionary_iterator(indent, item)
    return result_str


if __name__ == '__main__':
    print(dictionary_iterator(0, data))

That will print out:

plugins
    Chrome PDF Viewer: mhjfbmdgcfjbbpaeojofohoefgiehjai
    Chrome PDF Viewer: internal-pdf-viewer
    Native Client: internal-nacl-plugin
    Shockwave Flash: PepperFlashPlayer.plugin
    Widevine Content Decryption Module: widevinecdmadapter.plugin
    anotherLevel
        sublevel
            item1: value1

1 Comment

Why do you need a global var if you return it anyway? Global varaibles are a code smell.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.