Pregunta

Esta es una simple cuestión de cómo Python maneja los datos y variables. He hecho muchos experimentos y han descubierto la mayoría de Python, excepto que esta me mantiene tropezar:

[Editar: I separó y reorganizado los ejemplos para mayor claridad]

Ejemplo 1:

>>> a = [[1], 2]
>>> a[0:1]
[[1]]
>>> a[0:1] = [[5]]
>>> a
[[5], 2] # The assignment worked.

Ejemplo 2:

>>> a = [[1], 2]
>>> a[0:1][0]
[1]
>>> a[0:1][0] = [5]
>>> a
[[1], 2] # No change?

Ejemplo 3:

>>> a = [[1], 2]
>>> a[0:1][0][0]
1
>>> a[0:1][0][0] = 5
>>> a
[[5], 2] # Why now?

Puede alguien me explique lo que está pasando aquí?

Hasta ahora, las respuestas parecen afirmar que a[0:1] devuelve una lista nueva que contiene una referencia al primer elemento de a. Pero no veo cómo eso explica el ejemplo 1.

¿Fue útil?

Solución

a [0: 1]. Devuelve una nueva matriz que contiene una referencia a la matriz de [1], por lo que se termina la modificación de la matriz interna a través de una llamada de referencia

La razón el primer caso no modifica la [1] serie es que se está asignando la matriz externa copiado un nuevo valor de la matriz interior.

Fondo línea - a. [0: 1] devuelve una copia de los datos, pero los datos interna no se copia

Otros consejos

Mi entendimiento es cortar devuelve un nuevo objeto. Es decir que del valor de retorno es una lista nueva.

Por lo tanto no se puede utilizar un operador de asignación a los cambios de los valores de la lista original

>>> a = [[1], 2, 3]
>>> k = a[0:2]
>>> id(a)
4299352904
>>> id(k)
4299353552
>>> 

>>> id(a)
4299352904
>>> id(a[0:2])
4299352832

algunas jugadas más a lo largo de las líneas

>>> k = 5
>>> 
>>> id(k)
4298182344
>>> a[0] = [1,2]
>>> a
[[1, 2], 2, 3]
>>> id(a)
4299352904
>>> 

[Editar: en la segunda parte de la pregunta]

>>> a[0:1] = [[5]]

La siguiente notación se denomina también comúnmente como asignación rebanada El comportamiento de las listas incorporadas es atómica (delete + insert) ocurre de una sola vez. Mi opinión es que esto no está permitido para la secuencia personalizada.

Hay tres operaciones distintas con índices, todas son traducidas a llamadas de método:

  • a[i] = b => a.__setitem__(i, b)
  • del a[i] => a.__delitem__(i)
  • a[i] utiliza como una expresión => a.__getitem__(i)

Aquí a, b y i son expresiones y i pueden contener objetos de división creado utilizando la sintaxis abreviada de colon. Por ejemplo:.

>>> class C(object):
...     def __setitem__(self, *a):
...             print a
... 
>>> C()[1] = 0
(1, 0)
>>> C()['foo'] = 0
('foo', 0)
>>> C()['foo':'bar'] = 0
(slice('foo', 'bar', None), 0)
>>> C()['foo':'bar',5] = 0
((slice('foo', 'bar', None), 5), 0)

Entonces, ¿qué está sucediendo en su tercer ejemplo es la siguiente:

a[0:1][0][0] = 5

se convierte

a.__getitem__(slice(0,1)).__getitem__(0).__setitem__(0, 5)

La primera __getitem__ devuelve una copia de parte de la lista, pero la segunda __getitem__ devuelve la lista real dentro que, que se modifica a continuación, utilizando __setitem__.

Su segundo ejemplo por el contrario se convierte

a.__getitem__(slice(0,1)).__setitem__(0, 5)

Así __setitem__ está siendo llamado en la copia en rodajas, dejando intacta la lista original.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top