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.


No hay comentarios:

Publicar un comentario