pprint dictionary on multiple lines - python

I'm trying to get a pretty print of a dictionary, but I'm having no luck:
>>> import pprint
>>> a = {'first': 123, 'second': 456, 'third': {1:1, 2:2}}
>>> pprint.pprint(a)
{'first': 123, 'second': 456, 'third': {1: 1, 2: 2}}
I wanted the output to be on multiple lines, something like this:
{'first': 123,
'second': 456,
'third': {1: 1,
2: 2}
}
Can pprint do this? If not, then which module does it? I'm using Python 2.7.3.

Use width=1 or width=-1:
In [33]: pprint.pprint(a, width=1)
{'first': 123,
'second': 456,
'third': {1: 1,
2: 2}}

You could convert the dict to json through json.dumps(d, indent=4)
import json
print(json.dumps(item, indent=4))
{
"second": 456,
"third": {
"1": 1,
"2": 2
},
"first": 123
}

If you are trying to pretty print the environment variables, use:
pprint.pprint(dict(os.environ), width=1)

Two things to add on top of Ryan Chou's already very helpful answer:
pass the sort_keys argument for an easier visual grok on your dict, esp. if you're working with pre-3.6 Python (in which dictionaries are unordered)
print(json.dumps(item, indent=4, sort_keys=True))
"""
{
"first": 123,
"second": 456,
"third": {
"1": 1,
"2": 2
}
}
"""
dumps() will only work if the dictionary keys are primitives (strings, int, etc.)

This is a Copy-Pasta for testing purposes and to help with a usage example.
from pprint import pprint # I usually only need this module from the package.
a = {'first': 123, 'second': 456, 'third': {1:1, 2:2}, 'zfourth': [{3:9, 7:8}, 'distribution'], 1:2344, 2:359832, 3:49738428, 4:'fourth', 5:{'dictionary':'of things', 'new':['l','i','s','t']}}
pprint(dict(a), indent=4, width=1)
# Wrap your variable in dict() function
# Optional: indent=4. for readability
# Required: width=1 for wrapping each item to its own row.
# Note: Default pprint is to sort the dictionary
# Note: This also auto-wraps anything sting that has spaces in it. See 'of things' below.
# Documentation: https://docs.python.org/3/library/pprint.html
# Examples: https://pymotw.com/2/pprint/
# Blog: https://realpython.com/python-pretty-print/
Provides the following result:
{ 1: 2344,
2: 359832,
3: 49738428,
4: 'fourth',
5: { 'dictionary': 'of '
'things',
'new': [ 'l',
'i',
's',
't']},
'first': 123,
'second': 456,
'third': { 1: 1,
2: 2},
'zfourth': [ { 3: 9,
7: 8},
'distribution']}

Related

Delete key:value pair from dict in list in nested dict

Lets say I have this dict:
dictos = {
"a": {
"b": {
"c": 3,
"d": 4,
"e": [],
"f": [{"g": 5}, 'test', {"h": 6, "i": 7}]
}
}
}
And lets say I want to delete "c": 3 pair. What I am doing:
import dpath.util
path = "a/b/c"
dpath.util.delete(dictos, path)
It is working great. The output is:
{
'a': {
'b': {
'd': 4,
'e': [],
'f': [{'g': 5}, 'test', {'h': 6, 'i': 7}]
}
}
}
The problem is when I am trying to delete key:value pair inside the list.
Lets say I want to delete "h":6. So when doing:
path = "a/b/f[2]/h"
dpath.util.delete(dictos, path)
I am getting:
dpath.exceptions.PathNotFound: Could not find a/b/f[2]/h to delete
it.
So the question basically is how to delete items from nested dicts that are in a list?
It seems the library expects the same separator to be used for all segments i.e. use a/b/f/2/h
path = "a/b/f/2/h"
dpath.util.delete(dictos, path)
print(dictos)
Result:
{'a': {'b': {'d': 4, 'e': [], 'f': [{'g': 5}, 'test', {'i': 7}]}}}

Remove the bottom level in a nested python dictionary

