Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pythonic way to convert a dictionary into namedtuple or another hashable dict-like?

I have a dictionary like:

d = {'a': 1, 'b': 2, 'c': 3, 'd': 4} 

which I would like to convert to a namedtuple. My current approach is with the following code

namedTupleConstructor = namedtuple('myNamedTuple', ' '.join(sorted(d.keys()))) nt= namedTupleConstructor(**d) 

which produces

myNamedTuple(a=1, b=2, c=3, d=4)

This works fine for me (I think), but am I missing a built-in such as...

nt = namedtuple.from_dict() ? 

UPDATE: as discussed in the comments, my reason for wanting to convert my dictionary to a namedtuple is so that it becomes hashable, but still generally useable like a dict.

UPDATE2: 4 years after I've posted this question, TLK posts a new answer recommending using the dataclass decorator that I think is really great. I think that's now what I would use going forward.

like image 298
Max Power Avatar asked May 11 '17 16:05

Max Power


People also ask

How do you turn a dictionary into a tuple?

Use the items() Function to Convert a Dictionary to a List of Tuples in Python. The items() function returns a view object with the dictionary's key-value pairs as tuples in a list. We can use it with the list() function to get the final result as a list.

What is the difference between Namedtuple and dictionary?

Finally, namedtuple s are ordered, unlike regular dict s, so you get the items in the order you defined the fields, unlike a dict . If you need more flexibility, attrs is an interesting alternative to namedtuple. If you're using Python 3.7 or CPython 3.6 dicts are insertion ordered.

Are Python dictionaries hashable?

All immutable built-in objects in Python are hashable like tuples while the mutable containers like lists and dictionaries are not hashable. Objects which are instances of the user-defined class are hashable by default, they all compare unequal, and their hash value is their id().

Why are dictionaries hashable?

When we use a key that contains an unhashable type, i.e. a list, the underlying hash map cannot guarantee the key will map to the same bucket every single time. If we can't hash our key, we can't use it in our dictionary. Therefore, Python dictionaries require hashable dict keys. Having immutable keys is not enough.


2 Answers

To create the subclass, you may just pass the keys of a dict directly:

MyTuple = namedtuple('MyTuple', d) 

Now to create tuple instances from this dict, or any other dict with matching keys:

my_tuple = MyTuple(**d) 

Beware: namedtuples compare on values only (ordered). They are designed to be a drop-in replacement for regular tuples, with named attribute access as an added feature. The field names will not be considered when making equality comparisons. It may not be what you wanted nor expected from the namedtuple type! This differs from dict equality comparisons, which do take into account the keys and also compare order agnostic.

For readers who don't really need a type which is a subclass of tuple, there probably isn't much point to use a namedtuple in the first place. If you just want to use attribute access syntax on fields, it would be simpler and easier to create namespace objects instead:

>>> from types import SimpleNamespace >>> SimpleNamespace(**d) namespace(a=1, b=2, c=3, d=4) 

my reason for wanting to convert my dictionary to a namedtuple is so that it becomes hashable, but still generally useable like a dict

For a hashable "attrdict" like recipe, check out a frozen box:

>>> from box import Box >>> b = Box(d, frozen_box=True) >>> hash(b) 7686694140185755210 >>> b.a 1 >>> b["a"] 1 >>> b["a"] = 2 BoxError: Box is frozen 

There may also be a frozen mapping type coming in a later version of Python, watch this draft PEP for acceptance or rejection:

PEP 603 -- Adding a frozenmap type to collections

like image 168
wim Avatar answered Sep 19 '22 08:09

wim


from collections import namedtuple nt = namedtuple('x', d.keys())(*d.values()) 
like image 30
Mitendra Avatar answered Sep 21 '22 08:09

Mitendra