viernes, 11 de marzo de 2022

Clase para el manejo de textos escrita en Python

Clase para el manejo de textos

Clase para el manejo de textos escrita en Python. Esta clase contiene métodos útiles que podrás utilizar en tus proyectos. Puedes usarla mediante herencia o directamente como Text.method ya que todos sus métodos están a nivel de clase.

Listado de paises, código y nombre para un proyecto en Python.

 Listado de paises. El código para cada pais en una variable única, y un listado de items (código y nombre) de paises que podrias utilizar en un select input con Django.

lunes, 6 de septiembre de 2021

Javascript: Comprobar si un objeto está vacio.

¿Cómo saber si un objeto en Javascript está vacio o no?

En Python, por ejemplo, la evaluación de un diccionario o lista  que estén vacios (sin contenido), retornará un valor falso.

bool({}) # Retornará False.
bool([]) # Retornará False.

Pero en Javascript es diferente. La evaluación siguiente retornará un valor verdadero, aunque el objeto esté vacio:

// Creamos un objeto y su contenido.
var obj1 = {nombre"limón"color"verde"}

// Creamos un objeto vacio.
var obj2 = {}

// Confirmamos la existencia del objeto 1, y es verdadera.
if (obj1) {
  console.log("El objeto 1 existe, y tiene contenido.");
}

// Confirmamos la existencia del objeto 2, y también es verdadera.
if (obj2) {
  console.log("El objeto 2 también existe, pero está vacio.")
}

La ejecución del código anterior producirá la siguiente salida:

[LOG]: "El objeto 1 existe, y tiene contenido." 

[LOG]: "El objeto 2 también existe, pero está vacio." 

Pero lo que necesitamos es comprobar si un objeto está o no vacio. La siguiente función te podrá ayudar, incluso sin saber si el "objeto" a evaluar es realmente un objeto, porque lo que necesitas saber es:

  1. Si es un objeto.
  2. Si tiene valor.

/**
 * Confirma si un objeto existe y tiene valor.
 * @param obj Objeto a evaluar. Puede ser cualquier tipo.
 * @returns Retorna true si el objeto existe y no está vacio, false todo lo contrario.
 */
function isObject(obj) {
    if (obj == undefined || !obj) {
        return false;
    }
    try {
        if (Object.keys(obj).length) {
            return true;
        }
        else {
            return false;
        }
    }
    catch (error) {
        return false;
    }
}

martes, 29 de junio de 2021

Python: Hola Mundo con Kivy


Kivy es una biblioteca de Python de código abierto para el desarrollo rápido de aplicaciones que utilizan interfaces de usuario innovadoras, como aplicaciones multitáctiles.

Hola Mundo con Kivy

Instalación de Kivy

pip install kivy


Código fuente

Creamos un archivo con la extención .py con el siguiente contenido:


import kivy 

# Para crear una interfaz de usuario necesitamos 
# importar el módulo de la aplicación Kivy:
from kivy.app import App

# Importamos una etiqueta con la que 
# mostraremos el texto "Hola Mundo".
from kivy.uix.label import Label

# Cambie esto a su versión de Kivy instalada.
kivy.require("2.0.0")


# Esta es la clase principal de nuestra aplicación. 
# Aquí se construirá la ventanda con una etiqueta 
# con el texto "Hola Mundo".
class HelloWorldKivyApp(App):

    # Método que retorna el widget raiz.
    def build(self):

        # La etiqueta con el texto "Hola Mundo" es 
        # retornada como widget raiz.
        return Label(text="Hello World")


# Aquí es inicializada nuestra clase y el método 
# run es llamado, iniciando así nuestra aplicación.
HelloWorldKivyApp().run()


Ejecutamos nuestro código:

python [nombredetuarchivo].py


¡Y listo!


domingo, 27 de junio de 2021

Python Decimal vs float

Cuando trabajamos con números decimales en Python generalmente recurrimos a la clase interna float, y es que además, cuando escribimos el número flotante de manera literal, Python nos devuelve un objecto de tipo float en vez de un objecto de tipo Decimal. Esto nos va a funcionar para la mayoría de los casos, pero los números float tienen limitaciones que podrían ser problemáticas para otros casos de uso. Simplemente no son lo suficientemente precisos.

