Why does Python 3 need dict.items to be wrapped with list()?

PythonPython 3.xPython 2to3

Python Problem Overview


I'm using Python 3. I've just installed a Python IDE and I am curious about the following code warning:

features = { ... }
for k, v in features.items():
    print("%s=%s" % (k, v))

Warning is: "For Python3 support should look like ... list(features.items()) "

Also there is mention about this at http://docs.python.org/2/library/2to3.html#fixers

> It also wraps existing usages of dict.items(), dict.keys(), and dict.values() in a call to list.

Why is this necessary?

Python Solutions


Solution 1 - Python

You can safely ignore this "extra precautions" warning: your code will work the same even without list in both versions of Python. It would run differently if you needed a list (but this is not the case): in fact, features.items() is a list in Python 2, but a view in Python 3. They work the same when used as an iterable, as in your example.

Now, the Python 2 to Python 3 conversion tool 2to3 errs on the side of safety, and assumes that you really wanted a list when you use dict.items(). This may not be the case (as in the question), in which case dict.items() in Python 3 (no wrapping list) is better (faster, and less memory-consuming, since no list is built).

Concretely, this means that Python 2 code can explicitly iterate over the view: for k, v in features.viewitems() (which will be converted in Python 3 by 2to3 to features.items()). It looks like your IDE thinks that the code is Python 2, because your for statement is very good, in Python 3, so there should be no warning about Python 3 support.

Solution 2 - Python

In Python 2, the methods items(), keys() and values() used to "take a snapshot" of the dictionary contents and return it as a list. It meant that if the dictionary changed while you were iterating over the list, the contents in the list would not change.

In Python 3, these methods return a view object whose contents change dynamically as the dictionary changes. Therefore, in order for the behavior of iterations over the result of these methods to remain consistent with previous versions, an additional call to list() has to be performed in Python 3 to "take a snapshot" of the view object contents.

Solution 3 - Python

Python 3 returns a Dictionary View Object rather than a list which Python 2 would return and some operators that you would expect may not be true - also a View Object will change if the underlying dictionary changes, (possibly in the code that you are iterating through which could cause some unwelcome surprises).

Solution 4 - Python

When converting a project to python 3 using 2to3, you can disable this by excluding the dict fixer for more concise output:

$ 2to3 -x dict *

Watch out for iteritems(), iterkeys() https://docs.python.org/2/library/2to3.html#2to3fixer-dict and fix by hand.

Solution 5 - Python

In Python 3, dict.items(), dict.keys(), and dict.values() are iterators. Therefore if you are expecting a list, you might get some errors when doing operations that work on lists, but not necessarily on iterators, such as len(dict.items()) (will generate a TypeError).

CORRECTION

The dict_items returned by calling dict.items() in Python 3 does indeed have a __len__() and will not generate a TypeError. The dict_items object is not a list, however, and does not have list methods, such as append(), index(), etc...

Also, as the other (I would say much better) answers by Hamidi and Barnes state, dict_items is a view object that will dynamically change when the dict is altered.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDewfyView Question on Stackoverflow
Solution 1 - PythonEric O LebigotView Answer on Stackoverflow
Solution 2 - PythonFrédéric HamidiView Answer on Stackoverflow
Solution 3 - PythonSteve BarnesView Answer on Stackoverflow
Solution 4 - PythonfmalinaView Answer on Stackoverflow
Solution 5 - PythonJoel CornettView Answer on Stackoverflow