miércoles, 30 de diciembre de 2015

T2 LOS MÉTODOS STR.MAKETRANS() Y STR.TRANSLATE(), DOS AMIGOS MUY BIEN AVENIDOS.

COSTA NORTE DE TENERIFE DESDE LAS LADERAS DE EL SAUZAL, CON EL ACANTILADO DE ACENTEJO AL FONDO
     Los métodos de las strings str.maketrans() y str.translate(), y por este orden, son interdependientes, conjugándose mutuamente para obtener un resultado. Con el primero, cuya traducción libre podría ser precísamente ésa, "hacer una traducción", podemos pasar dos argumentos en formato de tabla ("TABLE") aunque esto, salvo en el caso de que vayamos a hacer una traducción profunda, en toda regla, resulta muy laxo, como podremos ver en los ejemplos. En ambos casos deben ser cadenas de texto, strings, siendo el primero de los argumentos la cadena donde se encuentran los caracteres literarios que vamos a traducir; y el segundo, los caracteres literarios a los que deben traducirse los primeros. Contamos, además, con la opción de pasar un tercer argumento que nos permite eliminar caracteres si así lo deseamos. 
El primer y segundo argumento deben tener la misma longitud para que la traducción pueda llevarse felizmente a cabo, por lo que podemos recurrir a la función len() como controlador. El método str.translate(), "traducción" lleva como argumento al propio método str.maketrans(), por lo que conviene asignar siempre a este último una variable para volverlo más manejable, aplicándosele a la string sobre la que invoquemos el método str.translate(), devolviéndonos así la susodicha cadena con los caracteres literales modificados de acuerdo a nuestra propuesta de traducción.
En el caso de str.maketrans(), no introducimos una cadena concreta sino que, o bien dejamos una cadena vacía, " ",  o bien la llamamos por el nombre de tipo de objeto, str, dado que se trata de un método estático que funciona a partir de su condición como argumento de str.translate(), y de aquí que habláramos al comienzo de esta entrada de interdependencia entre ambos.
Para finalizar, en el caso de traducciones más complejas tenemos a nuestra disposición el módulo codecs de la librería estándar de Python.


Y ahora otro ejemplo con tercer argumento para str.maketrans():


VISTA DEL TEIDE DESDE EL MACIZO DE TENO,  PRÓXIMO AL BARRANCO DE GUERGUES, NOROESTE DE TENERIFE.



jueves, 24 de diciembre de 2015

T2. EL MÉTODO STR.FORMAT(*ARGS, **KWARGS) Y LA FUNCIÓN FORMAT() AL DESCUBIERTO.

PLAYA DE LA COSTA DE ABADES, CON ESTRUCTURAS EROSIONADAS POR EL VIENTO Y EL MAR SOBRE LOS RESTOS DE UNA PLAYA DE ARENISCA FÓSIL.

     Este método constituye en sí mismo una herramienta muy potente que Python pone a nuestra disposición para configurar formatos de salida de datos en forma de cadenas. Recordemos que su función es la devolver una cadena con una estructura nueva, diferente a la original, donde los campos de reemplazo son sustituidos por los argumentos que hayamos pasado. Mostramos un ejemplo:


Observemos como '*args' hace referencia a tipos de datos mientras que '**kwargs' hace referencia a keywords, palabras-clave que apuntan a otros tipos de datos, muchas veces, funciones. El asterisco en 'args' hace referencia a que admite diferentes tipos de datos, incluso, expresiones matemáticas: string, int, float, list,..., mientras que el doble asterisco en 'kwargs' refiere que la inclusión de keywords es opcional, pudiendo coexistir más de una keyword en el argumentado del método.
Veamos un par de ejemplos. En el último, introducimos un troceado (slicing) de una cadena. Como podemos comprobar, en todos los casos obtenemos resultados óptimos.



Cono ya sabemos, los campos de reemplazo se distinguen visualmente con llaves, {...}, siendo su nombre o identificación un número entero cuyo orden será correlativo a la posición (o índices) de los argumentos que pasemos a la función: {0} corresponde al primer argumento de la función, {1} al segundo, {3} al tercero, y así sucesivamente. Por cierto, si queremos incluir llaves en nuestro formato de salida tan sólo tenemos que duplicarlas. Tan sencillo como eso:



