LISTAS I

VISTA DEL PALMERAL DEL BARRANCO DE MASCA, MACIZO DE TENO, NOROESTE DE TENERIFE.
      Comencemos por dar una definición del tipo de dato list, lista, para hacernos una idea de lo que significa este nuevo objeto de Python. El objeto lista es una secuencia (v. entrada correspondiente) ordenada de ninguna (lista vacía) o más 'referencias de objetos' (variables que apuntan a otros objetos de Python: enteros, decimales, cadenas, tuplas, otras listas, etc.). Se caracterizan por ser mutables (esto es, que  puede modificar su contenido con el concurso de métodos preconstruidos), iterables (que puede ser recorrida  en orden de principio a fin por un bucle for/in), más versátiles que las tuplas que estudiaremos en el apartado siguiente y, al contrario que éstas últimas, más homogéneas que heterogéneas, es decir, proclives a contener elementos, datos, ítems o como prefiramos llamarlos del mismo tipo de dato.
Todos los lenguajes de programación deben trabajar con colecciones de datos a los que cada cual significa con su propia nomenclatura: matrices, arrays, etc. En el caso de Python, el tipo de dato principal que atiende a esta necesidad es el tipo list.
En una lista, realmente, se generan varios espacios de memoria correlativos (salvo, claro está, en una lista vacía, esto es, una lista que se declara sin contener todavía ningún elemento y que ya veremos más adelante), tantos como elementos/ítems/datos contenga, pero que funcionan en primera instancia como una unidad (el objeto de tipo list que acabamos de construir), de tal modo que el nombre de variable que le hemos dado a la lista "actúa" como si fuera un espacio único de memoria que engloba a todos los sendos "subespacios" de memoria que se han generado por elemento.
Este concepto es extensible a cualquier colección de datos.





HAY QUIENES SOSTIENEN QUE LAS LISTAS SON, EN REALIDAD, EL ALMA DE PYTHON, SU ESENCIA MISMA COMO LENGUAJE.



Quizás lo que más nos extrañe de esta definición sea el concepto de 'referencias de objetos'. Y es que la cosa tiene su aquél. Vaya por delante que es casi un tecnicismo, que en cuanto a funcionalidad, prácticamente, ni nos va ni nos viene. aunque bien es cierto que en niveles bastante más avanzados de programación conviene tenerlo en cuenta. Así que, como el conocer un poquito mejor las neuras de Python nunca está de más, pasamos a desarrollar un poco el asunto, lo justo, vamos.
Cuando se crea una lista o una tupla, pongamos por caso, ni una ni otra almacenan en memoria los distintos objetos (strings, ints, floats, ...) que integran la colección. Lo que realmente ocurre es que Python, de manera automática, en cuanto se declara una lista, realiza una copia de cada objeto (o de las variables que los refieran). Y es esa copia y no el objeto en sí lo que se "coloca" en esa lista o en esa tupla que hemos creado. Es por eso que cuando se elimina, por ejemplo, un ítem o elemento de una lista, lo que realmente se elimina es la copia, esa "referencia al objeto", que desaparece de manera total y, sin embargo, el objeto en sí, el real, el auténtico, el objeto referenciado es enviado a la basura, donde se almacena, y de donde es posible recuperarlo aún: la referencia al objeto se elimina completamente de la memoria pero el objeto "real" va a la basura.
Comprenderemos un poco mejor el proceso cuando hablemos de la sentencia del.
Podemos establecer una cierta analogía con la 'papelera'  de los sistemas operativos: cuando enviamos un archivo a la papelera y clicamos sobre "eliminar" o similares, éste desaparece de nuestro escritorio y/o de nuestra/s carpeta/s, de manera que ya no podemos acceder directamente a él. ¿Pero ha sido realmente eliminado del todo? ¡No! Sigue ocupando en memoria el mismo espacio que ha estado ocupando hasta ahora, solo que la GPU dicta que ese mismo espacio de memoria queda desde entonces habilitado para ser sobrescrito por cualquier otro archivo que queramos guardar. Por eso mismo, igual que sucede con los objetos de las listas que hemos "eliminado", esos archivos son recuperables total o parcialmente por programas de recuperación de datos. Recapitulemos: lo que se ha borrado (o añadido, por ejemplo, si se ha sumado otro objeto a la lista) es la copia, la referencia al objeto, y esta sí que es irrecuperable una vez se elimina, mientras que el objeto en sí al que referencia, es enviado a la basura desde donde aún es posible recuperarlo.



