python trick needed to convert dictionary of functions into dictionary of results
Question: I am currently blank on how to do this in an effective way.I thought about
using objects but I don't see how they could help in this case. Any ideas?

    
    
    from random import choice
    from copy import deepcopy
    
    
    def main():
    
        def rand_int():
            return choice(['yes', 'no'])
    
        # any nesting, functions possible
        spec = {
            'answer': rand_int,
            'next': {'answer': rand_int},
            'the_answer': 42
        }
    
        #### looking for elegant (automatic) way to do this
        result = deepcopy(spec)
        result['answer'] = result['answer']()
        result['next']['answer'] = result['next']['answer']()
        #### until here
    
        # result2 = ...
    
        print 'result: %s' % result
    
    
    if __name__ == '__main__':
        main()
    

please do not tell me to use xsd!


Answer: You can do this with one line in a [dictionary
comprehension](https://www.youtube.com/watch?v=t85uBptTDYY):

    
    
    {key: function() for key, function in mydictionary.items()}
    

Of course, this will throw errors when a value isn't a function, so if that is
a possibility, we can simply add a check with [the `callable()`
builtin](http://docs.python.org/library/functions.html#callable):

    
    
    {key: (function() if callable(function) else function) for key, function in mydictionary.items()}
    

We then need to deal with the fact that your answer needs to be recursive,
this makes it a little more complex, but not too hard to fix:

    
    
    def call_all_callables_in_dict(mapping):
        if hasattr(mapping, "items"):
            return {key: call_all_callables_in_dict(value) for key, value in mapping.items()}
        elif callable(mapping):
            return mapping()
        else:
            return mapping
    

Note that if you have objects with an `items` attribute or method you wish to
store in a `dict` this function will be run on, this could cause problems. I
would recommend changing the name of that attribute or method, or replacing
the check with `isinstance(dict)`.

I would also like to note that for misleading function names `rand_int` that
returns a string of `'yes'` or `'no'` is probably about as bad as it gets.
Generally you want `True`/`False` in those situations as well.

As noted in the comments, pre-Python 2.7, you may not have dictionary
comprehensions. To get around this, `dict()` will take a generator of tuples,
so you can replace a dict comprehension like so:

    
    
    {x: y for x, y in something.items()}
    

With:

    
    
    dict((x, y) for x, y in something.items())
    

* * *

So, in full:

    
    
    from random import choice
    
    def rand_int():
            return choice(['yes', 'no'])
    
    spec = {
        'answer': rand_int,
        'next': {'answer': rand_int},
        'the_answer': 42
    }
    
    def call_all_callables_in_dict(mapping):
        if hasattr(mapping, "items"):
            return {key: call_all_callables_in_dict(value) for key, value in mapping.items()}
        elif callable(mapping):
            return mapping()
        else:
            return mapping
    
    print(call_all_callables_in_dict(spec))
    

Gives us:

    
    
    {'answer': 'no', 'the_answer': 42, 'next': {'answer': 'yes'}}
    