Una característica singular de los campos de reemplazo es su capacidad para adoptar diferentes sintaxis. 


La primera formulación sintáctica, como dejamos bien claro, es la más común y frecuente, mientras que las tres siguientes son formulaciones más técnicas que a tienden a:
  • CONVERSIÓN:  Cadena traducida a un esquema de codificación específico.
  • FORMATO:  Nombre del esquema de codificación (UTF-8, ASCII. LATIN-1, etc.) al que se ha traducido la cadena.
Los campos de reemplazo pueden estar anidados, es decir, que pueden contener a su vez otros campos de reemplazo, y éstos a su vez otros nuevos, y así sucesivamente, como si fueran muñecas rusas, para hacernos una idea, aunque los campos de reemplazo anidados no pueden contener especificaciones de formato. En virtud de la claridad del código es recomendable no recurrir a los anidamientos siempre que sea posible y, en todo caso, no exceder de dos o tres niveles de anidamiento.

 


   Si hacemos memoria y repasamos lo que hemos aprendido sobre las concatenaciones de las strings, recordaremos que no podemos concatenar una cadena con un entero. Sin embargo, podemos soslayar este 'inconveniente' mediante la función str.format(*args, **kwargs):


El método también nos permite concatenar strings pero para eso es mejor utilizar el método específico str.join(iterable) de las strings que va mucho mejor. ¿He dicho ya que me gustan las galletas?


VISTA DEL TEIDE TRAS EL MONTEVERDE Y EL PINAR,  DESDE LOS ALTOS DE LA CORONA, LOS REALEJOS
COMARCA DE LA ISLA BAJA, NORTE DE TENERIFE

      NOMBRES DE CAMPO

      Cuando hablamos de NOMBRES DE CAMPO nos estamos refiriendo a aquéllo que introducimos entre las llaves, que bien, como ya sabemos, puede ser un número entero o cadenas que apuntan a otra cadena u otro tipo de dato, 


Vemos cómo podemos utilizar palabras-clave (keywords) para manejar datos en el formateo final. Por ejemplo, en el primer caso, creamos una keyword que llamamos "nombre" y que, como es preceptivo, insertamos entre llaves, {nombre}, y le asignamos en la lista de argumentos el valor "Javier", que como podemos ver en el momento de ejecutarse el script, asume aquí la correspondiente traducción. Comprobamos también que en una misma cadena a formatear podemos incluir tanto argumentos posicionales como argumentos de palabra-clave aunque, eso sí: en el momento de pasar los argumentos a la función, los argumentos posicionales (args) van PRIMERO y los argumentos de palabra-clave(kwargs) van DESPUÉS
Hemos dicho que que podemos pasar listas (list) y diccionarios (dict) como "args" de la función str.format(*args, **kwargs). Cuando queramos llamar a alguno de los elementos de la lista lo identificamos por su índice para incluirlo en el campo de reemplazo. Veamos cómo hacemos esto:


Y para el caso de los diccionarios:


También Python nos facilita acceder a los atributos con nombre en str.format(*args, **kwargs). Vamos a verlo:


A modo de resumen, presentamos el siguiente esquema con las equivalencias entre argumentos posicionales y argumentos de palabras-clave:

SETA EN EL SOTOBOSQUE DEL MONTE DE AGUAGARCÍA, TACORONTE-EL SAUZAL, NORTE DE TENERIFE

       ESPECIFICADORES DE FORMATO

      La función principal de un ESPECIFICADOR DE FORMATO consiste en modificar a nuestra conveniencia el formato de salida de un script. Veamos un cuadro sintáctico basado en el que proporciona Mark Summerfield, en Pyhton 3, editorial ANAYA Multimedia, libro dedicado a la programación en Python, a un nivel medio-avanzado, cuya lectura recomendamos para reforzar nuestro aprendizaje al cabo de este manual (v. página dedicada al listado de links).


      CADENAS:

      Lo primero de todo, y de manera general tanto para cadenas, como para enteros y decimales, pasa por hacerle saber al intérprete de Python mediante la sintaxis pertinente de que vamos a hacer una especificación de formato con la inclusión de dos puntos, :, En el caso de las strings que nos ocupa , podremos controlar tres aspectos: el carácter (o los caracteres) de relleno, la alineación que queramos para el campo de reemplazo y sus anchuras máximas y mínimas.