Decimal vs flotante en Python

El problema de la aritmética de Punto Flotante

Los números de punto flotante se representan en el hardware de la computadora en fracciones en base 2 (binario). Por ejemplo, la fracción decimal

0.125

…tiene el valor 1/10 + 2/100 + 5/1000, y de la misma manera la fracción binaria

0.001

…tiene el valor 0/2 + 0/4 + 1/8. Estas dos fracciones tienen valores idénticos, la única diferencia real es que la primera está escrita en notación fraccional en base 10 y la segunda en base 2.

Lamentablemente, la mayoría de las fracciones decimales no pueden representarse exactamente como fracciones binarias. Como consecuencia, en general los números de punto flotante decimal que ingresas en tu computador son sólo aproximados por los números de punto flotante binario que realmente se guardan en la máquina.

El problema es más fácil de entender primero en base 10. Considerá la fracción 1/3. Podés aproximarla como una fracción de base 10

0.3

…o, mejor,

0.33

…o, mejor,

0.333

…y así. No importa cuantos dígitos desees escribir, el resultado nunca será exactamente 1/3, pero será una aproximación cada vez mejor de 1/3.

De la misma manera, no importa cuantos dígitos en base 2 quieras usar, el valor decimal 0.1 no puede representarse exactamente como una fracción en base 2. En base 2, 1/10 es la siguiente fracción que se repite infinitamente:

0.0001100110011001100110011001100110011001100110011...

La mayoría de los usuarios no son conscientes de esta aproximación por la forma en que se muestran los valores. Python solamente muestra una aproximación decimal al valor verdadero decimal de la aproximación binaria almacenada por la máquina. En la mayoría de las máquinas, si Python fuera a imprimir el verdadero valor decimal de la aproximación binaria almacenada para 0.1, debería mostrar

>>> print(f"{0.1:.55f}")
0.1000000000000000055511151231257827021181583404541015625

Esos son más dígitos que lo que la mayoría de la gente encuentra útil, por lo que Python mantiene manejable la cantidad de dígitos al mostrar en su lugar un valor redondeado.

Un problema práctico

Tenemos los siguientes números:

a = 10
b = a / 77
c = b * 77

en el ejemplo anterior, a debería ser igual a c, pero no lo es ya que sus valores son los siguientes:
a = 10
b = 0.12987012987012986 
c = 9.999999999999998

El módulo decimal

Afortunadamente Python tiene otra forma de lidiar con los números decimales, que es el módulo decimal. A diferencia de los flotantes, los objectos Decimal definidos en el módulo decimal no son propensos a esta pérdida de precisión, porque no se basan en fracciones binarias.

from decimal import Decimal

>>> Decimal(0.1)

0.1000000000000000055511151231257827021181583404541015625

¡Ups! En el ejemplo anterior hemos obtenido un número con toda la impresición del float. Esto se debe a que Python primero evaluó el flotante 0.1, de modo que el valor que estuvo obteniendo el objeto Decimal en realidad fue este

Decimal(0.1000000000000000055511151231257827021181583404541015625)

La manera correcta de hacer esto es pasandole una representación, del  número que queremos utilizar, en string.

>>> n = Decimal("0.1")

>>> f"{n:.60f}"

'0.100000000000000000000000000000000000000000000000000000000000'


>>> n = Decimal(str(0.1))

>>> f"{n:.60f}"

'0.100000000000000000000000000000000000000000000000000000000000'


¡Problema resuelto!


Si quieres saber más sobre este tema te recomiendo 

decimal- Aritmética decimal de coma fija y coma flotante

Decimal vs float in Python



sábado, 30 de enero de 2021

Javascript: Convertir un número a formato de miles separado por coma.

Función Javascript para convertir un número a un string con formato de división de miles separado por coma.

