How can I process a python dictionary with callables? - python

I would like to create a python directory whose values are to be evaluated separately.
So, for example, in the following non-working example I define
a = {'key1': 'value1', 'key2': 42, 'key3': foo(20)}
for which e.g.
def foo(max):
"""Returns random float between 0 and max."""
return max*random.random()
and after processing of the dict I want to have e.g.
a_processes = {'key1': 'value1', 'key2': 42, 'key3': 12.238746374}
The example does not work since the value of key key3 is immediately evaluated, and foo(20) is no callable. The way it could work would be to use something like
a = {'key1': 'value1', 'key2': 42, 'key3': foo}
but here foo will miss its arguments. One way to handle this would be to define the dict in the following way
a = {'key1': 'value1', 'key2': 42, 'key3': [foo, 20]}
with the following processing scheme
a_processed = dict([k,process(v)] for k,v in a.items())
in which process is a meaningful function checking if its argument is a list, or if the first element is a callable which gets called with the remaining arguments.
My question is about a better way/idea to implement my basic idea?

Use the functools.partial() to create a callable that'll apply a set of arguments to another callable:
from functools import partial
a = {'key1': 'value1', 'key2': 42, 'key3': partial(foo, 20)}
Now the key3 value is a callable object; a['key3']() will in turn call foo(20) and return the result.
You'd still need to 'process' this dictionary (testing with the callable() function:
{k: v() if callable(v) else v for k, v in a.iteritems()}
of course. If you are using Python 3, use a.items() instead.
A functools.partial setup let's you add additional arguments as needed (provided foo() supports them):
a['key3']('additional', arguments='accepted')
You could even create a dictionary subclass that does this automatically when accessing a key:
def CallablesDict(dict):
def __getitem__(self, key):
value = super(CallablesDict, self).__getitem__(key)
return value() if callable(value) else value
then define a as:
a = CallablesDict({'key1': 'value1', 'key2': 42, 'key3': partial(foo, 20)})
print a['key3'] # calls foo(20)

I often use an argument-free lambda here, just because I like the syntax:
>>> def foo(x):
... return x*100
...
>>> a = {'key1': 'value1', 'key2': 42, 'key3': lambda: foo(20)}
>>> a
{'key3': <function <lambda> at 0x96ae80c>, 'key2': 42, 'key1': 'value1'}
>>> {k: v() if callable(v) else v for k,v in a.iteritems()}
{'key3': 2000, 'key2': 42, 'key1': 'value1'}

Related

How to update a list of dicts in pymongo?

I have some records like that in collection:
{
'_id': 1,
'test_field': [{'key1': 'value1'}, {'key2': 'value2'}]
}
test_field is a list of dicts. I need to push new dict in that list if any key does not exist and if it does I need to update that key’s value.
Examples:
{'key1': 'test_value'} → 'test_field': [{'key1': 'test_value'}, {'key2': 'value2'}]
{'test_key': 'test_value2'} → 'test_field': [{'key1': 'value1'}, {'key2': 'value2'}, {'test_key': 'test_value_2'}]
Help please
if you need a function in python to do it, this might work for you.
def modify_test_field(my_dict, test_field, new_key, new_val):
my_dict[test_field] = [obj for obj in my_dict[test_field] if new_key not in obj]
my_dict[test_field].append({new_key: new_val})
and call it like modify_test_field(orig_dict, 'test_field', new_key, new_val)

How to split values in a nested dictionary by characters

Lets say I have a nested dictionary
nested_dict={"dict1":{"key1":"value1", "key2":"value2", "key3":"value3;value4"}}
Now I want to split value3 and value 4 under the same key like this,
nested_dict={"dict1":{"key1":"value1", "key2":"value2", 'key3': ['value3', 'value4']}}
What would be the best way to do so in Python?
use the fact that dict is mutable and you can recursively change anything under the sun :P
nested_dict={"dict1":{"key1":"value1", "key2":"value2", "key3":"value3;value4"}}
def sol(d):
for i in d:
if type(d[i]) is dict:
sol(d[i])
else:
d[i] = d[i].split(';')
if len(d[i])==1: d[i] = d[i][0]
sol(nested_dict)
print(nested_dict)
{'dict1': {'key1': 'value1', 'key2': 'value2', 'key3': ['value3', 'value4']}}

Removing nulls and empty objects of mixed data types from a dictionary