Consider this input dictionary:
my_dict = {
'group1':{
'type1': {'val1' : 45, 'val2' : 12, 'val3' : 65},
'type2': {'val5' : 65, 'val6' : 132, 'val7' : 656},
},
'group2':{
'type3': {'val11' : 45, 'val12' : 123, 'val13' : 3},
'type4': {'val51' : 1, 'val61' : 2, 'val71' : 3, },
},
}
I would like to remove the last 'level' (the one that only has numbers), and get something like:
new_dict = {
'group1':{
'type1': ['val1', 'val2', 'val3'],
'type2': ['val5', 'val6', 'val7'],
},
'group2':{
'type3': ['val11', 'val12', 'val13'],
'type4': ['val51', 'val61', 'val71'],
},
}
I am currently doing it by manually looping and so on, but I wonder if there is a way to do it more efficiently.
If your dictionary doesn't have a fixed number of nesting levels, you could write a recursive function to do it:
def stripBottom(d):
if not isinstance(d,dict):
return d
elif not any(isinstance(v,dict) for v in d.values()):
return list(d)
else:
return {k:stripBottom(v) for k,v in d.items()}
Output:
my_dict = {
'group1':{
'type1': {'val1' : 45, 'val2' : 12, 'val3' : 65},
'type2': {'val5' : 65, 'val6' : 132, 'val7' : 656},
},
'group2':{
'type3': {'val11' : 45, 'val12' : 123, 'val13' : 3},
'type4': {'val51' : 1, 'val61' : 2, 'val71' : 3, },
},
}
print(stripBottom(my_dict))
{'group1': {'type1': ['val1', 'val2', 'val3'],
'type2': ['val5', 'val6', 'val7']},
'group2': {'type3': ['val11', 'val12', 'val13'],
'type4': ['val51', 'val61', 'val71']}}
If your dictionary has variable levels of nesting or if you want to drop a specific level, you would need to add a parameter to the function:
def stripBottom(d,level=0):
if not isinstance(d,dict):
return d
elif level == 0:
return list(d)
else:
return {k:stripBottom(v,level-1) for k,v in d.items()}
print(stripBottom(my_dict,1))
{'group1': ['type1', 'type2'], 'group2': ['type3', 'type4']}
You don't give an example of the actual code you are using to change the dict, but likely you will always need 2 levels of looping to iterate over groups, and then types. Something like:
newdict = {}
for k, grp in my_dict.items():
newdict[k] = {}
for typ, val in grp.items():
newdict[k][typ] = list(val)
One option to be more efficient is to not pre-compute these updted values, but instead when you come to use the 'group' data, wrap the output in list at that point. (Though obviously you will still be iterating when the dict is being used, to get these nested dicts).

Python Dict inside List inside Dict - comprehension possible?

I have an object in Python 3 of this format:
a = {
'events': [
{
'timestamp': 123,
'message': 'test'
},
{
'timestamp': 456,
'message': 'foo'
},
{
'timestamp': 789,
'message': 'testbar'
},
],
'first': 'abc',
'last': 'def'
}
I want to create a new object of the same format, but filtered by whether the message key's corresponding value contains a certain string, for example filtering by "test":
a = {
'events': [
{
'timestamp': 123,
'message': 'test'
},
{
'timestamp': 789,
'message': 'testbar'
},
],
'first': 'abc',
'last': 'def'
}
Can I use a nested comprehension for this? I know you can do nested list comprehensions like:
[[y*2 for y in x] for x in l]
But is there a neat way for a dict > list > dict situation?
One option would be to create a new copy of the input dict without events, and then set the filtered events as you require, like this:
copy = {k: v for k, v in a.items() if k != 'events'}
copy['events'] = [e for e in a['events'] if 'test' in e['message']]
Or if you don't mind overwriting the original input, simply do this:
a['events'] = [e for e in a['events'] if 'test' in e['message']]
I would go with a list comprehension with an if-statement like the following:
[event for event in a["events"] if event["message"] == "test" ]
Loop through the values of the "events"-key and add them to the list if the value of their "message" key equals "test".
The result is a list of dictionaries that you can assign back to a["events"] or a copy of a if you would like to preserve a["events"].
So - you can use multiple layers of comprehension, but that doesn't mean you should. I think for such an example, you'd produce cleaner code, by running it through a couple of for loops. Having that said, I think the following is technically achieves the outcome you're asking for.
>>> pprint.pprint(a)
{'events': [{'message': 'test', 'timestamp': 123},
{'message': 'foo', 'timestamp': 456},
{'message': 'testbar', 'timestamp': 789}],
'first': 'abc',
'last': 'def'}
>>> aa = copy.deepcopy(a)
>>> aa['beta'] = aa['events']
>>> pprint.pprint({k:[item for item in v if 'test' in item['message']] if isinstance(v, list) else v for k, v in aa.items()})
{'beta': [{'message': 'test', 'timestamp': 123},
{'message': 'testbar', 'timestamp': 789}],
'events': [{'message': 'test', 'timestamp': 123},
{'message': 'testbar', 'timestamp': 789}],
'first': 'abc',
'last': 'def'}
>>> pprint.pprint({k:[item for item in v if 'test' in item['message']] if isinstance(v, list) else v for k, v in a.items()})
{'events': [{'message': 'test', 'timestamp': 123},
{'message': 'testbar', 'timestamp': 789}],
'first': 'abc',
'last': 'def'}
As said, this is something you can do; I would however on behalf of everyone who's had to read other people code in their careers, respectfully request that you don't use this in production code. A couple of for loops might be more LOC, but would in most cases be much more readable and maintainable.

