Use generator
With the following generator:
def get_stuff(dct, iter_keys, get_keys): k, stuff = get_keys l, m = iter_keys if k in dct: yield {k: dct[k], stuff: dct[stuff]} if dct.get(l): for subdct in dct[l][m]: for res in get_stuff(subdct, iter_keys, get_keys): yield res list(get_stuff(d, ["l", "m"], ["k", "stuff"]))
you get the results:
list(get_stuff(d))
Python 3.3 provides a new yield from expression used to delegate assignment to a subgenerator. Using this expression, the code can be one line shorter:
def get_stuff(dct): if "k" in dct: yield {"k": dct["k"], "stuff": dct["stuff"]} if dct.get("l"): for subdct in dct["l"]["m"]: yield from get_stuff(subdct) def get_stuff(dct, iter_keys, get_keys): k, stuff = get_keys l, m = iter_keys if k in dct: yield {k: dct[k], stuff: dct[stuff]} if dct.get(l): for subdct in dct[l][m]: yield from get_stuff(subdct, iter_keys, get_keys):
Some methods to avoid globals
generators
Often, if you need to create a list and look for a replacement for global variables, generators can come in handy, because they save the status of the current work in its local variables, and the creation of the whole result is delayed by the consumption of the generated values.
recursion
Recursion stores subselects in local variables on the stack.
class instance with internal property
A class can serve as a tin to encapsulate your variables.
Instead of using a global variable, you store the intermediate result in the instance property.
Generalization for different data structures
In your comments, you mentioned that you get many different types with each dump.
I will assume that your data meets the following expectations:
- has a tree structure
- each node in the tree should contribute to the result (for example, the dictionary
{"k": xx, "stuff": yy} ) - each node may contain subitems (list of trays)
One way to make the solution more general is to provide a list of keys to use to access the value / subitems; another option is to provide a function that does the job of getting the value and subitems of the node.
Here I use get_value to deliver the node value and get_subitems to deliver the trays:
def get_value(data): try: return {"k": data["k"], "stuff": data["stuff"]} except KeyError: return None def get_subitems(data): try: return data["l"]["m"] except TypeError: return None
Processing is performed as follows:
def get_stuff(dct, get_value_fun, get_subitems_fun): value = get_value(dct) if value: yield value lst = get_subitems_fun(dct) if lst: for subdct in lst: for res in get_stuff(subdct, get_value_fun, get_subitems_fun): yield res
called this way:
get_stuff(d, get_value, get_subitems)
The advantage of using functions is that it is much more flexible for any data structure that you would have to process (adaptation to other data structures will only require providing a custom version of the get_value and get_subitems - with the same or different names according to your preferences.