TAJINASTES BLANCOS COMENZANDO A FLORECER, CAMINO RURAL DE CHIRCHE, GUÍA DE ISORA, OESTE DE TENERIFE. |
Como podemos suponer con sólo conocer un poco de informática, una "herramienta" que empiece (o directamente se llame) 'DEL' no puede referenciar otra cosa que "delete", en castellano, "borrar, eliminar". Y efectivamente, eso es lo que hace en Python la sentencia del. Sin embargo, no lo olvidemos, la singularidad de las listas y sus elementos componentes. Recordemos que estos no son los objetos en sí sino referencias a los propios objetos, algo así como copias exactas de sí mismas.
Como consecuencia de ello, la aplicación de la sentencia del a los elementos de una lista lo que realmente provoca es, primero, la desvinculación entre la referencia al objeto x y el objeto x en sí, la eliminación de la referencia y la remisión del objeto tal cual a la basura donde éste se recoge y almacena, siempre y cuando no existan otras referencias de objeto que lo apunten explícitamente.
La sentencia del mantiene concomitancias claras con el método list.clear() cuando emplea una rebanada vacía, pues ambas eliminan todos los ítems de una lista devolviendo un resultado similar. Igualmente mantiene esa misma afinidad con los métodos list.remove() cuando el ítem es señalado por el índice, y con list.pop() y list.pop(índice), aunque no se nos devuelve el ítem eliminado.
LAS REFERENCIAS EN PYTHON
Consideramos llegados a este punto que conviene ahondar un poco más en un aspecto fundamental de Python: la referencia. Y para hacerlo nos vendría bien comenzar con un ejemplo. Veamos:
Fijémonos que a pesar de que tenemos dos variables distintas, lista1 y lista2, al modificar el valor de una de ellas, en virtud de su asignación por el operador =, la mentada modificación se refleja automáticamente en la segunda. De hecho, la llamada al verificador is de identidad bajo la sintaxis lista1 is lista2 nos devuelve el booleano True. Pero la pregunta que podríamos hacernos es: ¿Por qué esto es así? Si lista1 y lista2 eran las mismas cuando se asignaron, lo cual es perfectamente comprensible, ¿por qué ahora, a posteriori, cuando hemos modificado una de ellas y no hemos vuelto a reasignarlas, la secuencia de datos que contienen ambas son idénticas? ¿Por qué ha cambiado lista2 al modificar lista1 si no las hemos vuelto a asignar desde que modificamos lista1?
Pues la respuesta está en la referencia ¿ein?
Lo que realmente ocurre es que, no nos olvidemos de ello, para Python todo cuanto existe en el mundo mundial, todo cuanto ha sido, es y será son objetos (objects), lo que tendrá su importancia cuando nos internemos en la Programación Orientada a Objetos, POO,Cuando hemos procedido a modificar la lista1 sustituyendo un objeto por otro, hemos creado un objeto nuevo: el objeto 30, con el tipo de dato int, nuestro recién alumbrado objeto reside en algún lugar recóndito, frío, oscuro y tenebroso de la memoria de Python, eso sí, con un identificador, id, único y exclusivo suyo que lo diferencia y distingue de cualquier otro objeto almacenado en ella. Contamos con la función id() para conocer el identificador (la matrícula, el DNI, el número de serie, o como nos lo queramos imaginar) de nuestro objeto.
BEJEQUE CRECIENDO SOBRE UNA GRIETA EN LA ROCA, BARRANCOS DE GÜÍMAR, CENTRO SUR DE TENERIFE. |
Lo singular del caso está en que si, por ejemplo, creáramos una variable a y le asignamos el valor de lista[4], esto es, 30, dicha variable a no sería más que una referencia a ese objeto en sí: una especie de puntero láser imaginario que dibuja un inquietante puntito rojo sobre el corazón mismo del objeto 30.
Y si ahora asignáramos a una variable b el valor de a obtendríamos el mismo id para ambas: a y b están en la misma dirección de memoria y no en direcciones distintas como sucede en otros lenguajes.
Si modificamos el valor de a, la variable continúa ocupando el mismo espacio de memoria, con una id distinta pues contamos con un objeto nuevo que requiere de su propio identificador exclusivo, y lo único que ha cambiado es su valor.
Aprovechando la condición mutable de las listas, contando con una misma lista de datos con dos variables distintas, si modificáramos directamente el objeto lista mediante la sustitución, por ejemplo, de uno cualquiera de sus ítems, comprobaremos que tanto una como otra variable continúan referenciando al mismo objeto lista. En el ejemplo anterior, con a = 45, que es un objeto de tipo int, se creó un nuevo objeto que, como era de prever, tendría una id distinta a la de b, pero en el caso de la lista que nos ocupa ahora, podemos modificar el objeto "sobre la marcha", haciendo uso de la condición mutable que poseen las listas.
Otra cosa muy distinta sería si hubiéramos procedido de la siguiente manera:
La diferencia estriba en que al modificar la lista mediante una asignación nueva que contiene una secuencia de datos con un ítem modificado, 12 en lugar de 8, con respecto al original, hemos creado en 'pares' un objeto list distinto al objeto list 'divx2' y, en consecuencia, ambas variables apuntan a objetos list diferentes, mientras que en el caso anterior, hemos modificado el objeto int 8 convirtiéndolo en el nuevo objeto int 12 sin haber tocado para nada las listas salvo por la llamada al índice (pares[3] = 12): hemos modificado directamente la lista `pares`sobre la marcha, actuando sobre ella. De esta manera, al no haber tocado a las listas en sí, aunque sí a sus ítems para modificarlos, ambos objetos devuelven el mismo resultado, son idénticos y responden al mismo id.
Vamos a considerar a continuación el siguiente caso:
Lo vemos claro, ¿verdad? Pongamos nuestra atención ahora en lo que ocurre cuando efectuamos una operación sobre la marcha actuando de manera directa sobre el objeto.
Lo que obtenemos como resultado es: lista1 = None.
Sucede con todos los ejemplos que hemos estudiado en este apartado que Python fue diseñado en su génesis de esta manera tan singular, tan "en la orilla opuesta" de lo que constituye el protocolo habitual en tantos lenguajes de programación, de tal modo que una operación, fuera cual fuere, si modificamos in situ un objeto, Python no devuelve ningún valor en tanto que contiene implícitamente el valor None.
Es por esta razón que la variable y no muestra ningún valor cuando se le llama, dado que su valor es None. El método list.reverse() ha funcionado en x pero no ha ocurrido igual en y. De esta manera, Python impide que se genere un previsible caos cuando codificamos operaciones que combinen modificaciones in situ con objetos que se crean nuevos, manteniendo un nivel adecuado de coherencia con respecto a la gestión de la memoria.
En el caso anterior obtenemos un resultado deseable procediendo de la forma siguiente:
Esto es, primero ejecutamos la inversión y luego realizamos la asignación y = x, después de que x haya sido modificada.
Para finalizar, regresando a nuestra sentencia del que encabeza esta entrada y de acuerdo a todo lo anterior, tenemos que aclarar que la mencionada sentencia, considerada como "destructor" de Python, sólo elimina la referencia al objeto que se aloja en un espacio de memoria interna concreto pero no exactamente al objeto en sí, salvo en el caso de que tan sólo exista una única referencia al objeto, en cuyo caso, el "recolector de basura" que tiene "asociado", al no poder ya nosotros por nuestra cuenta como programadores llamar al objeto porque carece de "nombre/referencia" que lo señale, elimina (ahora sí) al objeto y libera su espacio de memoria poniéndolo a disposición de un nuevo objeto que queramos almacenar en él, eso sí, con una nueva referencia.
Este proceso lo veremos mejor cuando estudiemos los MÉTODOS ESPECIALES en la Programación Orientada a Objetos. ¡Uy! Creo que me están llamando para sacarme de paseo... ¡Hasta otra!
LADERAS DE TENO EN LA VECINDAD DEL BARRANCO DE GUERGUES, NOROESTE DE TENERIFE. |
No hay comentarios:
Publicar un comentario