Una vez hemos introducido los dos puntos preceptivos a la derecha del argumento posicional, podremos escribir, opcionalmente, un carácter (o varios) de relleno y un carácter de alineación que determinará su dirección adjuntando el signo correspondiente. A continuación podemos introducir un tipo de dato entero para determinar la anchura mínima de la cadena que nos devuelva la función. En el caso de que queramos hacer lo propio con la anchura máxima. colocaremos al final, tras un punto, un tipo de dato entero.
Proponemos una batería de ejemplos ilustrativos:



Es posible declarar un campo de reemplazo dentro de las propias especificaciones de formato. y ésto, además, lo podemos hacer de dos maneras distintas:



      ENTEROS:

      En su caso, la especificación de formato permite escoger el carácter (o caracteres) de relleno, un carácter de alineación que determinará la dirección a la derecha o a la izquierda, su signo, la anchura mínima que pueda tener el campo de reemplazo y, finalmente, la base (binaria, hexadecimal u octal).

PINARES EN LA CABECERA DEL
BARRANCO DE AÑAVINGO,
SUR DE TENERIFE

La especificación de formato de un tipo de dato entero, int,
igual que sucede con la especificación para las cadenas, comienza con los dos puntos obligatorios, a partir de los cuales podemos introducir, opcionalmente, un carácter (o caracteres) de relleno (ya sabemos que éste no puede ser {}), otro de alineación, un signo (con + se muestra obligatoriamente el entero con un espacio, mientras que con - se mostrará sólo si éste es negativo con el signo menos delante), un  entero  que determina la anchura mínima y que puede venir precedido por # para mostrarnos también el prefijo de la base, y por último, un valor 0 con el que obtendríamos un relleno con ceros.
Para el caso de las bases, podemos optar por una salida diferente a la base 10 estándar asociando los caracteres de tipo adecuados (=> binarios, x (minúscula) => hexadecimales, X  (mayúscula) => hexadecimales en mayúsculas, o => octales y d => valores enteros decimales). Terminamos con otros dos tipos de caracteres: c, que muestra los caracteres Unicode del valor entero sobre el que aplicamos el método, y n, que   devuelve al entero de acuerdo a su entorno.
Presentamos un esquema para verlo mejor:




Ejemplos de uso:


     NÚMEROS DE PUNTO FLOTANTE (FLOAT):

      En el caso de los floats podemos escoger el carácter (o caracteres) de relleno, la alineación que queramos darle al campo, el signo, su tamaño mínimo y una cantidad ponderada de dígitos decimales. a la derecha del punto, pudiendo elegir entre presentar el float bajo formato exponencial, estándar o porcentual. Su especificación de formato coincide con la de los valores enteros excepto por por dos puntos que vamos a considerar a continuación:
  1. Adicionalmente al tamaño mínimo que, reiteramos, es opcional, podemos determinar la cantidad de decimales a mostrar escribiendo un punto y un valor entero a continuación.
  2. Opcionalmente también, es posible añadir al final un carácter de tipo:
                 A) e/E => e para un formato exponencial en minúscula, y E para un formato exponencial en mayúsculas.
                 B) f => formato estándar de punto flotante.
                 C) g => formato "general", similar al anterior, salvo que la cifra fuera muy grande, en cuyo caso será similar a e.
                 D) G => formato similar a g pero que utiliza indistintamente a f o E.

Contamos también con con el signo %, por el que el número de punto flotante se multiplica por 100. El número resultante se mostrará en formato f asociado a un símbolo %


   Veamos un ejemplo con el carácter %:

                 
FINCA RÚSTICA DE PLATANERAS EN LA ZONA DE EL GUINCHO, ENTRE ICOD Y GARACHICO, NORTE DE TENERIFE

      LA FUNCIÓN format() PARA EL FORMATEO DE NÚMEROS... ¡SORPRESA!

     

      Sí, aunque parezca mentira con el tremendo empacho de cadenas que llevamos, existe en Python una función (no un método, ¡cuidado!, que es una función dependiente de una clase, como es el caso que hemos visto hasta ahora de str.format(), donde format() es el método y str la clase a la que pertenece) que se ocupa de formatear la salida de números: format().
