Entendiendo la ausencia de punteros en Python

27

5

En algunas aplicaciones sencillas que me ha tocado escribir en C/C++ he visto la facilidad con la que se resuelven ciertas tareas utilizando punteros. Ahora, más interesado en otro lenguaje: Python, he notado la ausencia de este concepto. ¿A qué se debe esta ausencia? Siendo Python un lenguaje muy poderoso y utilizado, entonces, ¿qué concepto lo sustituye?, ¿está implícito en los tipos de datos, en las asignaciones, en la instanciación de una clase?

Un ejemplo extremadamente sencillo sería que en C podemos codificar cosas como esta:

#include <stdio.h>

int main(void) {
    // your code goes here
    int a = 5;
    int *b = &a;
    printf("a = %d; b = %d\n", a, *b); // (1)

    a = 6;
    printf("a = %d; b = %d\n", a, *b); // (2)
    return 0;
}

(1): a = 5; b = 5

(2): a = 6; b = 6

b apunta a la dirección de memoria de a, cualquier modificación en a podrá ser observada al desreferenciar b. Cualquier asignación por indirección *b = <valor>; modificará a.

Pero, en Python:

a = 5
b = a
print "a = {0:d}; b = {1:d}".format(a,b) # (1)
b is a # resultado: True

a = 6
print "a = {0:d}; b = {1:d}".format(a,b) # (2)
b is a # resultado: False

(1): a = 5; b = 5

(2): a = 6; b = 5

Al principio a y b hacen referencia al mismo objeto. Luego, cuando a es modificado se crea un nuevo objeto; entonces, ambos hacen referencia a objetos diferentes y de valores diferentes.

No hay una forma de hacer lo que en C en Python con este tipo de dato, pero es posible hacer algo similar con tipos de datos mutables; sin embargo, solo se puede cuando hacemos modificaciones internas del dato mutable, por ejemplo: cambiar el valor de un elemento de una lista.

a = [1, 2]
b = a

print b is a # resultado: True

b.append(3)

print b is a # resultado: True

a = [4, 5]

print b is a # resultado: False

OSjerick

Posted 2015-12-03T23:00:09.650

Reputation: 377

2El concepto de variable al estilo C (posición de memoria cuyo contenido cambia) no tiene sentido en Python. Lo que se conoce como variables en realidad son 'nombres' que guardan una referencia a un objeto (una instancia de un tipo), esto en sí es un puntero expresado de forma implícita. El operador is compara las referencias de ambos nombres y devuelve True en caso de que sean iguales, esto es, que apunten al mismo objeto.tinproject 2015-12-06T21:02:33.627

Estaría bueno que comentes algún caso puntual en que los punteros te parezca necesario el concepto para hacer la pregunta más clara (y también las posibles respuestas)eloyesp 2015-12-04T00:05:01.467

esto vendría a ser un alias no? dos nombres para una misma variable, me parece que usar esto va a hacer que el código sea más difícil de entender ya que al modificar un valor hace cambiar otra variable que nunca se modificó. me gustaría ver un caso de uso real para esta técnica.Samus_ 2015-12-05T23:17:34.010

Answers

28

Su ausencia se debe a que el uso explícito de punteros es una característica de lenguajes de más bajo nivel como el C. Lenguajes de alto nivel como Python lo evitan con el propósito de hacer más fácil y ágil su utilización, así como no tener que conocer detalles del modelo de datos.

Que el programador de Python no tenga que lidiar con los punteros no quiere decir que el intérprete no haga uso de ellos. De hecho los usa profusamente de forma implícita.

En Python todo es un objeto creado en la memoria dinámica (mantenida automáticamente). Cuando llamas a una función los argumentos son pasados mediante sus punteros. Es lo que se conoce como convención de llamada por objeto. De igual forma si asignas a = b, a lo que guarda es el puntero del objeto de b. Así que todas las variables son punteros a objetos, que son manejados implícitamente.

Lo que sí hay que diferenciar es entre objetos inmutables y mutables.

  • Inmutables son los números, las cadenas o las tuplas. Al asignar x = 2015 creará un objeto entero y x apuntará a él pero el contenido de ese objeto no podrá ser modificado. Si luego asignas x = 2016 lo que hará internamente será crear un nuevo objeto con el nuevo contenido.
  • Mutables son otros objetos como los diccionarios o las listas. En este caso dichos objetos sí podrán ser modificados. Si tienes v = [1] y luego llamas a v.append(2), v seguirá apuntando al mismo objeto, pero su contenido habrá cambiado.

En resumen, al ejecutar este código:

x = 2015
y = x
x = 2016

print x
print y

v = [1]
w = v
v.append(2)

print v
print w

El resultado será:

2016
2015
[1, 2]
[1, 2]

Guillermo Ruiz

Posted 2015-12-03T23:00:09.650

Reputation: 614

7

En C, los punteros suelen satisfacer tres necesidades: referenciar estructuras reservadas dinámicamente, pasar parámetros a una función por referencia, o iterar una colección.

En el caso de Python, y los lenguajes de objetos con memoria automática en general, las variables cumplen la función de referenciar estructuras creadas dinámicamente: uno puede crear instancias de los objetos en cualquier momento.

En general, los objetos de reservan en la memoria dinámica de los procesos, y las variables son referencias a ellos: casi casi que las referencias son abstracciones de los punteros, con algunas propiedades más.

Por este motivo, el pasaje de parámetros se hace siempre por referencia, por lo que no se necesitan punteros para esto.

Por último, en los lenguajes de objetos existen objetos iteradores, que exponen una interfaz de más alto nivel para recorrer colecciones de datos.

Abstraerse de los detalles de la memoria del proceso es algo buscado en los lenguajes, y por todo esto es que no son necesarios los punteros: por diseño.

mgarciaisaia

Posted 2015-12-03T23:00:09.650

Reputation: 463

2Por este motivo, el pasaje de parámetros se hace siempre por referencia, por lo que no se necesitan punteros para esto. falso, el paso de parámetros se hace por valor, pero se trata de valores referencia. Ni Python, ni Java, ni JavaScript, ni muchos otros permiten modificar el valor concreto de una variable pasada por parámetro, solo el valor al que hacen referencia, y solo para tipos mutables.Darkhogg 2015-12-04T01:04:41.463

0

Es un poco chapuza, pero si realmente necesitas 1 variable y un "puntero" puedes hacer:

class mutable_obj:
    def __init__(self, x):
        self.x = x

a = mutable_obj(10)
b = a
a.x == b.x # True
a.x = 30
a.x == b.x # True
b.x = 86
a.x == b.x # True

Creo que es innecesario, igualmente si alguien sabe una mejor manera ¡que lo diga! :D

Pablo

Posted 2015-12-03T23:00:09.650

Reputation: 23