Después de esta pequeña disgresión, recuperamos el tema de las listas al nivel que, por ahora, nos interesa.
Las listas pueden crearse invocando a una función predefinida, como invocábamos a la función set() para crear un conjunto. En este caso, la función es list(), que acepta un único argumento:



Analicemos nuestro ejemplo:
1. Creamos una variable usando 'a' como identificador. A esta variable le asignamos una colección de objetos (strings, ints, floats, y hasta un set y todo) separados por comas.
2. Le pasamos la función type() a  'a' y Python nos dice que la variable almacena una tuple, tupla, cosa que nos confirma cuando le pedimos que nos muestre 'a'. Efectivamente, en 3. se nos devuelven los valores entre paréntesis que, como ya veremos, determina gráficamente  a una colección de datos cualquiera como una tupla. IMPORTANTE: Python, por defecto, ante una colección o seriación de objetos tal y como se muestra en 1., de manera automática, categoriza a la variable que los contiene como una tupla.
Pero como nosotros queremos una lista y no una tupla, le pasamos en 4. la función list() a 'a', obteniendo, efectivamente, una lista con su sintaxis básica de encerrar los objetos de la secuencia entre corchetes.
Sin embargo, al pedir de nuevo el tipo de 'a', tal y como hacemos en 5., Python nos sigue diciendo que 'a' es una tupla. Una especie de conversión puntual que desaparece con el siguiente prompt.
De la misma manera que si queremos guardar un dato en memoria y poderlo recuperar más adelante necesitamos asignarlo a una variable, para conseguir que esta conversión de tupla a lista se troque permanente procedemos como en 6., usando el mismo identificador de variable que pasamos como argumento a list() para asignarle la función list(a). Y ya lo tenemos: en 7. podemos comprobar cómo ahora la variable 'a' identifica a una lista y no a una tupla.

MESA DE EL CONDE O DE ICHASAGUA DESDE EL PIE DE LA PICA DE IMOQUE, PITÓN VOLCÁNICO DE LAS MEDIANÍAS DE ARONA, SUR DE TENERIFE.

A esta función list(), en el caso de que no le pasáramos argumento alguno, nos devuelve una lista vacía (vienen bien para, por ejemplo, ir almacenando en ella valores que desconocemos a priori: respuestas del usuario, resultados de la aplicación de fórmulas científicas, variables estadísticas según se vayan obteniendo, e infinidad de cosas más); con un argumento, tal y como hemos visto en el ejemplo anterior, nos devuelve una lista con una copia simple del argumento (lo ocurrido en el punto 4. de nuestro ejemplo); y si le pasamos como argumento otro tipo de secuencia tratará de convertirlo en lista.
También podemos crear una lista directamente encapsulando una serie de objetos entre corchetes separados por comas unos de otros. ¿Recordamos que hacíamos lo propio encerrando objetos entre llaves y, cómo no, separándolos por comas para crear conjuntos? Igual que sucedía con los conjuntos, es la manera más segura de construir una lista.



