Dict order in python 3.6 vs older

2020-02-07 04:50发布

问题:

I have this bit of code that I need printed out in this exact order (Visitor Team, Visitor Rating, Home Team, Home Rating, Expected Winner, Margin) when I run it through tabulate.

final_dict = {'Visitor Team': visitor_team, 'Visitor Rating': visitor_rating, 'Home Team': home_team,
              'Home Rating': home_rating, 'Expected Winner': expected_winner, 'Margin': expected_winner_diff}

print(tabulate(final_dict, headers="keys", floatfmt=".2f", tablefmt="fancy_grid"))

I've been learning and using Python 3.6 and, unbeknownst to me, dicts in 3.6 are ordered now so this actually prints out as I intended it to. It was just dumb luck I guess that Python 3.6 gave me exactly what I needed!

But I went to install Python 3.5 on another computer and this doesn't print out like I want. I've been reading about ordereddicts but I'm not sure how exactly to use it. Do I need to declare final_dict as empty first and then iterate into it the key order I need?

回答1:

Dictionaries in Python 3.6 are ordered, but that feature is considered an implementation detail that you shouldn't rely upon (except in a few specific cases like **kwargs). If you do require a specific order, you should use collections.OrderedDict instead. You can construct one using a list of key, value tuples that are in the desired order:

from collections import OrderedDict

finaldict = OrderedDict([('Visitor Team', visitor_team),
                         ('Visitor Rating', visitor_rating),
                         ('Home Team', home_team),
                         ('Home Rating', home_rating),
                         ('Expected Winner', expected_winner),
                         ('Margin', expected_winner_diff),
                        ])

An OrderedDict works just like a normal dict in most respects, other than having a different repr and a few additional methods. You can read more about it in the docs.

In Python 3.6+ you'd also be able to use keyword arguments to the constructor if your key strings were valid identifiers (e.g. OrderedDict(Margin=expected_winner_diff)). Unlike the ordering of normal dicts, the order of keywords is guaranteed to be preserved (not an implementation detail). That's not backwards compatible though (and can't work for your non-identifier keys anyway).

But it's probably worth considering that if you need a very specific order for your data, a dictionary may not be the best type to use to store it in. I see the tabulate function you're using comes from a library, and according to the docs, it accepts many different formats of data. I'd probably just pass it a list of column data, and give it the headers separately:

data = [visitor_team, visitor_rating, home_team,
        home_rating, expected_winner, expected_winner_diff]

headers = ["Visitor Team", "Visitor Rating", "Home Team",
           "Home Rating", "Expected Winner", "Margin"]

print(tabulate(data, headers=headers, floatfmt=".2f", tablefmt="fancy_grid"))

(Note, I've not actually tested that code, since I don't have the tabulate library on my system. But it should at least be close to working.)