Lo cierto es que apenas se utiliza y, de alguna manera, ha quedado inclusa en Python 3 como una suerte de reliquia binaria de tiempos pretéritos. Pero estar, está. Y funcionar, funciona. Así que hablaremos algo de ella porque siempre, uno no sabe cuándo, nos podría venir bien algún día.
Eso sí, la función format() devolverá siempre una string porque de casta le viene al galgo
Vemos primero una captura donde se muestra su argumentado:


      
Si observamos la especificación, comprobamos que Python nos devuelve (return) un valor (value) al que se le asignará el método especial __format__(), y ya veremos en su momento lo que son los métodos especiales, vinculados a la superclase predefinida object de Python, por la sintaxis del punto. pasándole como argumento un formato específico (format_spec).
Que nadie se acongoje: esto es mucho más sencillo de lo que parece, con tanto tecnicismo.
Veamos, por cierto, gráficamente, lo que acabamos de mencionar:


Es importante hacer notar que esto sucede a nivel interno, es decir, la propia función format() ya se encarga ella solita de hacer lo que debe, simplificando mucho trabajar con ella. Aún más, las especificaciones, realmente, son opcionales de tal modo que si pasamos como argumento de format() un número, entero, float, octal, hexadecimal, etc., la función se comportará exactamente igual que str(), devolviendo el mismo resultado, realizando conversiones automáticas a tipo de dato int o float y, a continuación, a cadena.


Vamos a ver a continuación los posibles argumentos que puede llevar la función format(), eso sí, si se insertan más de uno, respetando el orden que exige su sintaxis:



RETAMAS EN PROCESO DE FLORACIÓN. PARQUE NACIONAL DE LAS CAÑADAS DEL TEIDE.

      1.- [[fill]align]

   
     Este argumento, realmente, se divide en dos: un relleno (fill) con cualquier carácter válido en Python, y una alineación (align) que apunta si dicho relleno debe situarse a la izquierda (<), a la derecha (>), al centro (^), y el operador =, que asume un alineado por la derecha e interpola el carácter entre el signo que le hemos dado a nuestro número y el número en sí mismo.
El relleno más básico sólo requiere de un número pasado como string y se colocará siempre a la izquierda del valor en la devolución final:



Vemos a continuación un ejemplo con inclusiones más completas:


Veamos las concomitancias pero, a la vez, limitada flexibilidad del método tradicional str.format():


      2.- [sign]

   
     El segundo parámetro opcional refiere el signo, básicamente, + o - que queremos proporcionar al número y la manera de introducirlo, aunque en el caso de los números negativos, esto sólo será posible si el número ya es negativo. Además, si el número ya es negativo, seguirá siéndolo a pesar de que introduzcamos el signo +.