En este ejemplo, x, y y z son listas homogéneas dado que todos los elementos son del mismo tipo(x, ints; y, strings; z, floats). La variable w acoge una lista heterogénea que aglutina una string, un int, un float y una tupla que, a su vez, contiene tres objetos de tipo string: "a", "b" y "c". Finalmente h es  una lista que no contiene valores sino variables: x, y, z y w que señalan a las cuatro listas que acabamos de construir, es decir, una lista de listas. Esto es, precísamente , a lo que se conoce como LISTAS ANIDADAS, donde una lista a puede contener varias listas; y éstas, a su vez, todas o algunas, pueden contener a su vez listas (2º nivel); y éstas a su vez, todas o algunas, pueden contener a su vez listas (3º nivel); etcétera.
Podemos crear una lista vacía no poniendo elemento alguno entre los corchetes, o con todos los objetos que queramos, de uno sólo en adelante, eso sí todos ellos separados por comas, como reflejan los ejemplos.
Las listas, como secuencias que son, son susceptibles de compararse empleando los consabidos operadores de comparación. Veámoslo:



Recordemos una vez más que que una secuencia es mutable en tanto en cuanto sus elementos pueden ser indexados, esto es, llamados por sus índices. Aquí mostramos un ejemplo ilustrativo:



Analizando el ejemplo tenemos en 1. que la comparación de igualdad nos devuelve False. ¿Por qué sucede esto si sabemos que el resultado de aplicar el indexado nos devuelve, efectivamente, un float y una string? Porque, basándonos en el primer caso, lista[3] no es un tipo de dato sino un dato en sí mismo: es decir, compara un dato con un tipo de dato. Obviamente, el resultado es False. Si en su lugar hubiéramos construido esta comparación: list[3] == 0.09, nos hubiera devuelto True, ya que comparamos dos datos entre sí.
En 2. podemos ver una especie de "escalado" o "cascada" de indexado. Comenzamos por el índice [2] que nos devuelve una lista; en la siguiente línea de código probamos a poner dos índices juntos: el primero, [2], nos devolvería la lista de antes, mientras que el segundo, [-1], señala al elemento que ocupa esa posición en esa misma lista, "roma"; pero si aún interponemos un tercer índice, [2], éste se aplica a la string "roma" y nos devuelve la letra "m".
En 3. provocamos una excepción. ¿Por qué? Porque como ya sabemos, los conjuntos no son secuencias y, por consiguiente, tampoco soportan indexado.
Finalmente, en 4. trabajamos con una rebanada, slice (recordemos aquí que todo objeto que soporta indexado, también soporta slicing), y un índice, combinándolos para obtener un resultado.
¿A que no parece tan complicado?

FACHADA PRINCIPAL, EJEMPLO DEL NEOCLÁSICO CANARIO, DEL PALACIO DEL OBISPADO EN LA CIUDAD PATRIMONIO HISTÓRICO DE LA HUMANIDAD DE SAN CRISTÓBAL DE LA LAGUNA.

Además, como no puede ser de otra manera dada su condición de mutable, los índices nos pueden resultar útiles para cambiar unos ítems por otros:



Observemos cómo resolvemos el problema que nos plantea indexar con rebanadas y utilizarlas para sustituir elementos de una lista. Ahora ya podemos hacerlo con la sintaxis que mostramos a continuación. Y no sólo eso, sino que también nos permite eliminar ítems e, incluso, vaciar la lista por completo.



      TENGAMOS EN CUENTA QUE EL ÍNDICE FINAL DE UNA REBANADA (SLICE) COINCIDE CON LA LONGITUD DE LA LISTA QUE SE NOS DEVUELVA, ESTO ES, QUE EL NÚMERO DE ELEMENTOS DE LA LISTA RESULTANTE (len(rebanada)) COINCIDE CON EL VALOR DEL ÍNDICE FINAL: len(rebanada) = ÍNDICE FINAL DE LA REBANADA.


Las listas también pueden concatenarse, como las cadenas, usando el operador +. También podemos usar el operador +=, que sumará todos los elementos que se encuentren a la derecha del operador. Y lo mismo sucede con la multiplicación a través del operador *.