/**
* Convierte un número a número de tipo string de división de miles separado por coma.
* @param {number} num Número que se desea convertir.
* @param {number} decimal_places Cantidad de decimales (default=2).
* @returns {string}
*/
function intcomma(num, decimal_places=2) {
try {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
} catch (error) {
return num;
}
}

jueves, 24 de diciembre de 2020

¿Cómo generar backups Django desde archivo Python?


 A continuación el código para generar nuestros backups en Django. Lo incluimos en una tarea automatizada para que el código se ejecute automáticamente cada cierto tiempo. Es necesario que el código sea ejecutado en nuestro entorno virtual.

Para ello hacemos uso de la librería pathlib, útil para trabajar con rutas de archivos y directorios. Ofrece un sin número de método adecuados a la plataforma. Según su documentación, este módulo ofrece clases que representan rutas del sistema de archivos con semántica apropiada para diferentes sistemas operativos. Las clases de ruta se dividen entre rutas puras , que proporcionan operaciones puramente computacionales sin E/S, y rutas concretas , que heredan de rutas puras pero también proporcionan operaciones de E/S.

Y también de hacemos uso de la librería zipfile para comprimir nuestros backups en archivos .zip.


import os
import datetime


from pathlib import Path # https://docs.python.org/3/library/pathlib.html
from zipfile import ZipFile # https://docs.python.org/3/library/zipfile.html


# Importamos los settings de nuestro proyecto.
from app.settings import (setting1, setting2, setting3)

SETTINGS = (setting1, setting2, setting3)

# Directorio donde serán almacenados las copias de seguridad.
BACKUP_DIR_NAME = Path(__file__).resolve().parent.parent / "backups"

# Sufijo que tendrá el nombre del archivo generado Ej. nombre_20201224.zip
FILE_SUFFIX_DATE_FORMAT = "%Y%m%d"

# Cantidad de días que durará una copia de seguridad
# almacenada antes de proceder a borrarla automáticamente.
DAYS_TO_KEEP_BACKUP = 3

# Usaremos esta fecha para comparar los archivos antiguos que serán eliminados.
back_date = datetime.datetime.now() - datetime.timedelta(days=DAYS_TO_KEEP_BACKUP)
back_date = back_date.strftime(FILE_SUFFIX_DATE_FORMAT)


# Eliminamos primero para asegurarnos de que casi siempre haya
# espacio disponible para los nuevos backups que serán creados.

for setting in SETTINGS:
path = BACKUP_DIR_NAME

    # Suponiendo hemos creado una variable NAME en cada uno de nuestros setting
prefix = setting.NAME + "_"

# Listamos los archivos dentro del directorio donde se guardan los backups.
list_files = path.iterdir()

for f in list_files:
if f.suffix.lower() == ".zip":

try:
suffix = f.name.split("_")[1].split(".")[0]
except (IndexError):
# Si el archivo no tiene la estructura 'name_%Y%m%d.zip'
# entonces no es un archivo que se ha generado aquí.
continue
# Comparamos las fechas de tipo string y funciona ya que:
# '20201221' es menor que '20201224.
if suffix < back_date:
print(f"Eliminando: {f}")
f.unlink(missing_ok=True)



# Ahora procedemos a generar nuestros backups.

for setting in SETTINGS:

# Construimos el nombre que tendrá el archivo de salida, de acuerdo
# a este formato: 'filename_%Y%m%d.json' -> 'ininstancia_20201224.json'.
timestamp = datetime.datetime.now().strftime(FILE_SUFFIX_DATE_FORMAT)
backup_filename = BACKUP_DIR_NAME / f"{setting.NAME}_{timestamp}.json"

# Ejecutamos el comando python manage.py dumpdata...
print(f"dumpdata para {setting.NAME}")
os.system(f"python manage.py dumpdata > {backup_filename}")

# Creamos el archivo .zip y eliminamos el .json.
zip_filename = backup_filename.with_suffix(".zip")
with ZipFile(zip_filename, 'w') as zip:
zip.write(backup_filename, backup_filename.name)

# Eliminamos el archivos .json.
backup_filename.unlink(missing_ok=True)

print(zip_filename, "OK")