Por otra parte, si insertamos un único espacio en blanco (sólo uno, pues a partir de dos o más , Python lanza una excepción de tipo ValueError: Invalid format specifier) cuando el número es positivo, se aplica automáticamente dicho espacio a la izquierda del número. En el caso de que el número fuera negativo, no tendría mayor incidencia y devuelve el número tal cual.
En el caso de que combinemos relleno y signo. éste debe ir precediendo a la cantidad de relleno.


      3.- [#]

   
       El símbolo almohadilla apunta a los diferentes formatos numéricos que acepta Python con los que está trabajando. Sucintamente, "b", para binarios; "o", para octales y "x" para hexadecimales. Se admite también la opción "e" y "E" para mostrar la notación científica de un número.
Podemos insertar, dado un número decimal o de punto flotante, un punto seguido de una cifra para indicarle al intérprete de Python el número de decimales que queremos que se muestren. Si el número que pasamos tras el punto es igual o inferior a la parte entera del valor, devolverá la notación científica.
También podemos pasar un punto seguido de una cifra y la letra 'f'' para determinar el número de decimales que queremos mostrar y que, en caso de que fuera factible, efectuase un redondeo. La inserción de 'f' en solitario, "f", ejecuta un recorte automático y por defecto a seis decimales, y cuando el número de decimales del valor es inferior a 6, rellena los decimales faltantes hasta llegar a seis con ceros.


      4.- [0][width]

   
     Determina el espacio que media entre el inicio de la string, con la comilla de apertura, y el número, siempre de izquierda a derecha. Sólo podemos rellenar con 0; de resto, sólo se mostrará un espacio vacío. Veamos algunos ejemplos con cambios de tipo de números:


      5.- [,]

   
     Con este argumento opcional de format() podemos conseguir escribir miles en el formato europeo, donde los miles se representan con comas y los decimales con puntos.


      6.- [.precision]

   
     Con este nuevo parámetro precisamos la cantidad de números (dígitos) que se mostrarán tras el punto decimal, esto es, cuanto mayor sea el número de dígitos a la izquierda del punto mayor es la precisión global del valor. Si el dígito es mayor que el total de los decimales, se mostrarán todos los decimales sin añadir nada. Recordemos que con una cifra inferior, se muestra automáticamente la notación científica del valor.


      7.- [type]

   
     El último parámetro opcional de format(). Señala en qué tipo de dato se va a mostrar el valor cuando la función format() se ejecute. La devolución varía según sea un valor de tipo entero o un valor de tipo decimal. Veamos:


Finalizamos: No olvidemos que la función format() tiene sus concomitancias (equivalencias) en el método str.format(), donde ambos devuelven cadenas y resultados similares.

MONTEVERDE EN EL MONTE DEL AGUA, ERJOS, NOROESTE DE TENERIFE.


martes, 15 de diciembre de 2015

T1. LOS OPERADORES 'IN' E 'IS'. PERTENENCIA E IDENTIDAD.

A) OPERADOR IN:

CORTE DE ALMAGRE EN EL BARRANCO DE LEMES, ARICO, SUR DE TENERIFE

     Aprovechando que nos hemos dado de bruces con los booleanos, vamos a explicar un elemento más de Python: la propiedad IN. Es importante advertir que nos estamos refiriendo a in como tal, en solitario, y no asociada al iterador FOR (FOR/IN), que estudiaremos cuando hayamos concluido con los principales tipos de datos de Python, y cuyo significado particular, como no puede ser de otra manera, es el mismo en ambos casos: 'en'. 
IN se apoya en el tipo de dato booleano y nos resultará muy útil cuando, por ejemplo, estemos haciendo un listado "generoso" de ítems y no sepamos si hemos incluido en él un ítem concreto. Al usar in en una expresión referida a una variable que almacene una colección de datos, como una string, por ejemplo, que almacena una colección de caracteres literales, nos devolverá True si encuentra lo que le hemos pedido buscar, o False en caso de no encontrarlo. Su sintaxis es muy sencilla: ítem in nombre_de_la_variable.
He aquí un ejemplo de uso:


Hay quien también se refiere a in como 'verificador' en tanto en cuenta 'verifica' si tal o cual ítem está en una variable o no. Por otra parte, se cuentan autores que prefieren denominarlo OPERADOR DE PERTENENCIA. Se admiten propuestas...
También podemos escribir NOT IN, pasando la frase a negativo, poniendo el énfasis en "no estar",


Precisemos: el operador in busca substrings allí donde lo apliquemos y no coincidencias de caracteres literales: no sólo busca los caracteres coincidentes sino que lo hace también en el mismo orden. Y aún más: discierne entre mayúsculas y minúsculas. Pongamos un ejemplo:





ROQUE DE FUERA, ROQUES DE ANAGA, NORESTE DE TENERIFE


B) OPERADOR IS:

ROQUE DE TABORNO, ANAGA CENTRAL. EJEMPLO DE PITÓN (VOLCÁNICO)

      El objetivo del OPERADOR DE IDENTIDAD es el de comprobar si las dos referencias que se le pasan apuntan al mismo objeto, o cuando se le pasa una sola referencia ésta tiene valor None.
