2010-02-18 9 views
13

Me gustaría poder hacer un diccionario de Python con cadenas como claves y conjuntos de cadenas como los valores. P. ej .: { "crackers" : ["crunchy", "salty"] } Debe ser un conjunto, no una lista.¿Diccionario de Python que asigna cadenas a un conjunto de cadenas?

Sin embargo, cuando intento el siguiente:

word_dict = dict() 
    word_dict["foo"] = set() 
    word_dict["foo"] = word_dict["foo"].add("baz")          
    word_dict["foo"] = word_dict["foo"].add("bang") 

me sale:

Traceback (most recent call last): 
    File "process_input.py", line 56, in <module> 
    test() 
    File "process_input.py", line 51, in test 
    word_dict["foo"] = word_dict["foo"].add("bang") 
AttributeError: 'NoneType' object has no attribute 'add' 

Si hago esto:

word_dict = dict() 
    myset = set() 
    myset.add("bar") 
    word_dict["foo"] = myset 
    myset.add("bang") 
    word_dict["foo"] = myset 

    for key, value in word_dict:              
     print key,                 
     print value 

me sale:

Traceback (most recent call last): 
    File "process_input.py", line 61, in <module> 
    test() 
    File "process_input.py", line 58, in test 
    for key, value in word_dict: 
ValueError: too many values to unpack 

¿Algún consejo sobre cómo obligar a Python a hacer lo que me gustaría? Soy un usuario de Python intermedio (o eso pensaba, hasta que me encontré con este problema.)

Respuesta

27

set.add() no devuelve un nuevo set, modifica el set se llama sucesivamente. Usarlo de esta manera:

word_dict = dict() 
word_dict["foo"] = set() 
word_dict["foo"].add("baz")          
word_dict["foo"].add("bang") 

Además, si se utiliza un bucle for para iterar sobre un diccionario, que está interactuando sobre las teclas:

for key in word_dict: 
    print key, word_dict[key] 

alternativa usted puede iterar sobre word_dict.items() o word_dict.iteritems():

for key, value in word_dict.items(): 
    print key, value 
+0

Gracias. Por supuesto, duh. –

23
from collections import defaultdict 

word_dict = defaultdict(set) 
word_dict['banana'].add('yellow') 
word_dict['banana'].add('brown') 
word_dict['apple'].add('red') 
word_dict['apple'].add('green') 
for key,values in word_dict.iteritems(): 
    print "%s: %s" % (key, values) 
+0

+1 no responde directamente a la pregunta, pero sin duda puede hacer la vida del OP más fácil aquí . –

+0

¡Agradable! Es una gran idea. –

+0

+1 no sabía eso .. Tuve el mismo problema que el OP y esto es muy bueno y la OMI más legible que la respuesta aceptada. – DrColossos

1

Probar:

word_dict = dict() 
myset = set() 
myset.add("bar") 
word_dict["foo"] = myset 
myset.add("bang") 
word_dict["foo"] = myset 

for key in word_dict:              
    print key, word_dict[key] 

Parece que el iterador de diccionario estándar devuelve solo key pero no tupla.

Prueba:

>>> d = { 'test': 1 } 
>>> for k, v in d: print k, v 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: too many values to unpack 
>>> for k in d: print d[k] 
... 
1 
+0

Alternativamente, 'para clave, valor en word_dict.iteritems():' es un poco más largo, pero más agradable en el acceso de 'clave' y' valor' en mi humilde opinión. –

6

Cuando dice word_dict["foo"].add("baz"), está añadiendo 'baz' al conjunto word_dict [ "foo"].

La función devuelve None - actualizar el conjunto es un efecto secundario. Así

word_dict["foo"] = word_dict["foo"].add("baz") 

en última instancia establece word_dict["foo"] a None.

Solo word_dict["foo"].add("baz") sería correcto.

En el segundo escenario, cuando se dice

for key, value in word_dict:              

se encuentra con un error porque la sintaxis correcta es

for key in word_dict: 

para recorrer sólo las llaves en word_dict.En esta situación, desea

for key,value in word_dict.iteritems(): 

en su lugar.

1

El problema es el siguiente:

word_dict["foo"] = word_dict["foo"].add("baz") 

Cuando se llama a word_dict["foo"].add("baz"), estás mutando el conjunto que se refiere a word_dict["foo"], y que la operación vuelve None. Entonces, al leer su afirmación de derecha a izquierda, agrega "baz" al conjunto al que hace referencia word_dict["foo"], y luego establece el resultado de esa operación (es decir, None) en word_dict["foo"].

Por lo tanto, para que esto funcione como esperaba, simplemente elimine word_dict["foo"] = de su extracto.

Diccionarios iterar sobre sus claves por defecto, por lo tanto el ValueError intenta esto:

for key, value in word_dict: 

Lo que sucede aquí es que la iteración en word_dict está volviendo solamente una clave (por ejemplo, "foo"), que le' Re tratando de descomprimir en las variables key & value. Al desempaquetar "foo", obtendrá "f", "o", & "o", que es un valor demasiado grande para caber en dos variables y, por lo tanto, su ValueError.

Como otros han dicho, lo que quiere es iterar sobre pares de valores clave del diccionario, así:

for key, value in word_dict.iteritems(): 
Cuestiones relacionadas