Usando hashlib en Python

Python nos ofrece multiples librerías con valor incalculable para todo el tema de criptografía, una de ellas la librería hashlib, que nos va a permitir trabajar con un tipo de encriptado conocido como SHA

Su nombre proviene del inglés, ( Secure Hash Algorithms ), y su labor consiste en crear estructuras seguras, mediante funciones de encriptado, que puedan ser utilizados por diferentes lenguajes de modo transversal.

Los algoritmos o funciones SHA con que trabaja haslib, son varios(‘sha256', 'sha384', 'sha224', 'sha512', 'sha1'), con diferentes tamaños de bloque

hashlib, posee dos funciones asociadas, que usaremos al aplicar las transformaciones:

  • encode() : Convierte las cadenas en bytes, para que la funcion hash pueda procesarla.
  • hexdigest() : Devuelve el dato codificado en formato hexadecimal.

Haremos una pequeña demostración de su uso:

Introduciremos un cadena  y la convertiremos a su equivalencia en bytes utilizando la funcion enconde(),  para que la funcion SHA  pueda manipularla, esta la codifica con hexdigest(), e imprimimos la cadena resultante

import hashlib 
import hashlib 
   
 # valor de entrada 
 str = "el comienzo de todo"
   
 result = hashlib.sha256(str.encode()) 
  
 # Imprimiendo el valor hexadecimal. 
 print("El resultado es: ") 
 print(result.hexdigest()) 
 print ("\r") 
  
 # salida: El resultado es: 
 9f78aef8f9e252913e43156c570568592f014cb0175d52a6071a5eed8959e183
    
   
 # valor de entrada 
 str = " el comienzo de todo "
  
 result = hashlib.MD5(str.encode()) 
   
 # Imprimiendo el valor hexadecimal. 
 print("El resultado es: ") 
 print(result.hexdigest())
 # salida: El resultado es: 3455ed58e2999e23fc7385207e4fb999 

Y listo esto es todo.

Espero modestamente que este artículo, sirva de ayuda a alguien.

Gracias.

…. hay que levantarse cada mañana con una esperanza y dormirse cada noche con una meta….

El uso de NumPy.

Es  una de las librerías  de Python  mas conocida, debido  a la fortaleza que da al lenguaje en el procesamiento de matrices y arrays de diferente complejidad.

Su uso, es ampliamente reconocido como procesador de cálculos científicos, (que entre otras muchas opciones permite procesar matrices multidimensionales, ejecutar funciones de transmisión o de Algebra Lineal, integrar scripts de otros lenguajes  como C y Fortran y  trabajar con números aleatorios ), también es utilizado a menudo para almacenar datos genéricos, con la propiedad de que podemos definir tipos de datos arbitrarios, que pueden integrarse  con múltiples tipos de bases de datos.  

Recordando que en Python todo es un objeto, diremos que NumPy establece entonces un arreglo multidimensional y otras matrices derivadas, que no son más que otros  objetos.

 Lo que hace Numpy,  es dotarnos una herramienta que nos permite realizar operaciones en un arreglo de cualquier dimensión.

Python ofrece otras opciones para procesar  datos,  como  son sus listas, la diferencia es que Numpy permite realizar operaciones estadísticas y de álgebra, crear  funciones de entrada y salida de datos, ordenar los integrantes de un arreglo y ejecutar operaciones lógicas, extendiendo la capacidad de Python para procesar matrices e información científica

A continuación mostrar algunos de los comandos más usados de esta extensión:

 Para instalar NumPy, en  Windows necesitas Python y Pip en tu sistema.

pip install numpy

#Luego importar la librería con Import

import numpy

Array()

Una lista de python no es un arreglo, sino elementos que se encuentran encerrados entre encerrados entre corchetes, para convertirlos en un array de Numpy, basta con aplicar la siguiente sintaxis:

elementoLista = numpy.array

 import numpy
 l = [1, 2, 3, 4, 5]
 nuevo = numpy.array(l)
 print("la lista convertida a array es = ", nuevo) 

y obtenemos el nuevo array:

>>la lista convertida a array
es =  [1 2 3 4 5]

Del mismo modo haríamos si en vez de ser una lista es una tupla. Sabemos que la tupla contiene una serie de elementos encerrados entre paréntesis, entonces será:

 import numpy
 tupla = (1, 2, 3, 4, 5)
 nuevoarray = numpy.array(tupla)
 print("El nuevo array a partir de la tupla es  = ", nuevoarray) 

La salida será:

>>El nuevo array a partir de
la tupla es  =  [1 2 3 4 5]

Append()

numpy.append(array, value, axis)

append() añade los elementos al final del arreglo, ya sean columnas o valores independientes, por lo que se obtiene entonces un nuevo array actualizado.

Si no definimos el valor de axis(es opcional y asimila valores enteros),  la nueva matriz obtenida se aplanará.

Para añadir una columna lo haríamos de este modo: Considere el siguiente ejemplo donde creamos un arreglo bidimensional e insertamos dos columnas:

 import numpy
 uno = numpy.array([[0, 1, 2, 3,], [4, 5, 6, 8,]])
 dos = numpy.array([[7], [9]])
 nuevo = numpy.append(uno, dos, axis = 1)
 print(nuevo) 

eso nos dará como resultado:

 [[0,1,2,3,7],
 [4,5,6,8,9]] 

Si no usaramos un valor para axis

newArray = numpy.append(a, b)

El resultado seria

 [0, 1,2, 3, 4, 5, 6, 8, 7, 9]

Añadir una fila

 import numpy
 a1 = numpy.array([[0, 1, 2, 3], [4, 5, 6, 7]])
 nuevo = numpy.append(a1, [[8, 9, 10, 11, 12]], axis = 0)
 print(nuevo)
 [[0, 1, 2, 3]
 [, 5, 6, 7]
 [8, 9, 10, 11, 12]] 

Añadir un arreglo a otro

 import numpy
 x = numpy.array([8, 12, 16, 20, 24])
 y = numpy.array([28, 32, 36, 40, 44])
 nuevo = numpy.append(x, y)
 print("Nuevo array resultante = ", nuevo) 

el resultado es:

Nuevo array resultante =  [ 8 12 16 20 24 28 32 36 40 44]

Insert()

La diferencia con append(), es que insert(), permite decidir donde exactamente queremos agregar el elemento,  seleccionando el índice que deseamos.

 import numpy
 ar = numpy.array([0, 1, 2,3])#declaramos el array tipo numpy
 nuevo = numpy.insert(a, 2, 55)#insertamos en el índice 2 el valor 55
 print(nuevo) 

La salida será la siguiente:

[0, 1, 55, 2, 3]

delete()

Se utiliza para  eliminar un elemento de un arreglo NumPy  

 import numpy
 restar = numpy.array([1, 2, 3, 4, 5])
 nuevo = numpy.delete(restar, 2, axis = 0)
 print(nuevo) 

Obtendremos:

[1 2 4 5]

Eliminar una fila

import numpy
valores = numpy.array([[1, 2, 3, 4, 5], [6, 7, 8, 9,10], [11, 12, 25, 22]])
nuevo = numpy.delete(valores, 1, axis = 0)
print(nuevo) 

 esto nos dara como resultado:

[list([1, 2, 3, 4, 5]) list([11, 12, 25, 22])]

Size

El método size tiene diferentes usos, como obtener el número de elementos  en un array o calcular la longitud de este:

Calcular el número de elementos en un array

 import numpy
 ar = numpy.array([1000, 2000, 3000, 6000])
 if(ar.size != 0):
     print("la matriz no esta vacia")
 else:
     print("ar contiene = ", ar) 

La salida es la siguiente:

>>la matriz no esta vacia

 Si moficaramos  el código y colocaramos

 import numpy
 ar = numpy.array([1000, 2000, 3000, 6000])
 if(ar.size == 0):
     print("la matriz no esta vacia")
 else:
     print("ar contiene = ", ar) 

Obtendriamos

>>ar contiene =  [1000 2000 3000 6000]

where()

Nos devuelve el índice de un valor

 import numpy
 lista = numpy.array(['a', 2, 'b', 4, 'c'])
 print("c is found at index: ", index[0]) 

El resultado será:

>>c is found at index:  (array([4]),)

Si cambiamos la última línea de nuestro código

 import numpy
 lista = numpy.array(['a', 2, 'b', 4, 'c'])
 print("c is found at index: ", numpy.where(lista == '5')) 

Obtendremos también el tipo de dato

>>c is found at index:  (array([], dtype=int64),)

Obtener la longitud de un array

 import numpy
 cuerpo = numpy.array([1, 2, 3, 4, 5, 6])
 print("El tamaño del cuerpo  = ", cuerpo.size) 

 el resultado será:

>>El tamaño del cuerpo  =  6

Dividir un arreglo

Para dividir un arreglo utilizaremos dos puntos (:) y la sintaxis es la siguiente :

array[from:to]

 Funciona de este modo:

 import numpy
 parte = numpy.array([1, 2, 3, 4, 5, 6, 7, 8])
 print("Un pedazo del array parte es = ", parte[2:5]) 

Obtendremos:

>>un pedazo del array parte es
=  [3 4 5]

Lo que hemos hecho ha sido extraer del arreglo parte una sección del mismo que va del índice 2 al 5.

 Extraer los dos últimos elementos

 import numpy
 two_last= numpy.array([0, 1, 2, 3, 4, 5, 6, 7, 8])
 print("A subset of array a = ", two_last[-2:]) 

Resultado:

>>A subset of array a =  [7 8]

addition()  

Numpy, también permite aplicar funciones a los miembros de un arreglo o matriz multidimensional, mediante el uso de addition()

 import numpy
 addition = lambda x: (x + x*2)
 conjunto = numpy.array([1, 2, 3, 4, 5, 6])
 print("Resultado: ", addition(conjunto)) 

La salida es:

Resultado:  [ 3 6  9 12 15 18]

tolist

El método tolist, nos permitirá convertir un arreglo en una lista.

 import numpy
 x = numpy.array([10, 20, 30, 40, 50, 60, 70, 80, 90])
 print("Convirtiendo un array en lista = ", x.tolist()) 

obtenemos entonces:

>>Convirtiendo un array en lista =  [10, 20, 30, 40, 50, 60, 70, 80,90]

savetxt()

Con savetxt(), podemos exportar un arreglo a formato de texto o csv: 

 import numpy
 a = numpy.array([16, 32, 48, 60])
 numpy.savetxt("mi.csv", a) 

Este código generará un archivo CSV en la ubicación donde se almacena nuestro archivo de código Python.

Puedes eliminar el relleno de ceros adicional de esta manera:

numpy.savetxt("miArray.csv", a,fmt='%.2f')

sort()

 Podemos  ordenar el arreglo NumPy usando el método sort (), que toma como eje  por defecto(-1), que indicará la forma en que queremos ordenar el arreglo, siendo  -1 el ultimo eje.

 import numpy
 x = numpy.array([56, 45, 17, 89, 3, 12, 5])
 print("array ordenado = ", numpy.sort(x)) 

el resultado:

>> array ordenado =  [ 3  5 12 17 45 56 89]

Normalizar un arreglo

Normalizar un arreglo, consiste en colocar los valores de un arreglo dentro de un  rango definido, siguiendo la sintaxís:

x = (x – xmin) / (xmax – xmin)

Con  los métodos max () y min () podemos organizar el array colocando los valores limites que esperamos:

 import numpy
 x= numpy.array([5000, 4800, 160, 80, 1200, 3000, 500])
 xmax = x.max()
 xmin = x.min()
 x = (x - xmin)/(xmax - xmin)
 print("array nomalizado x = \n", x)
 print(xmax )
 print(xmin ) 

 asi obtendremos:

 array nomalizado x =
 [1.  0.95934959 0.01626016 0.  0.22764228 0.59349593  0.08536585]
 5000
 80 

Indexar un arreglo

 import numpy
 x = numpy.array([40, 73, 77, 89])
 print("elemento en el indice 3 = ", x[3]) 

el resultado es:

>>elemento en el indice 3 =  89

Otro ejemplo, de su uso en un array multidimensional

 import numpy
 b = numpy.array([[10, 45, 36], [78, 9, 18]])
 print("elemento en el indice b[0][1] = ", b[0][1]) 

La salida será:

>>elemento en el indice
b[0][1] =  45

Y listo, esto es todo.

Espero modestamente que este artículo, sirva de ayuda a alguien.

Gracias.

Desarrollar funciones en Python

Desarrollar funciones en Python pueden ser necesario para hallar solucion a problemas que otras funciones existentes no nos resuelven.

La librería del lenguaje no deja de crecer, pero es común que si actuamos como investigadores, en mas de una ocasion, no encontremos lo que necesitamos para obtener la respuesta que buscamos.

Funciones

En Python como en muchos otros lenguajes existen funciones y métodos.

Veamos a  una función como trozo de código que controla   o ejecuta un conjunto de instrucciones, y a la que podemos necesitar utilizar varias veces, esperando siempre el mismo comportamiento.

Los tipos de funciones en Python son tres:

Las que son predefinidas como print() o help().

Las que son definidas por el usuario, ya que este las crea

Las funciones anónimas, o  funciones lambda, llamadas  asi porque no se declaran bajo el standard def, que es el que usa python en el resto de los casos.

Docstring

Antes de ir más allá, algo básico a la hora de escribir código  en Python como en todo lenguaje de programación, son los comentarios, o la documentación que explique lo que estamos creando.

Añadir docstrings a la función, permite conocer su comportamiento esperado, ya que mediante su descripción documentamos todo aquello que consideramos importante, para entender que hace.

Los docstring se colocan justo después de la primera línea de la función, y se inicializan con tres comillas dobles,  y se finaliza de igual modo.

def  nada():
"""
   esta función no hara nada
   retornara un campo de tipo none
"""
   return 

Métodos

Los métodos son pequeñas funciones, que forman parte de una clase, por tanto se accede a ellos instanciando esta o con un objeto, a diferencia de una función típica que puede ser llamada sin esa restricción.

 Puede parecer confuso, pero la mejor forma de verlo es pensando que: todos los métodos son funciones pero no todas las funciones son métodos.

Por ejemplo una función puede ser:

def función_x(a,b,c):
   return a*b+c

Habiendo definido la función y lo que esperamos de ella, para llamarla solo debemos  asignar valores a sus parámetros

función_x(2,3,5)

Comparemos como seria al crear una clase:

class Resultado(object):  
   def solucion(self, a,b,c):  
   self.contents = a*b+c 
   return self.contents

Si ahora deseamos llamar  al método solución(), al pertenecer a la clase Resultado, necesitamos primero crear un objeto o instanciar la clase.

solucionInstance = resultado() 
solucionInstance.solucion(1,2,4)

Un elemento que puede llamar a confusión cuando empiezas en Python es la diferencia entre parámetros y argumentos.

Entenderlo es más sencillo de lo que parece:

Imagina que creas una función que suma dos variables, la variable A y la B

def letras(A, B) 
   return A+B

A y B son parámetros, sin embargo cuando debes llamar la función o el  método para ejecutarlo necesitas dar valor a  los parámetros cuando los llamas

Si  A = 1, B=5

def letras(1, 5)

La  función hará lo que está establecido en su comportamiento sumar 1+5

Cuando creamos la clase Resultado al método solución se le pasaron tres parámetros, sin embargo al crear el objeto se pasaron cuatro argumentos, pues se añadió self.

self , es siempre el primer argumento de cualquier clase y hace referencia a ella misma.

Cuando una función es creada por un usuario, se declara siempre igual:

  • La palabra def y luego el nombre de la función,  después se añaden los parámetros de la función entre paréntesis y después  dos puntos,  para terminar la línea.
  • La acción que la funcion debe ejecutar..
  • Y la llamada a return para que nos devuelva algo. No colocar return provocará que la función devuelva un objeto none, el cual no admite que se ejecuten funciones sobre el.
def función(a, b): 
   c=a+b 
   return c

Existen diferentes tipos de argumentos

Los que son por defecto, los requeridos, los argumentos keyword y los  variables.

Argumentos por defecto

Son que les asigna un valor mediante el operador =

def menos(a,b,d=3): 
   return a-b-d

Esta función puede ser llamada con todos sus parámetros,  o solo con alguno de ellos.

#llamandola con 1 parametro  
menos(b=2)
#llamandola con todos los parametros 
menos( a=10,b=12,d=4)

Argumentos requeridos

Son aquellos que tiene que ser pasados a la función en el momento adecuado y en un orden dado para garantizar su ejecución

En la función menos() a, b y d son argumentos requeridos, los cuales deben pasarse en un momento dado (al inicio) y en un orden ( ya que a-b-d), cambiar ese orden alteraría el resultado.

Argumentos keyword

Este tipo de argumentos son llamados utilizando el parametro al que corresponde para identificarlo

def sol(a,b): 
   return a+b 
   
#llamando la función con el uso de keywords 
def sol(a=2, b=3)

 Cuando usamos las keywords, podemos cambiar el orden de los argumentos, sin que ello afecte el resultado

def sol(b=3,a=2)

Argumentos de número  variable

Se utiliza cuando no se sabe el numero de argumentos esperado, y para ello se utiliza la sintaxis *args

def  varios(*args):   
   return sum(args)  
   #ejecutando la función 
   varios(3,6,7)

El asterisco * , se coloca antes del nombre de la variable que soporta los argumentos multiples:

def  diferentes(*varnueva):  
   x=2  
   for i in varnueva:  
   x += i*2  
   return x

Variables

Las  variables en Python pueden ser locales o globales, las primeras son las que se definen dentro de las funciones, por tanto solo se puede acceder a ellas desde dentro de la función, mientras que las variables globales puede obtenerla cualquier función.

Return

Return es el encargado de  devolver el resultado, ya sea uno o múltiples valores, y su uso nos permite , ampliar las posibilidades  de nuestra función o método.

Cuando necesitamos que el return nos devuelva multiples valores, utilizaremos tuplas

Funciones anónimas

Son las funciones que en vez de declararse con def, son declaradas con la palabra lambda.

double = lambda x: x*3  
   double(5)

En este caso x es el argumento, y x*3 la instrucción que la función debe cumplir

Una función con dos argumentos podría ser

sum = lambda xmy:x+y  
   sum(4,2)

Las funciones anónimas pueden usarse por ejemplo, cuando se requieren funciones con un corto periodo de tiempo de vida, por ejemplo cuando se trabaja con maps(), filter() o reduce().

Main

La función main(), se usa comunenente en Python para agrupar los principales componentes de un sistema.

En un ejemplo sencillo podría ser algo asi:

def  main():  
   varios()  
   solucion() 
   main()

Existe un detalle a considerar, para llamar main() como clase, debe hacerse de esta forma:

__name__ ==’__main__’:

De lo contrario Python asumirá que estamos llamando a un modulo

main() también puede crearse utilizando __init__ para instanciar una clase o un objeto. El nuevo objeto instanciado es asignado al parámetro self

La estructura es esta:

class  nueva:  
""" Requires:  
   atrib_a 
   atrib_b 
"""
def  __init__ (self, atrib_a, atrib_b): 
   self.atrib_a =atrib_a 

 self.atrib_b = atrib_b 
 def  funcion1(self): 
 funcion1  = …acción…. 
 return funcion1 
 #llamando a main 
 if __name__ ==  ”__main__”: 
  solucion =  solucion(argumento1, argumento2) 
  funcion1  = solucion.funcion1() 
  print(funcion1) 

Y listo, esto es todo.

Espero modestamente que este artículo, sirva de ayuda a alguien.

Gracias.

 ….un sueño es casi todo  y más que  nada, más que todo al soñarlo, casi nada después……