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?
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.
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.
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).
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.
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.
来源:https://stackoverflow.com/questions/17695456/why-does-python-3-need-dict-items-to-be-wrapped-with-list