¿Por qué Python 3 necesita dict.items para envolverse con list ()?

Estoy usando Python 3. Acabo de instalar un IDE de Python y tengo curiosidad por la siguiente advertencia de código:

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

La advertencia es: “Para Python3, el soporte debe verse como … list(features.items())

También hay una mención al respecto en http://docs.python.org/2/library/2to3.html#fixers

También envuelve los usos existentes de dict.items (), dict.keys () y dict.values ​​() en una llamada a la lista.

¿Por qué es esto necesario?

Puede ignorar esta advertencia de “precauciones adicionales” de manera segura: su código funcionará igual incluso sin list en ambas versiones de Python. Se ejecutaría de forma diferente si necesitara una lista (pero este no es el caso): de hecho, features.items() es una lista en Python 2, pero una vista en Python 3. Funcionan igual cuando se usan como un iterable. como en tu ejemplo

Ahora, la herramienta de conversión 2 a 3 de Python 2 a Python 3 se equivoca por el lado de la seguridad, y supone que realmente quería una lista cuando usa dict.items() . Es posible que este no sea el caso (como en la pregunta), en cuyo caso dict.items() en Python 3 (sin list dict.items() ) es mejor (más rápido y consume menos memoria, ya que no se dict.items() una lista).

Concretamente, esto significa que el código de Python 2 puede iterar explícitamente sobre la vista: for k, v in features.viewitems() (que se convertirá en Python 3 por 2to3 en features.items() ). Parece que su IDE piensa que el código es Python 2, porque su statement for es muy buena, en Python 3, por lo que no debería haber ninguna advertencia sobre el soporte de Python 3.

En Python 2, los items() los métodos items() , las keys() y los values() usan para “tomar una instantánea” del contenido del diccionario y devolverlo como una lista. Significaba que si el diccionario cambiaba mientras estaba iterando sobre la lista, los contenidos de la lista no cambiarían.

En Python 3, estos métodos devuelven un objeto de vista cuyo contenido cambia dinámicamente a medida que cambia el diccionario . Por lo tanto, para que el comportamiento de las iteraciones sobre el resultado de estos métodos se mantenga consistente con las versiones anteriores, se debe realizar una llamada adicional a list() en Python 3 para “tomar una instantánea” del contenido del objeto de la vista.

Python 3 devuelve un objeto de vista de diccionario en lugar de una lista que Python 2 devolvería y algunos operadores que usted esperaría podrían no ser ciertos; también cambiará un objeto de vista si cambia el diccionario subyacente (posiblemente en el código que está iterando). lo que podría causar algunas sorpresas desagradables).

En Python 3, dict.items() , dict.keys() y dict.values() son iteradores. Por lo tanto, si está esperando una lista, puede obtener algunos errores al realizar operaciones que funcionan en listas, pero no necesariamente en iteradores, como len(dict.items()) (generará un TypeError ).

CORRECCIÓN

Los dict_items devueltos al llamar a dict.items() en Python 3 sí tienen un __len__() y no generarán un TypeError . Sin dict_items objeto dict_items no es una lista y no tiene métodos de list , como append() , index() , etc.

Además, como el otro (yo diría que mucho mejor) responde por el estado de Hamidi y Barnes, dict_items es un objeto de vista que cambiará dinámicamente cuando se modifique el dict .

Al convertir un proyecto a Python 3 usando 2to3 , puede deshabilitarlo excluyendo el dict para obtener un resultado más conciso:

 $ 2to3 -x dict * 

Tenga cuidado con iteritems() , iterkeys() https://docs.python.org/2/library/2to3.html#2to3fixer-dict y iterkeys() mano.