¿Por qué mi código genera un error __setitem__ cuando uso __iadd__ en un elemento contenido?

¿Alguien puede decirme por qué este código se queja de que no hay __setitem__ en el contenedor? Pensé que solo necesitaba __getitem__ en el contenedor para recuperar el elemento y luego __iadd__ para establecer el valor, no sé por qué está esperando __setitem__

 class Item: def __init__(self): pass def __iadd__(self, value): print 'added: ' + value return self class Container: def __init__(self): self.__items = { 'foo': Item() } def __getitem__(self, name): return self.__items[name] if __name__ == '__main__': # works! con = Container() item = con['foo'] item += 'works!' # wtf? con['foo'] += "what's going on?" # output: # added: works! # added: what's going on? # Traceback (most recent call last): # File "foo.py", line 27, in  # con['foo'] += "what's going on?" # AttributeError: Container instance has no attribute '__setitem__' 

Básicamente,

 con['foo'] += "what's going on?" 

se comstack a algo como:

 item = con['foo'] item += "what's going on?" conf['foo'] = item 

Puedes ver, descomstackndo el código, algo como:

  2 0 LOAD_GLOBAL 0 (con) 3 LOAD_CONST 1 ('foo') 6 DUP_TOPX 2 9 BINARY_SUBSCR 10 LOAD_CONST 2 ("what's going on?") 13 INPLACE_ADD 14 ROT_THREE 15 STORE_SUBSCR 

Adivina esto: ¿Qué sucede si usas += en un tipo inmutable, como un int ? ¿Puede ver por qué llamar a += en un valor devuelto desde [] también tendría que llamar a __setitem__ ?

El verdadero truco es comprender que cualquier operador en python que tenga un = en él implica una asignación, ya que debe ser capaz de tratar con tipos inmutables de la manera esperada.

Para que quede claro, considere lo siguiente:

 >>> a = 10*10**9 >>> b = a >>> a is b True >>> a += 1 >>> a is b False 

Claramente, a fue asignado para hacer referencia a un nuevo valor. Por lo tanto, se mantiene que lo mismo sucede cuando realiza += en el valor devuelto por __getitem__ .

Desafortunadamente, la documentación de Python es terriblemente mala al afirmar que esto es lo que sucederá, pero como la otra respuesta señala con su descomstackción, claramente lo hace, y necesariamente debe manejar adecuadamente los tipos inmutables almacenados en contenedores mutables.