I have a named tuple class in python
class Town(collections.namedtuple('Town', [
'name',
'population',
'coordinates',
'population',
'capital',
'state_bird'])):
# ...
What I'd like to do is turn this into a dictionary. I'll admit python is not one of my stronger languages. The key is that I dont want it to be rigidly tied to the name or numbers of the fields I have.
Is there a way to write it such that I could add more fields, or pass an entirely different named tuple in and get a dictionary.
Edit: I cant not alter the original class definition as its in someone elses code. So I need to take an instance of a Town and convert it to a dictionary.
TL;DR: there's a method _asdict
provided for this.
Here is a demonstration of the usage:
>>> fields = ['name', 'population', 'coordinates', 'capital', 'state_bird']
>>> Town = collections.namedtuple('Town', fields)
>>> funkytown = Town('funky', 300, 'somewhere', 'lipps', 'chicken')
>>> funkytown._asdict()
OrderedDict([('name', 'funky'),
('population', 300),
('coordinates', 'somewhere'),
('capital', 'lipps'),
('state_bird', 'chicken')])
This is a documented method of namedtuples, i.e. unlike the usual convention in python the leading underscore on the method name isn't there to discourage use. Along with the other methods added to namedtuples, _make
, _replace
, _source
, _fields
, it has the underscore only to try and prevent conflicts with possible field names.
Note: For some 2.7.5 < python version < 3.5.0 code out in the wild, you might see this version:
>>> vars(funkytown)
OrderedDict([('name', 'funky'),
('population', 300),
('coordinates', 'somewhere'),
('capital', 'lipps'),
('state_bird', 'chicken')])
For a while the documentation had mentioned that _asdict
was obsolete (see here), and suggested to use the built-in method vars. That advice is now outdated; in order to fix a bug related to subclassing, the __dict__
property which was present on namedtuples has again been removed by this commit.
There's a built in method on namedtuple
instances for this, _asdict
.
As discussed in the comments, on some versions vars()
will also do it, but it's apparently highly dependent on build details, whereas _asdict
should be reliable. In some versions _asdict
was marked as deprecated, but comments indicate that this is no longer the case as of 3.4.
On Ubuntu 14.04 LTS versions of python2.7 and python3.4 the __dict__
property worked as expected. The _asdict
method also worked, but I'm inclined to use the standards-defined, uniform, property api instead of the localized non-uniform api.
$ python2.7
# Works on:
# Python 2.7.6 (default, Jun 22 2015, 17:58:13) [GCC 4.8.2] on linux2
# Python 3.4.3 (default, Oct 14 2015, 20:28:29) [GCC 4.8.4] on linux
import collections
Color = collections.namedtuple('Color', ['r', 'g', 'b'])
red = Color(r=256, g=0, b=0)
# Access the namedtuple as a dict
print(red.__dict__['r']) # 256
# Drop the namedtuple only keeping the dict
red = red.__dict__
print(red['r']) #256
Seeing as dict is the semantic way to get a dictionary representing soemthing, (at least to the best of my knowledge).
It would be nice to accumulate a table of major python versions and platforms and their support for __dict__
, currently I only have one platform version and two python versions as posted above.
| Platform | PyVer | __dict__ | _asdict |
| -------------------------- | --------- | -------- | ------- |
| Ubuntu 14.04 LTS | Python2.7 | yes | yes |
| Ubuntu 14.04 LTS | Python3.4 | yes | yes |
| CentOS Linux release 7.4.1708 | Python2.7 | no | yes |
| CentOS Linux release 7.4.1708 | Python3.4 | no | yes |
| CentOS Linux release 7.4.1708 | Python3.6 | no | yes |
Python 3. Allocate any field to the dictionary as the required index for the dictionary, I used 'name'.
import collections
Town = collections.namedtuple("Town", "name population coordinates capital state_bird")
town_list = []
town_list.append(Town('Town 1', '10', '10.10', 'Capital 1', 'Turkey'))
town_list.append(Town('Town 2', '11', '11.11', 'Capital 2', 'Duck'))
town_dictionary = {t.name: t for t in town_list}