How would one go about cleaning a dictionary containing a variety of datatypes of nulls and empty lists, dicts etc. E.g.
raw = {'key': 'value', 'key1': [], 'key2': {}, 'key3': True, 'key4': None}
To:
refined = {'key': 'value', 'key3': true}
Because of the mixed nature of data types in the dictionary, using:
refined = {k:v for k,v in processed.items() if len(v)>0}
throws a
TypeError: object of type 'bool' has no len()
Is there a solution to make a second conditional based on type(v) is bool?
Edit: I've found the issue I was encountering employing solutions was a result of the structure of the data, asking a separate question to deal with that.
You can try this.
refined={k:v for k,v in raw.items() if v or isinstance(v,bool)}
raw={'key': 'value',
'key1': [],
'key2': {},
'key3': True,
'key4': None,
'key5': False}
refined={k:v for k,v in raw.items() if v or isinstance(v,bool)}
#{'key': 'value', 'key3': True, 'key5': False}
How about
refined = {k:v for k, v in processed.items() v is not None and (type(v) not in (list, dict) or len(v) > 0)}

list of dictionaries from single dictionary

I have a dictionary like this
dict1 = {'key1': 'value1', 'key2': 'value2'}
how do I have an array of the keys and values as dictionaries like this
array_of_dict_values = [{'key1': 'value1'}, {'key2': 'value2'}]
What would be the easiest way to accomplish this?
You can do this:
>>> aDict = {'key1': 'value1', 'key2': 'value2'}
>>> aList = [{k:v} for k, v in aDict.items()]
>>> aList
[{'key2': 'value2'}, {'key1': 'value1'}]
While somebody already answered with how to do this, I'm going to answer with "you probably don't want to do this." If every entry is a dictionary with a single key, wouldn't a list of key-value pairs work just as well?
dictionary = {'key1': 'value1', 'key2': 'value2'}
print(list(dictionary.items()))
# [('key2', 'value2'), ('key1', 'value1')]

recursive access to dictionary and modification

I have the following dictionary:
my_dict = {'key1': {'key2': {'foo': 'bar'} } }
and I would like to append an entry to key1->key2->key3 with value 'blah' yielding:
my_dict = {'key1': {'key2': {'foo': 'bar', 'key3': 'blah'} } }
I am looking for a generic solution that is independent of the number of keys, i.e. key1->key2->key3->key4->key5 should work as well, even though keys from key3 on downwards do not exist. So that I get:
my_dict = {'key1': {'key2': {'foo': 'bar', 'key3': {'key4': {'key5': 'blah'} } } } }
Thanks in advance.
You can use the reduce() function to traverse a series of nested dictionaries:
def get_nested(d, path):
return reduce(dict.__getitem__, path, d)
Demo:
>>> def get_nested(d, path):
... return reduce(dict.__getitem__, path, d)
...
>>> my_dict = {'key1': {'key2': {'foo': 'bar', 'key3': {'key4': {'key5': 'blah'}}}}}
>>> get_nested(my_dict, ('key1', 'key2', 'key3', 'key4', 'key5'))
'blah'
This version throws an exception when a key doesn't exist:
>>> get_nested(my_dict, ('key1', 'nonesuch'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in get_nested
KeyError: 'nonesuch'
but you could replace dict.__getitem__ with lambda d, k: d.setdefault(k, {}) to have it create empty dictionaries instead:
def get_nested_default(d, path):
return reduce(lambda d, k: d.setdefault(k, {}), path, d)
Demo:
>>> def get_nested_default(d, path):
... return reduce(lambda d, k: d.setdefault(k, {}), path, d)
...
>>> get_nested_default(my_dict, ('key1', 'nonesuch'))
{}
>>> my_dict
{'key1': {'key2': {'key3': {'key4': {'key5': 'blah'}}, 'foo': 'bar'}, 'nonesuch': {}}}
To set a value at a given path, traverse over all keys but the last one, then use the final key in a regular dictionary assignment:
def set_nested(d, path, value):
get_nested_default(d, path[:-1])[path[-1]] = value
This uses the get_nested_default() function to add empty dictionaries as needed:
>>> def set_nested(d, path, value):
... get_nested_default(d, path[:-1])[path[-1]] = value
...
>>> my_dict = {'key1': {'key2': {'foo': 'bar'}}}
>>> set_nested(my_dict, ('key1', 'key2', 'key3', 'key4', 'key5'), 'blah')
>>> my_dict
{'key1': {'key2': {'key3': {'key4': {'key5': 'blah'}}, 'foo': 'bar'}}}
An alternative to Martijn Pieters's excellent answer would be to use a nested defaultdict, rather than a regular dictionary:
from collections import defaultdict
nested = lambda: defaultdict(nested) # nested dictionary factory
my_dict = nested()
You can set values by using regular nested dictionary access semantics, and empty dictionaries will be created to fill the middle levels as necessary:
my_dict["key1"]["key2"]["key3"] = "blah"
This of course requires that the number of keys be known in advance when you write the code to set the value. If you want to be able to handle a variable-length list of keys, rather than a fixed number, you'll need functions to do the getting and setting for you, like in Martijn's answer.

Categories