Notemos como en 1. el resultado de utilizar el operador + y el operador += no es el mismo: con el operador + obtenemos una concatenación estándar, conocida y previsible con lo que hasta ahora hemos estudiado. Sin embargo, con el operador += obtenemos una lista a a la que se ha añadido como ítems las listas b y c. Tengámoslo en cuenta cuando optemos por utilizar un operador u otro.
En 2. obtenemos una tupla (reiteramos una vez más que Python procede así por defecto) que contiene la lista b y una nueva lista c que pasa a ser el resultado de multiplicarse a sí misma por dos (duplicado).
Si en lugar de una tupla quisiéramos obtener una lista, como en 3., debemos asignar la expresión a una variable y luego pasar ésta como argumento de la función conversora predefinida list().
Como ya sabemos en relación a las secuencias, las listas soportan el operador de verificación o pertenencia in/not in, así como el recurso a la función len() en tanto que, como secuencias que son, insistimos, tienen tamaño, un tamaño perfectamente mensurable como podemos comprobar en el siguiente ejemplo:






   
   
       Os lo resumo en un par de ladridos desde la terraza de casa donde tomo el solecito: las listas, list, admiten indexado y slicing, esto es, hacer rebanadas; verificación de elementos a través de los operadores in y not in; la identidad mediante los operadores is e is not; la longitud o tamaño mediante la función len(); las funciones min(), max() y sum(). Finalmente, los ítems de una lista pueden repetirse sin ningún tipo de restricción.




BOSQUE Y SOTOBOSQUE DE PINAR Y MONTEVERDE EN LAS PORTELAS, EN EL MACIZO DE ANAGA, NOROESTE DE TENERIFE.



