CPak
CPak

Reputation: 13581

Recursive sub-generator call does not execute

Python 3.6+ btw

From a nested dictionary, I want to print a parent-value if a child-value matches a string. To do this, I tried this recursive call

for child in traverse_dict(value, 'ready', 'y'):
    print(child)

That is, when the parent-key is found, I want to (recursively) check whether any of its child-values (and child-keys) match the respective string patterns, and if yes, print. (I would collect the values eventually)

Using the same call but outside the function works as intended (try last 2 lines of example code or see below).

for i in traverse_dict(ex, 'ready', 'y'):
    print(i)
# Output is 
# Y

But when I try

for i in traverse_dict(ex, 'id'):
    print(i)
# Output is
# checkpoint
# A
# checkpoint
# B

But I expect

# Output is
# checkpoint
# Y             <= (missing this, output of traverse_dict(ex, 'ready', 'y'))
# A
# checkpoint
# B

Any idea why it FAILS when called inside the function?

See this example

ex = [
    {
        'Id': 'A',
        'Status': { 'Ready': 'Y' }
    },
    {
        'Id': 'B',
        'Status': { 'Ready': 'N' }
    }
]

def traverse_dict(
    data,
    *args
):
    if isinstance(data, dict):
        for key, value in data.items():
            # FOR SUB-GENERATOR WHERE *ARGS IS PASSED 2 ARGS
            try:
                if key.lower() == args[0] and value.lower() == args[1]:
                    yield value
                else:
                    yield from traverse_dict(value, *args)
            except:
                if key.lower() == args[0]:
                    print('checkpoint')
                    for child in traverse_dict(value, 'ready', 'y'):
                        print(child)
                    yield value
                else:
                    yield from traverse_dict(value, *args)
    elif isinstance(data, list):
        for item in data:
            yield from traverse_dict(item, *args)


for i in traverse_dict(ex, 'id'):
    print(i)


for i in traverse_dict(ex, 'ready', 'y'):
    print(i)

Thanks in advance!

Upvotes: 3

Views: 36

Answers (1)

milanbalazs
milanbalazs

Reputation: 5329

You have passed wrong data in for child in traverse_dict(value, 'ready', 'y'):... line. In your case the value contains "A" because the key.lower() == args[0] statement is True when the key is Id and the value is A or B. You should pass the 'Status' member of the current dict.

It means the correct line: for child in traverse_dict(data['Status'], 'ready', 'y'):

Output with this line:

>>> python3 test.py
checkpoint
Y
A
checkpoint
B
Y

Upvotes: 2

Related Questions