1

I am trying to list all keys with parent keys from a dictionary using python 3. How can I achieve this goal?

Here is so far I did using a recursive function (so that I can use this with any depth of dictionaries).

Here, if I do not use header_prefix, I get all the keys without parent keys. However, when I use header_prefix, it keeps adding parent keys incorrectly to the keys. Basically, I cannot reset header_prefix in the appropriate location.

from pprint import pprint
#%%

data = {
  "AWSTemplateFormatVersion": "2010-09-09" ,
  "Description": "Stack for MyProject 01",
  "Resources": {
    "elb01": {
      "Type": "AWS::ElasticLoadBalancing::LoadBalancer",
      "Properties": {
        "CrossZone" : "false",
        "HealthCheck" : {
          "Target" : "TCP:80",
          "Interval" : "20"
        },
        "ConnectionSettings": {
          "IdleTimeout": "120"
        }
      }
    },
    "lc01": {
      "Type": "AWS::AutoScaling::LaunchConfiguration" ,
      "Properties": {
        "ImageId" : "ami-01010105" ,
        "InstanceType" : "t2.medium" 
      }
    },
    "asg01": {
      "Type" : "AWS::AutoScaling::AutoScalingGroup",
      "Properties" : {
        "HealthCheckGracePeriod" : 300,
        "HealthCheckType" : "EC2"
      }
    }
  }
}
pprint(data)

#%%

def get_headers(json_data, headers, header_prefix):
    for key, value in json_data.items():
        if type(value) == dict:
            header_prefix = header_prefix + key + '.'
            get_headers(value,headers,header_prefix)
        else:
            headers.append(header_prefix+key)
    
    return(headers)
#%%
header_list = []
prefix = ''
data_headers = get_headers(data, header_list, prefix)

pprint(data_headers)

From the above code, I get the following output:

['AWSTemplateFormatVersion',
 'Description',
 'Resources.elb01.Type',
 'Resources.elb01.Properties.CrossZone',
 'Resources.elb01.Properties.HealthCheck.Target',
 'Resources.elb01.Properties.HealthCheck.Interval',
 'Resources.elb01.Properties.HealthCheck.ConnectionSettings.IdleTimeout',
 'Resources.elb01.lc01.Type',
 'Resources.elb01.lc01.Properties.ImageId',
 'Resources.elb01.lc01.Properties.InstanceType',
 'Resources.elb01.lc01.asg01.Type',
 'Resources.elb01.lc01.asg01.Properties.HealthCheckGracePeriod',
 'Resources.elb01.lc01.asg01.Properties.HealthCheckType']

My expected output is like below:

 ['AWSTemplateFormatVersion',
 'Description',
 'Resources.elb01.Type',
 'Resources.elb01.Properties.CrossZone',
 'Resources.elb01.Properties.HealthCheck.Target',
 'Resources.elb01.Properties.HealthCheck.Interval',
 'Resources.elb01.Properties.ConnectionSettings.IdleTimeout',
 'Resources.lc01.Type',
 'Resources.lc01.Properties.ImageId',
 'Resources.lc01.Properties.InstanceType',
 'Resources.asg01.Type',
 'Resources.asg01.Properties.HealthCheckGracePeriod',
 'Resources.asg01.Properties.HealthCheckType']

1 Answer 1

2

It seems to be a scoping issue. When you modify header_prefix inside the if statement, it modifies it in the function scope and so for all iterations of the loop, leading to the incorrect version being passed to get_headers in later iterations of the loop

In short:

Change

header_prefix = header_prefix + key + '.'
get_headers(value,headers,header_prefix)

To

pfx = header_prefix + key + '.'
get_headers(value,headers,pfx)

This way a new local variable will be created and passed, rather than the header_prefix being updated within the function scope.

(any variable name that's not used within the get_headers function will do

Sign up to request clarification or add additional context in comments.

2 Comments

Works. Great! Thanks. My confusion using local variable other than header_prefix was that how it would update be updated. I can see now that whenever get_headers is called with the local variable (pfx), header_prefix is updated.
Glad it helped. Technically every time you call that function it creates a new stack frame, and a new header_prefix variable is created with the value of whatever was passed into the function

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.