6 comentarios:

  1. Muy claras tus explicaciones. Gracias.

    ResponderEliminar
  2. Gracias a ti. Comentarios como el tuyo nos animan a seguir en la brecha. Esperamos seguir sirviéndote de ayuda. Saludos.

    ResponderEliminar
  3. POR QUE NO ME ALMACENA NUEVAS COMPONENTES?

    ResponderEliminar
  4. Buenas tardes, desconocido/a. Como ve, su código no lo muestro aquí porque resulta demasiado largo y farragoso. Por esa razón (y otras) recomiendo que las preguntas sobre códigos se remitan a los espacios web destinados para tal fin, como stackoverflow en español, y no en un blog de contenidos.
    Sobre lo que pregunta, lo mejor es ofrecerle una variante de su código conservando todo lo posible del original que Ud. me ha remitido, con algunas explicaciones, y mostrar el resultado final:

    while True:
    data = []
    N = ""; A = ""; F = ""; S = ""; C = ""; E = ""; T = ""; D = ""
    Pregunta = input("¿Quiere añadir datos personales?: ")
    if Pregunta == "sí":
    N = input("El nombre a añadir es: ")
    A = input("Ingrese un apellido: ")
    F = input("Ingrese su fecha de cumpleaños: ")
    S = input("Ingrese su sexo (1 para masculino, 2 para femenino ó 3 para otro): ")
    if S == '3':
    print("Su sexo es indefinido")
    elif S == '1':
    print("Su sexo es masculino")
    elif S == '2':
    print("Su sexo es femenino")
    else:
    print("Seleccione una opción correcta")
    C = input("Ingrese su correo electrónico: ")
    try:
    D = int(input("Ingrese su edad: "))
    except ValueError:
    print("Debe escribir un número")
    if D < 0:
    print("Por favor la edad debe ser positiva")
    continue
    try:
    E = int(input("Ingrese su cedula: "))
    except ValueError:
    print("Debe escribir un numero")
    if E < 0:
    print("Por favor la cédula debe ser positiva")
    continue
    try:
    T = int(input("Ingrese su número telefónico: "))
    except ValueError:
    print("Debe escribir un número")
    if T < 0:
    print("Por favor su número debe ser positivo")
    continue
    W = [N, A, F, S, C, E, T, D]
    data.append(W)

    ResponderEliminar
  5. A continuación, sigue el siguiente código:

    newinfo = input("¿Desea ingresar nueva información? (s/n): ")
    while newinfo == "s" or newinfo == "S":
    N = input("El nombre a añadir es: ")
    A = input("Ingrese un apellido: ")
    F = input("Ingrese su fecha de cumpleaños: ")
    S = input("Ingrese su sexo (1 para masculino, 2 para femenino ó 3 para otro): ")
    if S == '3':
    print("Su sexo es indefinido")
    elif S == '1':
    print("Su sexo es masculino")
    elif S == '2':
    print("Su sexo es femenino")
    else:
    print("Seleccione una opción correcta")
    C = input("Ingrese su correo electrónico: ")
    try:
    D = int(input("Ingrese su edad: "))
    except ValueError:
    print("Debe escribir un número")
    if D < 0:
    print("Por favor la edad debe ser positiva")
    continue
    try:
    E = int(input("Ingrese su cedula: "))
    except ValueError:
    print("Debe escribir un numero")
    if E < 0:
    print("Por favor la cédula debe ser positiva")
    continue
    try:
    T = int(input("Ingrese su número telefónico: "))
    except ValueError:
    print("Debe escribir un número")
    if T < 0:
    print("Por favor su número debe ser positivo")
    continue
    W = [N, A, F, S, C, E, T, D]
    data.append(W)
    newinfo = input("¿Desea ingresar nueva información? (s/n): ")
    if newinfo == "n" or newinfo == "N":
    pass
    for i in data:
    print("NOMBRE: ", i[0])
    print("APELLIDO: ", i[1])
    print("CUMPLEAÑOS: ", i[2])
    print("SEXO: ", i[3])
    print("CORREO: ", i[4])
    print("CÉDULA: ", i[5])
    print("TELÉFONO: ", i[6])
    print("EDAD: ", i[7])
    print("····························································")
    print ("Gracias por utilizar el programa")
    break

    ResponderEliminar
  6. Debe tener en cuenta las indentaciones (sangrías) que el corrector del blog no permite hacer (por eso, insisto, las preguntas de código a stackoverflow en español, o similares).
    A continuación, muestro el resultado de la ejecución del código anterior:

    ¿Quiere añadir datos personales?: sí
    El nombre a añadir es: Ana
    Ingrese un apellido: López
    Ingrese su fecha de cumpleaños: 12/12/2000
    Ingrese su sexo (1 para masculino, 2 para femenino ó 3 para otro): 2
    Su sexo es femenino
    Ingrese su correo electrónico: analopez@infomail.com
    Ingrese su edad: 20
    Ingrese su cedula: 12345
    Ingrese su número telefónico: 555555555
    ¿Desea ingresar nueva información? (s/n): s
    El nombre a añadir es: Juan
    Ingrese un apellido: Gómez
    Ingrese su fecha de cumpleaños: 10/10/2000
    Ingrese su sexo (1 para masculino, 2 para femenino ó 3 para otro): 1
    Su sexo es masculino
    Ingrese su correo electrónico: juangomez@infomail.com
    Ingrese su edad: 21
    Ingrese su cedula: 78900
    Ingrese su número telefónico: 111111111
    ¿Desea ingresar nueva información? (s/n): n
    NOMBRE: Ana
    APELLIDO: López
    CUMPLEAÑOS: 12/12/2000
    SEXO: 2
    CORREO: analopez@infomail.com
    CÉDULA: 12345
    TELÉFONO: 555555555
    EDAD: 20
    ····························································
    NOMBRE: Juan
    APELLIDO: Gómez
    CUMPLEAÑOS: 10/10/2000
    SEXO: 1
    CORREO: juangomez@infomail.com
    CÉDULA: 78900
    TELÉFONO: 111111111
    EDAD: 21
    ····························································
    Gracias por utilizar el programa

    Espero haberle servido de ayuda. Saludos.

    ResponderEliminar