Update values from a "default dictionary" without removing its keys [duplicate]

This question already has answers here:
Update value of a nested dictionary of varying depth
(28 answers)
Closed 4 years ago.
I have two dictionaries, the first is what the default values of the second one should fall back to if they are not present or not defined, and it is somewhat like this:
default_dict = {
'lorem': {
'foo': 'white',
'bar': 'black',
},
'ipsum': {
'xyz': '',
'abc': {},
'qwe': {}
}
}
And the second looks like this:
custom_dict = {
'lorem': {
'bar': 'blue',
},
'ipsum': {
'xyz': 'apple',
'qwe': { 'one': 'strawberry' }
}
}
Is there any way I can "update" from the default_dict with the values from the custom_dict?
The desired result would look something like this:
custom_dict = {
'lorem': {
'foo': 'white',
'bar': 'blue',
},
'ipsum': {
'xyz': 'apple',
'abc': {},
'qwe': { 'one': 'strawberry' }
}
}
I've tried doing default_dict.update(custom_dict) and then custom_dict = default_dict, but as you can imagine I'm just getting custom_dict back untouched... So the keys of default_dict are getting removed when it is updated.
Use:
d={a:b for k,v in custom_dict.items() for a,b in v.items()}
print({k:{a:d.get(a,b) for a,b in v.items()} for k,v in default_dict.items()})
A dictionary comprehension + a nested dictionary comprehension would work.
Output:
{'lorem': {'foo': 'white', 'bar': 'blue'}, 'ipsum': {'xyz': 'apple', 'abc': {}, 'qwe': {'one': 'strawberry'}}}
if the structure of your dictionaries are always like above so the following code works fine:
for item in default_dict:
for value in default_dict[item].keys():
if value not in custom_dict[item].keys():
custom_dict[item].update({value: default_dict[item][value]})
good luck

Why is data contamination?

# -*- coding: utf-8 -*-
import random, pprint
user = {}
USERINFO_STRUCT = {
'id': '',
}
def client_new(id):
global user
newuser = USERINFO_STRUCT
newuser['id'] = id
user[id] = newuser
pprint.pprint(user)
print ""
client_new(1)
client_new(2)
client_new(3)
I want results:
{1: {'id': 1}}
{1: {'id': 1}, 2: {'id': 2}}
{1: {'id': 1}, 2: {'id': 2}, 3: {'id': 3}}
The results of that code execution is:
{1: {'id': 1}}
{1: {'id': 2}, 2: {'id': 2}}
{1: {'id': 3}, 2: {'id': 3}, 3: {'id': 3}}
How are you doing this?
My machine is Debian Linux 8.6 (Python 2.7.9).
In python, dictionaries and lists are copied by reference:
>>> a = [0]
>>> b = a
>>> b
[0]
>>> a
[0]
>>> b[0] = 2
>>> a
[2]
>>> b
[2]
So, b and a refer to the same list in the python memory and modifying one modifies the other.
So, what you can do is when you want to create another copy of a list or dictionary, make a copy. For a list:
>>> b = a[:] # for a list
For a dictionary:
>>> b = a.copy() # for a dictionary
So, in your code, what you need is to copy the USERINFO_STRUCT into the newuser using newuser = USERINFO_STRUCT.copy()

Categories