Trabaja como un operador booleano que se aplica a las variables y no a datos o valores, ya que para comparar estos ya contamos con los operadores de comparación (v. tabla).
Partiendo de la base de que las variables, como ya sabemos, son referencias a objetos, cabe preguntarse si existen una o más referencias que apunten a un mismo objeto o, para ser más exactos, que un mismo objeto, por ejemplo, una string, esté almacenado en más de un único espacio de memoria referenciado por un nombre que lo identifique (variable).
La aplicación del operador devuelve True si la variable de la izquierda refiere al mismo objeto que refiere la variable de la derecha, devolviendo False en caso contrario.
Igual que sucede con el operador de pertenencia, el operador de identidad soporta su propia negación, su lectura inversa, con la adición de la keyword not.


En este ejemplo podemos observar perfectamente su comportamiento. Sin embargo, en LISTA [...] y en TUPLA (...) comprobamos un comportamiento anómalo: dos listas y dos tupla exactamente iguales y la aplicación del operador de identidad nos devuelve False en lugar de True. ¿Por qué ha ocurrido esto? Muy sencillo: porque las listas, las tuplas y algunos objetos más de Python se almacenan por defecto en objetos de lista (objetos de tupla, en el segundo caso) distintos.
Cuentan con la ventaja de operar con celeridad ya que no comparan objetos entre sí, como sí hacen los operadores de comparación, sino espacios de memoria. Suelen, como hemos dicho más arriba, emplearse para comparar un objeto concreto con el tipo de dato None, susceptible de ser utilizado como VALOR DE MARCADO para señalar que una variable no tiene valor o dato alguno guardado, o que dicho dato o valor es desconocido.


Resumiendo: no debemos comparar ni objetos (list is list [True], tuple is not tuple [False]) ni valores de una variable porque resultan una obviedad, una redundancia, que desde el punto de vista de la programación carece de sentido.
El uso correcto del verificador se orienta a las variables que señalan objetos, básicamente, para comprobar si dos variables distintas refieren a un mismo objeto o no.


1.- La variable no es una lista: una variable es una variable.
2.- He aquí la comprobación.
3.- Evidente: una lista no es una tupla.
4.- Tenemos dos conjuntos distintos, exactamente con los mismos ítems, sí, pero son dos conjuntos distintos: a uno lo hemos llamado c y al otro g. Por ese motivo operar cambios en c no suscitará un cambio especular en g.
5.- Las cadenas, sin embargo, sí son idénticas entre sí a pesar de tener dos nombres distintos. Ésta condición de similitud absoluta le es reconocido por Python por su literalidad (estar entrecomilladas) y no por su inmutabilidad: a = (1,2,3), b = (1,2,3) => a is b => False. Tiene que ver con la imposibilidad de ser desordenadas (su inmutabilidad): se trata de una colección o secuencia de datos que no podemos desordenar sin cambiar con ello su propia naturaleza. Por ejemplo, "amor" no es lo mismo que "roma", aunque contengan las mismas letras y su tamaño fuera similar: son dos conceptos distintos; pero en dos listas, pongamos por caso, como a = [1,2,3] y b = [3,1,2], el orden en que se muestren sus valores no afecta a su posterior funcionalidad: su significado es el mismo.
6.- Dos listas con idénticos ítems pero con dos nombres de variables distintos. Un caso similar a 4.
7.- Igualar una variable a otra implica automáticamente la  identidad absoluta entre ambas variables.
8.- Como ya sabemos, el método list.copy() devuelve una copia exacta de la variable, pero como ocurre con a y e, se trata de dos listas independientes la una de la otra.
9.- El objeto al que apunta el nombre de variable f no es una string: es, precisamente, eso, una variable.
10.- Confirmación de lo antedicho.

Mostramos a continuación una pequeña tabla que explicita dos aspectos básicos de los operadores de pertenencia e identidad:



Vamos a ver la diferencia que existe entre la declaración o expresión is en relación con el operador de comparación ==. Así nos aclararemos entre qué significan que dos variables apunten a un mismo objeto o que apunten a un mismo tipo de dato aún siendo similares los valores:



Obvia decir que lo mismo podemos hacer pasando la expresión a negativo (not is) y el operador de comparación a "distinto" (!=).

TRIGALES EN LOS REALEJOS, NORTE DE TENERIFE