0

I've a flat dict with entities. Each entity can have a parent. I'd like to recursively build each entity, considering the parent values.

Logic:

  1. Each entity inherits defaults from its parent (e.g. is_mammal)
  2. Each entity can overwrite the defaults of its parent (e.g. age)
  3. Each entity can add new attributes (e.g. hobby)

I'm struggling to get it done. Help is appreciated, thanks!

entities = {
    'human': {
        'is_mammal': True,
        'age': None,
    },
    'man': {
        'parent': 'human', 
        'gender': 'male',
    },
    'john': {
        'parent': 'man',
        'age': 20,
        'hobby': 'football',
    }
};

def get_character(key):
    # ... recursive magic with entities ...
    return entity
    
john = get_character('john')
print(john)

Expected output:

{
    'is_mammal': True,  # inherited from human
    'gender': 'male'  # inherited from man
    'parent': 'man', 
    'age': 20, # overwritten
    'hobby': 'football', # added
}
Mr. B.
  • 8,041
  • 14
  • 67
  • 117
  • Can entity have more than 1 parent? Can you have more than 2 levels of dictionaries? – matszwecja Nov 03 '22 at 12:50
  • @matszwecja each entity has one parent but the parent can have another parent: john -> man (parent) -> human (grand-parent). Yes, it can be infinite levels. It must be recursive. Thanks for your help. – Mr. B. Nov 03 '22 at 12:53
  • I would recommend you to add input with multiple person. – R. Baraiya Nov 03 '22 at 12:58
  • "Yes, it can be infinite levels": Can you clarify if you mean: 1. infinite? 2. any number, but finite? 3. Any finite small number (within default stack depth) – Lesiak Nov 03 '22 at 13:02
  • 1
    @Lesiak: realistically max. 10. Mostly 2-3. – Mr. B. Nov 03 '22 at 13:04
  • I was mostly asking about if "parent" can contain a dict itself instead of another key. – matszwecja Nov 03 '22 at 13:06

2 Answers2

2
def get_character(entities, key):
    try:
        entity = get_character(entities, entities[key]['parent'])
    except KeyError:
        entity = {}
    entity.update(entities[key])
    return entity
matszwecja
  • 6,357
  • 2
  • 10
  • 17
1

This solution is using recursion and a Python quirk where mutables (here it's a dictionary {}), are shared among function calls. See the discussion below for why this is somewhat surprising, though useful for accumulating recursion results.

def get_character(d, key, entity = {}):
    if d.get(key) is None:
        return entity
    return get_character(d, d.get(key).get('parent'), d.get(key) | entity)

get_character(entities, 'john')

{'is_mammal': True,
 'age': 20,
 'parent': 'man',
 'gender': 'male',
 'hobby': 'football'}
Nathan Furnal
  • 2,236
  • 3
  • 12
  • 25