¿Son punteros las variables de Python? O sino ¿qué son?

Resuelto Lior asked hace 11 años • 9 respuestas

Las variables en Python son solo indicadores, hasta donde yo sé.

Según esta regla, puedo asumir que el resultado de este fragmento de código:

i = 5
j = i
j = 3
print(i)

sería 3.

Pero obtuve un resultado inesperado para mí, y fue 5...

Además, mi libro de Python cubre este ejemplo:

i = [1,2,3]
j = i
i[0] = 5
print(j)

El resultado sería [5,2,3].

¿Qué estoy entendiendo mal?

Lior avatar Nov 23 '12 21:11 Lior
Aceptado

Los llamamos referencias. ellos funcionan asi

i = 5     # create int(5) instance, bind it to i
j = i     # bind j to the same int as i
j = 3     # create int(3) instance, bind it to j
print i   # i still bound to the int(5), j bound to the int(3)

Las entradas pequeñas están internadas, pero eso no es importante para esta explicación.

i = [1,2,3]   # create the list instance, and bind it to i
j = i         # bind j to the same list as i
i[0] = 5      # change the first item of i
print j       # j is still bound to the same list as i
John La Rooy avatar Nov 23 '2012 14:11 John La Rooy

Las variables no son indicadores. Cuando asignas una variable, estás vinculando el nombre a un objeto. A partir de ese momento puedes referirte al objeto usando el nombre, hasta que ese nombre sea rebote.

En su primer ejemplo, el nombre iestá vinculado al valor 5. Vincular diferentes valores al nombre jno tiene ningún efecto i, por lo que cuando imprima más tarde, el valor del ivalor seguirá siendo 5.

En su segundo ejemplo, vincula ambos iy jal mismo objeto de lista. Cuando modifica el contenido de la lista, puede ver el cambio independientemente del nombre que utilice para referirse a la lista.

Tenga en cuenta que sería incorrecto si dijera "ambas listas han cambiado". Sólo hay una lista pero tiene dos nombres ( iy j) que hacen referencia a ella.

Documentación relacionada

  • Modelo de ejecución: denominación y vinculación
Mark Byers avatar Nov 23 '2012 14:11 Mark Byers

TLDR: los nombres de Python funcionan como punteros con eliminación/referenciación automática, pero no permiten operaciones explícitas de puntero. Otros objetivos representan direcciones indirectas, que se comportan de manera similar a los punteros.


La especificación del lenguaje Python no define qué nombres y demás son realmente , solo cómo se comportan. Sin embargo, el comportamiento se puede explicar con sugerencias.

La implementación de CPython utiliza punteros de tipoPyObject* oculto. Como tal, es posible traducir la semántica de nombres en operaciones de puntero. La clave es separar los nombres de los objetos reales .

El código Python de ejemplo incluye nombres ( i) y objetos ( 5).

i = 5  # name `i` refers to object `5`
j = i  # ???
j = 3  # name `j` refers to object `3`

Esto se puede traducir aproximadamente a código C con nombres y objetos separados .

int three=3, five=5;  // objects
int *i, *j;           // names
i = &five;   // name `i` refers to position of object `5`
j = i;       // name `j` refers to referent of `i`
j = &three;  // name `j` refers to position of object `3`

¡La parte importante es que los "nombres como punteros" no almacenan objetos! No lo definimos *i = five, pero i = &five . Los nombres y objetos existen independientemente unos de otros.

Los nombres sólo apuntan a objetos existentes en la memoria.

¡Al asignar un nombre a otro, no se intercambian objetos! Cuando definimos j = i, esto es equivalente a j = &five. Ninguno ide los dos jestá conectado con el otro.

+- name i -+ -\
               \
                --> + <five> -+
               /    |        5 |
+- name j -+ -/     +----------+

Como resultado, cambiar el destino de un nombre no afecta al otro . Solo actualiza lo que apunta ese nombre específico.


Python también tiene otros tipos de elementos similares a nombres : referencias de atributos ( i.j), suscripciones ( i[j]) y cortes ( i[:j]). A diferencia de los nombres, que se refieren directamente a objetos, los tres se refieren indirectamente a elementos de objetos.

El código de ejemplo incluye nombres ( i) y una suscripción ( i[0]).

i = [1,2,3]  # name `i` refers to object `[1, 2, 3]`
j = i        # name `j` refers to referent of `i`
i[0] = 5     # ???

Un CPython listutiliza una matriz C de PyObject*punteros bajo el capó. De nuevo, esto se puede traducir aproximadamente a código C con nombres y objetos separados.

typedef struct{
    int *elements[3];
} list;  // length 3 `list` type

int one = 1, two = 2, three = 3, five = 5;
list values = {&one, &two, &three};  // objects
list *i, *j;                         // names
i = &values;             // name `i` refers to object `[1, 2, 3]`
j = i;                   // name `j` refers to referent of `i`
i->elements[0] = &five;  // leading element of `i` refers to object `5`

¡Lo importante es que no cambiamos ningún nombre! Cambiamos i->elements[0]el elemento de un objeto al que apuntan nuestros dos nombres.

Los valores de los objetos compuestos existentes se pueden cambiar.

Al cambiar el valor de un objeto a través de un nombre, los nombres no se cambian. Ambos iy jsiguen refiriéndose al mismo objeto, cuyo valor podemos cambiar.

+- name i -+ -\
               \
                --> + <values> -+
               /    |  elements | --> [1, 2, 3]
+- name j -+ -/     +-----------+

El objeto intermedio se comporta de manera similar a un puntero en el sentido de que podemos cambiar directamente a qué apunta y hacer referencia a él desde varios nombres.

MisterMiyagi avatar Aug 06 '2019 16:08 MisterMiyagi

Las variables de Python son nombres vinculados a objetos.

De los documentos :

Los nombres se refieren a objetos. Los nombres se introducen mediante operaciones de vinculación de nombres. Cada aparición de un nombre en el texto del programa se refiere a la vinculación de ese nombre establecida en el bloque de funciones más interno que contiene el uso.

Cuando tu lo hagas

i = 5
j = i

eso es lo mismo que hacer:

i = 5
j = 5

jno señala iy después de la tarea, jno sabe que iexiste. jsimplemente está vinculado a lo que sea que iapuntaba en el momento de la asignación.

Si hicieras las tareas en la misma línea, se vería así:

i = j = 5

Y el resultado sería exactamente el mismo.

Así, más tarde haciendo

i = 3

no cambia lo jque apunta, y puedes intercambiarlo, j = 3no cambiaría lo que iapunta.

Su ejemplo no elimina la referencia a la lista.

Entonces cuando haces esto:

i = [1,2,3]
j = i

Es lo mismo que hacer esto:

i = j = [1,2,3]

entonces iy jambos apuntan a la misma lista. Entonces tu ejemplo muta la lista:

i[0] = 5

Las listas de Python son objetos mutables, por lo que cuando cambias la lista de una referencia y la miras desde otra referencia, verás el mismo resultado porque es la misma lista.

Lo que probablemente quieras es una copia de la lista, tal vez como esta:

i = [1,2,3]
j = i.copy()

Tenga en cuenta que ambas listas contienen los mismos objetos y, si son mutables, estarán en el mismo estado mutado cuando se acceda desde ambas listas porque son los mismos objetos.

Russia Must Remove Putin avatar Apr 25 '2016 20:04 Russia Must Remove Putin