Crear APIs REST con Python y Hug

Hug framework

Crear APIs REST con Python y Hug

Hola a todos, han sido unas semanas muy divertidas, en las cuales he ido aprendiendo a ser padre, por lo que deje un poco olvidado el blog; pero creí conveniente dedicarle un tiempo. En esta entrada, vamos a aprender a crear APIs REST con Python y Hug, un framework que llevo un tiempo utilizando en mis proyectos, y que me ha dejado un buen sabor de boca, debido a su rendimiento y facilidad para obtener productos finales.

Continuar leyendo

Un desarrollador siendo papá

Un desarrollador siendo papá…

Hola a todos, aquí estamos una vez más después de un tiempo sin escribir, he tenido descuidado mis redes sociales, y el blog en especial, debido a, cómo podrán intuir por el título del post, hace un mes tuve la dicha de convertirme en padre, y debo decir que ha traído un cambio grande en mi vida. Es por esto que en esta ocasión, quiero recordar que esto no deja de ser un blog, y compartir mi experiencia y forma de sentir con esto de ser un desarrollador siendo papá.

Un desarrollador siendo papá

Lo sé, lo sé, aún falta para que la imagen sea del todo cierta, sin embargo el sentimiento ya existe. Es desconcertante estar 8 horas en la oficina cada día (realmente un poco más) y estar pensando en las ganas que tienes de cargar a tu hija, tenerla en tus brazos, y saber que ella puede sentir que la proteges, y sobre todo, la amas.

Debo decir que por ahora soy muy feliz llegando a casa, y viendo a mi novia y a mi hija, es maravilloso. Como desarrollador de software, siempre he tratado de pensar lógicamente, paso horas y horas escribiendo código que, para los mortales, es un tipo de lengua ilegible.

También, otra actividad que realizo durante mucho tiempo es “debuggear” aplicaciones, esta práctica es un proceso que supone un reto para cualquier desarrollador de software, ya que se centra en buscar errores en la aplicación, para así poder corregirlos. Con esto como premisa debo decir que ya encontré mi mayor reto: mi hija.

Cada vez que llora, debo aplicar todo mi conocimiento en esta tarea para poder “saber” que está mal con ella, pañal sucio, hambre, sueño, o simplemente quiere que le den un paseo. Todo esto únicamente observando detalladamente sus gestos, movimientos, sonidos, etc. Es algo sumamente complejo, y la verdad, aún no tengo un algoritmo con el que lidiar del todo con eso, pero seguimos en la etapa de “testing”.

Anteriormente me centraba en pasar horas frente al ordenador, observando charlas de conferencias, probando la tecnología del momento, o simplemente viendo “Los simpsons”, pero ahora, paso horas viéndola dormir, cargandola y paseando por la casa con ella, y sobre todo, amándola.

Esta entrada no tiene ningún objetivo cultural, no creo que pueda transmitir conocimiento alguno, simplemente quería escribir un poco ya que repito, hace un mes me convertí en padre y es el mejor trabajo y cargo el cual he desempeñado, y espero poder realizarlo correctamente en lo que me resta.

Me despido y pronto terminaré esos “post” que tengo en borrador, para que podamos seguir con la temática habitual del blog

El papá más feliz…

Tipos estáticos en Python con Mypy

tipos estáticos en python

Tipos estáticos en Python

Hola a todos, en esta entrada vamos a hablar sobre los tipos estáticos en Python, utilizando Mypy, esta herramienta desarrollada principalmente por un equipo de Dropbox, incluyendo al creador del lenguaje Guido Van Rossum.

tipos estáticos en python

Tipado estático en lenguajes dinámicos

Desde hace un par de años, han salido a la luz verificadores de tipado estático para lenguajes dinámicos populares como Hack para PHP o Flow y TypeScript para Javascript, los cuales han sido ampliamente adoptados por la comunidad (yo soy un feliz usuario de Flow).

Hace unos años tres años, una sintaxis provisional de anotaciones para tipos estáticos fue añadida a Python 3, sin embargo, los tipos estáticos en Python no habían sido adoptados aún ampliamente, debido a que no existía una herramienta para llevar a cabo la verificación. Es aquí donde llegamos a Mypy.

¿Qué es Mypy?

Como podemos encontrar en su página oficial:

Mypy is an experimental optional static type checker for Python that aims to combine the benefits of dynamic (or “duck”) typing and static typing. Mypy combines the expressive power and convenience of Python with a powerful type system and compile-time type checking. Mypy type checks standard Python programs; run them using any Python VM with basically no runtime overhead.

Cabe decir que a pesar de que Mypy ya soporta la mayoría de las características de Python, aún se encuentra en desarrollo. Y como es bien sabido, nada como un ejemplo para ver de que estamos hablando, también sacado de la página oficial de Mypy.

tipos estáticos en PythonSe puede observar en la imagen la diferencia al utilizar el tipado estático que Mypy nos permite, como mencionaba en las líneas de arriba, se utiliza la sintaxis de anotaciones para tipos estáticos de Python, logrando con esto no afectar el rendimiento de nuestros scripts ni nos hace añadir códigos extraños y dotándonos de los beneficios de tener tipado estático en un lenguaje flexible y dinámico como lo es Python.

Instalando Mypy

Para instalar esta herramienta, debemos tener Python >= 3.3 y desde nuestra línea de comandos debemos ejecutar lo siguiente:


pip install mypy

Empezando con Mypy

Con Mypy contamos con dos tipos de anotaciones diferentes, la mencionada anteriormente (la sintaxis de anotaciones de tipos estáticos de Python) y la sintaxis utilizando comentarios. Veamos un ejemplo:

# Primero desde el módulo typing debemos
# importar los tipos que vamos a necesitar
from typing import List


# Utilizando la sintaxis de anotaciones
def sum_list_to_str(nums: List[int]) -> str:
    """Suma los números de una lista, y retorna el resultado como string"""
    return str(sum(nums))


# Utilizando comentarios
def sum_list_to_str_2(nums):
    # type: (List[int]) -> str
    """Suma los números de una lista, y retorna el resultado como string"""
    return str(sum(nums))

Para ejecutar los scripts con anotaciones de Mypy, podemos realizarlo utilizando cualquier intérprete de Python, esto se debe a que Mypy comparte esta excelente propiedad con el verficador de código de Javascript, Flow. Esto es grandioso ya que significa que podemos añadir Mypy a nuestros proyectos sin preocuparnos de como debemos correr estos proyectos con Python.

De igual manera, podemos utilizar Mypy como un linter, el cual puede mostrar nuestros errores en un formato agradable. Por ejemplo, vamos a cambiar el valor de retorno en nuestra segunda función para comprobar esto, quedando de la siguiente manera:

# Utilizando comentarios
def sum_list_to_str_2(nums):
    # type: (List[int]) -> int
    """Suma los números de una lista, y retorna el resultado como string"""
    return str(sum(nums))

Ahora, desde nuestra línea de comandos ejecutamos:


mypy mi_archivo.py

Output: mi_archivo.py:16: error: Incompatible return value type (got "str", expected "int")

Genial, ¿no crees? Gracias a esto será muy sencillo depurar nuestros scripts y evitar errores durante la ejecución que muchas veces se vuelven una pesadilla para reparar. Si te interesa profundizar sobre las anotaciones de tipo de Mypy, puedes consultar el Cheat Sheet de Mypy y también en PEP-484.

En resumen…

Utilizar Mypy es una excelente opción cuando:

  • Buscamos utilizar tipos estáticos en Python.
  • Verificar tipos en “tiempo de compilación”
  • Lograr un mantenimiento sencillo.
  • Buscamos que nuestro código sea simple de entender y más sencillo de modificar sin introducir “bugs”
  • Llevar nuestros scripts de dinámicos a estáticos.
  • Desarrollar nuestros scripts con tipado dinámico e ir añadiendo tipado estático conforme el código vaya madurando, o migrar código Python existente a tipado estático.
  • Declaraciones de tipo que actúen como documentación verificada por máquina.

Y bien, es todo por esta ocasión, espero la explicación haya sido clara y cualquier comentario no dudes en dejarlo aquí abajo, o con confianza mencionalo por Twitter o en la Fanpage de Facebook, y aprovecho a invitarte para que me sigas en las redes y compartas el contenido del blog, con lo cual me harías un gran favor.

Saludos.

Crear un blog con NodeJS y Hexo

crear un blog con nodejs

Crear un blog con NodeJS

Hola a todos, en esta entrada vengo a escribir sobre Hexo, una herramienta de línea de comandos que nos permitirá crear un blog con nodejs, y con esto, crear la estructura de un blog de forma muy sencilla.

crear un blog con nodejs

¿Qué es Hexo?

Bien, como en su propia página de documentación nos adelantan:

Hexo is a fast, simple and powerful blog framework. You write posts in Markdown (or other languages) and Hexo generates static files with a beautiful theme in seconds.

Como podemos apreciar Hexo nos permitirá crear un blog de una forma sencilla y rápida. Nos da la posibilidad de crear los post de nuestro blog utilizando Markdown (lo cual es grandioso) o algún otro lenguajes y generar archivos estáticos y con un hermoso tema en segundos.

Generando nuestro blog

Lo primero que debemos hacer es instalar hexo, para esto debemos tener instalado NodeJS previamente, y ejecutar alguno de los siguientes comandos:


# Utilizando npm

npm install -g hexo-cli

# Utilizando yarn (recomendado)

yarn global add hexo-cli

Con esto ya tendremos el binario de hexo listo para utilizar, ahora lo que debemos hacer es ejecutar el siguiente comando:


hexo init my_blog

Luego nos posicionamos en el directorio que nos ha creado el comando anterior:


cd my_blog

Instalamos las dependencias:


# Utilizando npm

npm install

# Utilizando yarn

yarn install

Si todo se instaló correctamente, simplemente ejecutamos el servidor de hexo:


hexo server

Ahora si navegamos a la url que nos muestra en la salida (http://localhost:4000/), podremos visualizar nuestro blog, que debería verse parecido a lo siguiente:

crear un blog con nodejsSencillo y rápido, ¿no? Cumplen lo que prometen 😀

Creando un post

Tal vez, te estás preguntando, ¿cómo se crean los post?

La respuesta es simple. Únicamente debemos ejecutar el siguiente comando:


hexo new post 'Titulo de tu post'

Donde debemos reemplazar ‘Titulo de tu post’ con el titulo que quieras que tenga tu post. Para realizar esto no es necesario que detengas el servidor de hexo. Y listo, solo debes comenzar a escribir el contenido de tu post en el archivo generado con el titulo que escribiste dentro de la carpeta source.

Y deberías tener un resultado como el siguiente:

crear un blog con nodejsSi desean saber más sobre este grandioso framework siempre pueden darle un vistazo a su buena documentación, que aunque aún tiene mucho por delante, es una buena opción si quieres algo simple y que te permita llevar a cabo el objetivo de un blog: escribir.

Y bien, es todo por esta ocasión, espero la explicación haya sido clara y cualquier comentario no dudes en dejarlo aquí abajo, o con confianza mencionalo por Twitter o en la Fanpage de Facebook, y aprovecho a invitarte para que me sigas en las redes y compartas el contenido del blog, con lo cual me harías un gran favor.

Saludos.

¿Qué es __name__ en Python?

¿Qué es __name__ en Python?

Hola a todos, ya llevo un rato sin escribir, esto se debe a que me encuentro pasando por muchas cosas personales, muy buenas, y me estoy enfocando en ellas, pero sin embargo tengo muchos borradores que espero ya terminar y publicar, como adelanto les puedo decir que tratan sobre Xamarin, Vue, Python y Ruby. Y bien, bienvenidos a esta entrada donde a petición de un usuario en FB voy a intentar explicar qué es __name__ en Python.

que es __name__ en python

Seguro que al estar leyendo un libro sobre Python, o leyendo el código de algún script de tu interés has visto algo como lo siguiente:


class MyComplexClass(object):
    def __init__(self):
    print("Hello World!")
    # Código de la clase con lógica demasiado compleja
    # ...

def init():
    my_complex = MyComplexClass()
    # Resto de la lógica del script
    # ...

if __name__ == '__main__':
    main()

Si eres curioso, o el libro donde viste esto es de un buen autor, seguro explicaron de que se trata, si no es tu caso, o buscando sobre el tema diste con el blog sigue leyendo, no te defraudaré 🙂

Pequeño paréntesis cultural

Muchos lenguajes de programación, normalmente los lenguajes compilados (llámese C, Java, Go, Rust, etc.), requieren de una función que actúe como punto de entrada, esto es, que será lo primero en ejecutarse al correr el programa. Comúnmente esta función de punto de entrada es main() (Espero haber sido breve).

Sigo sin saber qué es __name__ en Python

Lo sé, no desesperes, las líneas anteriores eran necesarias. Python, al igual que muchos de los lenguajes de script, ejecuta el código interpretando cada línea de arriba a abajo. Cuando el intérprete de Python encuentra el bloque if anterior (if __name__ == ‘__main__’), comprueba el atributo especial __name__, con el objetivo de ver si su valor actual es “__main__”.

Tiene sentido…al cumplirse esta condición, estaremos seguros de que nuestro módulo (script) es el primero en ser “cargado” por el intérprete de Python. Suponiendo que el código anterior esté almacenado en el archivo mi_super_script.py y lo ejecutamos:


python mi_super_script.py

El resultado será lo que este definido dentro de la función init(). Por lo tanto, aunque Python no especifica como tal, oficialmente una función de punto de entrada que será ejecutada en primer lugar, el bloque anterior es una forma “idiomática” de lograr el mismo objetivo.

Por lo tanto, con esto nos aseguramos de que ese código en especifico será ejecutado únicamente cuando nuestro script sea ejecutado, y no cuando sea importado. ¿A qué me refiero?


# mi_super_script.py
def main():
    print("Script 1!")

if __name__ == '__main__':
    main()

# mi_super_script_dos.py
import .mi_super_script

def init():
    print("Script 2!")

if __name__ == '__main__':
    init()

Si nosotros ejecutaramos ambos scripts, tendríamos la siguiente salida:


python mi_super_script.py

# Output: "Script 1!"

python mi_super_script_dos.py

# Ouput: "Script 2!"

Como podrás notar, a pesar de que en mi_super_script_dos.py estamos importando el código de mi_super_script.py la función main no ha sido ejecutada.

Generalmente no es útil sobreescribir el valor por defecto que el intérprete le otorga a __name__, pero existe un caso puntual donde esto se lleva a cabo con frecuencia: funciones decoradoras.

Voy a dejar ese tema para otra entrada si les interesa la relación que tienen con el atributo especial __name__ les sugiero leer esto y esto.

Y bien, es todo por esta ocasión, espero la explicación haya sido clara y cualquier comentario no dudes en dejarlo aquí abajo, o con confianza mencionalo por Twitter o en la Fanpage de Facebook, y aprovecho a invitarte para que me sigas en las redes y compartas el contenido del blog, con lo cual me harías un gran favor.

Saludos.

Transpuesta de una matriz con Python

Transpuesta de una matriz con Python

Hola, y bienvenido a esta 5ta y última entrada de la serie de operaciones en matrices con Python. En esta ocasión, es el turno para aprender a obtener la transpuesta de una matriz con Python.

Una vez más aprovecho para invitarte a que me sigas en mis redes Twitter o en la Fanpage de Facebook, donde podrás estar informado de nuevas entradas del blog, o si tienes alguna duda o comentario puedes hacermelo saber.

Operaciones en matrices con python

Hasta el momento las entradas de esta serie han sido las siguientes:

Creando la clase Base

Suma de matrices

Producto por un escalar

Producto de matrices

Transpuesta

Como en las entradas anteriores, para realizar el ejemplo utilizaremos la clase base que creamos en la primera entrada de esta serie, así que si aún no la tienes, lee la primera entrada y regresa, aquí estaré esperando 😀

Un poco de teoría

Como en cada entrada de esta serie, un poco de teoría no viene mal para explicar el problema que tratamos de resolver. Para obtener la transpuesta de una matriz con python, primero debemos conocer como se lleva a cabo este procedimiento.

La transpuesta de una matriz A es otra matriz B tal que las filas de B son las columnas de A. Para ilustrar mejor estas palabras les dejo la siguiente imagen:

transpuesta de una matriz con pythonCódigo: Transpuesta de una matriz con python

Para obtener la matriz transpuesta de A es bastante simple como podrás observar en el siguiente código:

def transpose(self):
    for j in range(self.cols):
        row = []
        for i in range(self.rows):
            row.append(self.get_value_of_position(i,j))
        yield row

Nuevamente, y para mantener un uso eficiente de memoria, se define la función como un método generador. Esto evita tener que almacenar una copia de la matriz completa, la cual podría tener grandes dimensiones y ocupar bastante memoria.

Básicamente recorremos la matriz como lo estuvimos haciendo anteriormente, pero esta vez invirtiendo los indices, de esta forma logramos “voltear” nuestra matriz.

Ahora, si queremos verificar el funcionamiento de la función basta con escribir un código como el siguiente:

# Matriz A
m = Matrix(2,3)
# Primera fila
m.define_elem(0,0,1)
m.define_elem(0,1,2)
m.define_elem(0,2,3)
# Segunda fila
m.define_elem(1,0,7)
m.define_elem(1,1,8)
m.define_elem(1,2,9)

# Imprime la matriz A
print("Matriz A")
m.show_matrix()

# Imprime la transpuesta de la matriz A
print("B: Transpuesta de A")
for e in m.transpose():
    print(e)

Teniendo una salida como la siguiente:


Matriz A
| 1 | 2 | 3 |

| 7 | 8 | 9 |

B: Transpuesta de A
[1, 7]
[2, 8]
[3, 9]

Como vemos, es una salida exactamente igual a la imagen de ejemplo. Hasta este punto nuestra clase debe encontrarse de la siguiente forma (Recuerda que también se encuentra todo el código en el repositorio de Github):

#!/usr/bin/python
# -*- coding: utf-8 -*-
# author: Gabriel Cueto <TheMushr00m - @Mushr00m_Dev>


class Matrix(object):
    _n = 0
    _m = 0
    _elems = None

    def __init__(self, n, m):
        """Inicializa la matriz con valor 0 en cada posición"""
        self._n = n
        self._m = m
        self._elems = []
        for i in range(self._n):
            self._elems.append([])
            for j in range(self._m):
                self._elems[i].append(0)

    def define_elem(self, i, j, v):
        """ Sobreescribe el valor de una celda """
        self._elems[i][j] = v

    def show_matrix(self):
        """ Imprime los valores almacenados en la matriz """
        for i in range(self._n):
            for j in range(self._m):
                # Imprime de una forma elegante la matriz
                print("| {0} ".format(self.get_value_of_position(i, j)), sep=',', end='')
            print('|\n')

    def get_cols(self):
        """ Devuelve el número de columnas en la matriz """
        return self._m

    def get_rows(self):
        """ Devuelve el número de filas en la matriz """
        return self._n

    def get_value_of_position(self, i, j):
        """ Devuelve el valor en la fila(i), columna(j) de la matriz """
        return self._elems[i][j]

    def add(self, *matrix):
        """ Puede recibir varias matrices como argumentos """
        for i in range(self.rows):
            row = []
            for j in range(self.cols):
                tmp = self.get_value_of_position(i, j)
                for m in matrix:
                    tmp += m.get_value_of_position(i, j)
                row.append(tmp)
            yield row

    def scalar_product(self, x):
        """ x: Número real """
        for i in range(self.rows):
            row = []
            for j in range(self.cols):
                row.append(self.get_value_of_position(i, j)*x)
            yield row

    def product(self, m):
        """ Recibe una matriz como argumento
         Args:
             m (Matrix): Represents an instance of Matrix
        """
        if self.rows is not m.cols:
            raise Exception('Number of rows'
                            'and number of columns'
                            "don't match")
        for i in range(self.rows):
            row = []
            for j in range(m.cols):
                add = 0
                for c in range(self.cols):
                    add += self.get_value_of_position(i, c) * \
                           m.get_value_of_position(c, j)
                row.append(add)
            yield row

    def transpose(self):
        for j in range(self.cols):
            row = []
            for i in range(self.rows):
                row.append(self.get_value_of_position(i, j))
            yield row

    cols = property(fget=get_cols)
    rows = property(fget=get_rows)

Y bien, es todo por esta ocasión, espero la explicación haya sido clara y cualquier comentario no dudes en dejarlo aquí abajo, o con confianza mencionalo por Twitter o en la Fanpage de Facebook, y aprovecho a invitarte para que me sigas en las redes y compartas el contenido del blog, con lo cual me harías un gran favor.

Saludos.

Producto de matrices con Python

Producto de matrices con Python

Hola, y bienvenido a esta 4ta entrada en la serie de operaciones en matrices con Python. En esta ocasión, como podrán leer en el título, se trata sobre como podemos calcular el producto de matrices con python.

Una vez más aprovecho para invitarte a que me sigas en mis redes Twitter o en la Fanpage de Facebook, donde podrás estar informado de nuevas entradas del blog, o si tienes alguna duda o comentario puedes decirmelo sin problema.

Operaciones en matrices con python

Hasta el momento las entradas de esta serie han sido las siguientes:

Creando la clase Base

Suma de matrices

Producto por un escalar

Producto de matrices

Transpuesta (Pendiente)

Como en las entradas anteriores, para realizar el ejemplo utilizaremos la clase base que creamos en la primera entrada de esta serie, así que si aún no la tienes, lee la primera entrada y vuelves 😀

Un poco de teoría

El producto de matrices encuentra su origen en el papel que desempeñan las matrices como funciones lineales. Según la forma en que se define este producto, se puede decir que proviene de la composición de funciones lineales.

Si f y g son aplicaciones lineales tal que f: A -> B y g: B -> C (A, B son los dominios respectivos de f, g y B, C son los imágenes que corresponden a estos dominios) entonces la composición de f y g denotada por el operador o, cumple que f o g: A -> C. Los dominios pueden verse como los posibles valores de entrada de la función y pudiera hallarse representado por un conjunto de con las posibles salidas ofrecidas por esta función y también pudiera ser el conjunto de números reales. Por esta razón el producto de la matriz A(m,n) con la matriz B(n,p) sería una matriz C(m,p) lo cual representa una restricción. Dicho de otra forma, solo es posible multiplicar matrices cuando la cantidad de columnas de la primera es igual a la cantidad de filas de la segunda. En la siguiente imagen podemos observar un ejemplo:

Producto de matrices con pythonLa imagen anterior muestra el resultado de realizar el producto de las matrices A y B, operación que se lleva a cabo entre filas de A y columnas de B, lo que justifica que se requiera que esas cantidades sean iguales. Para calcular una celda de C, sea C(i,j), se toman los valores de la fila i de A y se multiplica cada uno con su correspondiente valor en la columna j de B, luego se suman los valores obtenidos y el resultado es C(i,j). De manera general C(i,j) = A(i, 1) * B(1,j) + A(i,2) * B(2,j) + + A(i,m) * B(m,j).

Código: producto de matrices con python

La implementación de la función con la que llevaremos a cabo esta operación, será una función generadora como las que hemos realizado en anteriores entradas de esta serie:

def product(self, m):
    """ Recibe una matriz como argumento """
    if self.rows is not m.cols:
        raise Exception('Number of rows'
                        'and number of columns'
                        "don't match")
    for i in range(self.rows):
        row = []
        for j in range(m.cols):
            add = 0
            for c in range(self.cols):
                add += self.get_value_of_position(i, c) * \
                       m.get_value_of_position(c, j)
            row.append(add)
        yield row

El código es sencillo, primero se hace una comparación para verificar si el número de filas de la matriz A es diferente al número de columnas de la matriz pasada como argumento B, en caso de que esto se cumpla lanzamos una excepción, caso contrario utilizando bucles recorremos las matrices, multiplicando y sumando los valores tal y como se explico anteriormente y añadiendolos a la nueva matriz C.

Si deseamos verificar el comportamiento de nuestra nueva función podemos realizarlo con el siguiente código:

ma = Matrix(2,3)
# First row
ma.define_elem(0,0,1)
ma.define_elem(0,1,2)
ma.define_elem(0,2,3)
# Second row
ma.define_elem(1,0,7)
ma.define_elem(1,1,8)
ma.define_elem(1,2,9)

mb = Matrix(3,2)
# First col
mb.define_elem(0,0,1)
mb.define_elem(1,0,7)
mb.define_elem(2,0,13)
# Second col
mb.define_elem(0,1,2)
mb.define_elem(1,1,8)
mb.define_elem(2,1,14)

for e in ma.product(mb):
    print(e)

Teniendo la siguiente salida:


[54, 60]
[180, 204]

Que como verás corresponden a los valores de las matrices representadas en la imagen anterior. Hasta este punto nuestra clase debe encontrarse de la siguiente forma (Recuerda que también se encuentra todo el código en el repositorio de Github):

#!/usr/bin/python
# -*- coding: utf-8 -*-
# author: Gabriel Cueto <TheMushr00m - @Mushr00m_Dev>


class Matrix:
    _n = 0
    _m = 0
    _elems = None

    def __init__(self, n, m):
        """Inicializa la matriz con valor 0 en cada posición"""
        self._n = n
        self._m = m
        self._elems = []
        for i in range(self._n):
            self._elems.append([])
            for j in range(self._m):
                self._elems[i].append(0)

    def define_elem(self, i, j, v):
        """ Sobreescribe el valor de una celda """
        self._elems[i][j] = v

    def show_matrix(self):
        """ Imprime los valores almacenados en la matriz """
        for i in range(self._n):
            for j in range(self._m):
                # Imprime de una forma elegante la matriz
                print("| {0} ".format(self.get_value_of_position(i, j)), sep=',', end='')
            print('|\n')

    def get_cols(self):
        """ Devuelve el número de columnas en la matriz """
        return self._m

    def get_rows(self):
        """ Devuelve el número de filas en la matriz """
        return self._n

    def get_value_of_position(self, i, j):
        """ Devuelve el valor en la fila(i), columna(j) de la matriz """
        return self._elems[i][j]

    def add(self, *matrix):
        """ Puede recibir varias matrices como argumentos """
        for i in range(self.rows):
            row = []
            for j in range(self.cols):
                tmp = self.get_value_of_position(i, j)
                for m in matrix:
                    tmp += m.get_value_of_position(i, j)
                row.append(tmp)
            yield row

    def scalar_product(self, x):
        """ x: Número real """
        for i in range(self.rows):
            row = []
            for j in range(self.cols):
                row.append(self.get_value_of_position(i, j)*x)
            yield row

    def product(self, m):
        """ Recibe una matriz como argumento """
        if self.rows is not m.cols:
            raise Exception('Number of rows'
                            'and number of columns'
                            "don't match")
        for i in range(self.rows):
            row = []
            for j in range(m.cols):
                add = 0
                for c in range(self.cols):
                    add += self.get_value_of_position(i, c) * \
                           m.get_value_of_position(c, j)
                row.append(add)
            yield row

    cols = property(fget=get_cols)
    rows = property(fget=get_rows)

Y bien, es todo por esta ocasión, espero la explicación haya sido clara y cualquier comentario no dudes en dejarlo aquí abajo, o con confianza mencionalo por Twitter o en la Fanpage de Facebook, y aprovecho a invitarte para que me sigas en las redes y compartas el contenido del blog, con lo cual me harías un gran favor.

Saludos.

Producto de matrices por un escalar con Python

Producto de matrices por un escalar con Python

Hola, y bienvenido a esta 3er entrada en la serie de operaciones en matrices con Python. En esta ocasión, como podrán leer en el título, se trata sobre como podemos calcular el producto de matrices por un escalar con python.

Una vez más aprovecho para invitarte a que me sigas en mis redes Twitter o en la Fanpage de Facebook, donde podrás estar informado de nuevas entradas del blog, o si tienes alguna duda o comentario puedes decirmelo sin problema.

Operaciones con matrices en python

Hasta el momento las entradas de esta serie han sido las siguientes:

Creando la clase Base

Suma de matrices

Producto por un escalar

Producto de matrices (Pendiente)

Transpuesta (Pendiente)

Por si no tienes aún la clase Base, aquí la tienes:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# author: Gabriel Cueto <TheMushr00m - @Mushr00m_Dev>


class Matrix:
    _n = 0
    _m = 0
    _elems = None

    def __init__(self, n, m):
        """Inicializa la matriz con valor 0 en cada posición"""
        self._n = n
        self._m = m
        self._elems = []
        for i in range(self._n):
            self._elems.append([])
            for j in range(self._m):
                self._elems[i].append(0)

    def define_elem(self, i, j, v):
        """ Sobreescribe el valor de una celda """
        self._elems[i][j] = v

    def show_matrix(self):
        """ Imprime los valores almacenados en la matriz """
        for i in range(self._n):
            for j in range(self._m):
                # Imprime de una forma elegante la matriz
                print("| {0} ".format(self.get_value_of_position(i, j)), sep=',', end='')
            print('|\n')

    def get_cols(self):
        """ Devuelve el número de columnas en la matriz """
        return self._m

    def get_rows(self):
        """ Devuelve el número de filas en la matriz """
        return self._n

    def get_value_of_position(self, i, j):
        return self._elems[i][j]

    def add(self, *matrix):
        """ Puede recibir varias matrices como argumentos """
        for i in range(self.rows):
            row = []
            for j in range(self.cols):
                tmp = self.get_value_of_position(i, j)
                for m in matrix:
                    tmp += m.get_value_of_position(i, j)
                row.append(tmp)
            yield row

    cols = property(fget=get_cols)
    rows = property(fget=get_rows)

Un poco de teoría

Un escalar x es un elemento que por lo general se encuentra en el conjunto de los números reales. El producto de una matriz A de m * n por un escalar x, es una operación binaria que toma por operandos a la matriz A y al escalar x y tiene por resultado una matriz C de m * n, donde para todo i, j indices válidos de C se cumple C(i,j) = x*A(i,j). Por ejemplo:

producto de matrices por un escalar con pythonLlevando la teoría a código

La implementación del método como una función generadora es bastante simple como podemos observar a continuación:

def scalar_product(self, x):
    for i in range(self.rows):
        row = []
        for j in range(self.cols):
            row.append(self.get_value_of_position(i, j)*x)
        yield row

Ahora, si deseamos probar el nuevo método, necesitamos escribir algo como lo siguiente:

m = Matrix(3, 3)
m.define_elem(0, 0, 1)
m.define_elem(0, 1, 2)
m.define_elem(0, 2, 3)

for e in m.scalar_product(3):
    print(e)

Si observamos con atención, estamos definiendo una matriz con los valores de la primera fila, en correspondencia a los de la figura anterior, ahora, al ejecutar el código, los valores de la primera fila de la matriz resultante, deben coincidir con los valores de la matriz C de la figura anterior.


[3, 6, 9]
[0, 0, 0]
[0, 0, 0]

Hasta este momento, el código completo de nuestra clase quedaría de esta forma. Recuerda que todo el código está disponible en el repositorio de Github:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# author: Gabriel Cueto <TheMushr00m - @Mushr00m_Dev>


class Matrix:
    _n = 0
    _m = 0
    _elems = None

    def __init__(self, n, m):
        """Inicializa la matriz con valor 0 en cada posición"""
        self._n = n
        self._m = m
        self._elems = []
        for i in range(self._n):
            self._elems.append([])
            for j in range(self._m):
                self._elems[i].append(0)

    def define_elem(self, i, j, v):
        """ Sobreescribe el valor de una celda """
        self._elems[i][j] = v

    def show_matrix(self):
        """ Imprime los valores almacenados en la matriz """
        for i in range(self._n):
            for j in range(self._m):
                # Imprime de una forma elegante la matriz
                print("| {0} ".format(self.get_value_of_position(i, j)), sep=',', end='')
            print('|\n')

    def get_cols(self):
        """ Devuelve el número de columnas en la matriz """
        return self._m

    def get_rows(self):
        """ Devuelve el número de filas en la matriz """
        return self._n

    def get_value_of_position(self, i, j):
        return self._elems[i][j]

    def add(self, *matrix):
        """ Puede recibir varias matrices como argumentos """
        for i in range(self.rows):
            row = []
            for j in range(self.cols):
                tmp = self.get_value_of_position(i, j)
                for m in matrix:
                    tmp += m.get_value_of_position(i, j)
                row.append(tmp)
            yield row

    def scalar_product(self, x):
        for i in range(self.rows):
            row = []
            for j in range(self.cols):
                row.append(self.get_value_of_position(i, j)*x)
            yield row

    cols = property(fget=get_cols)
    rows = property(fget=get_rows)

Y bien, es todo por esta ocasión, espero la explicación haya sido buena, cualquier comentario no dudes en dejarlo aquí abajo, o con confianza mencionalo por Twitter o en la Fanpage de Facebook, y aprovecho a invitarte para que me sigas en las redes.

 

Suma de matrices con Python

Suma de matrices con python

Hola a todos, bienvenidos a esta entrada, siguiendo la serie sobre operaciones con matrices en python, en esta ocasión veremos como llevar a cabo la suma de matrices con python.

Aprovecho para invitarte a que me sigas en mis redes Twitter o en la Fanpage de Facebook, donde podrás estar informado de nuevas entradas del blog, o si tienes alguna duda o comentario puedes decirmelo sin problema.

Operaciones con matrices en python

Hasta el momento las entradas de esta serie han sido las siguientes:

Creando la clase Base

Suma de matrices

Producto por un escalar

Producto de matrices (Pendiente)

Transpuesta (Pendiente)

Para esta entrada utilizaremos la clase base Matrix que realizamos en la entrada anterior.

Un poco de teoría

La suma de un conjunto de matrices A1, A2, …, An, es una de las operaciones más sencillas que se pueden realizar sobre esta estructura. Llevar a cabo esta suma depende en gran medida de que todas las matrices tengan igual dimensión y compartan el mismo valor para cada dimensión. Con esto, se da por entendido que no será posible sumar una matriz A de 3 x 2 con una matriz B de 4 x 2. Esto se justifica por la manera en que la suma de matrices se realiza.

El resultado de sumar dos matrices A y B es una nueva matriz C, que tiene en cada celda el resultado de sumar las correspondientes celdas de A y B, de modo que la primera celda de C, será C (0,0) = A (0,0) + B (0,0) y de manera general C (i,j) = A (i,j) + B (i,j) para todo par de indices válidos de A y B. Este procedimiento justifica el pre-requisito de que las dimensiones de todas las matrices coincidan. En resumen, la suma de n matrices se obtiene mediante la fórmula, C (i,j) = A1 (i,j) + A2 (i,j) + + An (i,j).

suma de matrices con pythonPuedes comprobar que los valores de las celdas de la primera fila de C coinciden con la suma de los valores de las celdas equivalentes en A y B.

5 = C (0,0) = A (0,0) + B (0,0) = 1 + 4

7 = C (0,1) = A (0,1) + B (0,1) = 2 + 5

9 = C (0,2) = A (0,2) + B (0,2) = 3 + 6

Pasemos al código

Para poder llevar a cabo la suma de matrices con python, el desarrollo del método suma queda de la siguiente manera:

def add(self, *matrix):
    """ Puede recibir varias matrices como argumentos """
    for i in range(self.rows):
        row = []
        for j in range(self.cols):
            tmp = self.get_value_of_position(i, j)
            for m in matrix:
                tmp += m.get_value_of_position(i, j)
            row.append(tmp)
        yield row

Como pueden observar, la función se implementa como un generador que retorna una fila (row) de la matriz C, cada que se alcanza la sentencia yield. Debo hacer mensión al ahorro de memoria que esto representa, ya que no estamos almacenando en memoria la estructura completa de C, lo cual es un beneficio cuando trabajamos sobre matrices de dimensiones considerables, esto se deriva de las bondades que nos brinda el uso de generadores.

Si visualizamos el código completo se encuentra de la siguiente manera:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# author: Gabriel Cueto <TheMushr00m - @Mushr00m_Dev>


class Matrix:
    _n = 0
    _m = 0
    _elems = None

    def __init__(self, n, m):
        """Inicializa la matriz con valor 0 en cada posición"""
        self._n = n
        self._m = m
        self._elems = []
        for i in range(self._n):
            self._elems.append([])
            for j in range(self._m):
                self._elems[i].append(0)

    def define_elem(self, i, j, v):
        """ Sobreescribe el valor de una celda """
        self._elems[i][j] = v

    def show_matrix(self):
        """ Imprime los valores almacenados en la matriz """
        for i in range(self._n):
            for j in range(self._m):
                # Imprime de una forma elegante la matriz
                print("| {0} ".format(self.get_value_of_position(i, j)), sep=',', end='')
            print('|\n')

    def get_cols(self):
        """ Devuelve el número de columnas en la matriz """
        return self._m

    def get_rows(self):
        """ Devuelve el número de filas en la matriz """
        return self._n

    def get_value_of_position(self, i, j):
        return self._elems[i][j]

    def add(self, *matrix):
        """ Puede recibir varias matrices como argumentos """
        for i in range(self.rows):
            row = []
            for j in range(self.cols):
                tmp = self.get_value_of_position(i, j)
                for m in matrix:
                    tmp += m.get_value_of_position(i, j)
                row.append(tmp)
            yield row

    cols = property(fget=get_cols)
    rows = property(fget=get_rows)

Recuerda que todo el código lo puedes encontrar en el repositorio en Github. Ahora, para poder ver en funcionamiento el método que creamos, podemos ejecutar algo como lo siguiente:

m1 = Matrix(3,3)
m1.define_elem(0,0,1)
m1.define_elem(0,1,2)
m1.define_elem(0,2,3)

m2 = Matrix(3,3)
m2.define_elem(0,0,4)
m2.define_elem(0,1,5)
m2.define_elem(0,2,6)

# Recorre el iterador generado
for e in m1.add(m2):
    print(e)

Seguro habrás observado, que la primera fila de m1 y m2 corresponden a los mismos valores mostrados en las matrices de la imagen de ejemplo A y B, la cual ilustraba la operación de suma de matrices. Por lo tanto, la primera fila del iterador resultante corresponde con la primera fila de la matriz C de la imagen. El resultado es el siguiente:


[5, 7, 9]
[0, 0, 0]
[0, 0, 0]

Y bien, es todo por esta ocasión, espero la explicación haya sido buena, cualquier comentario no dudes en dejarlo aquí abajo, o con confianza mencionalo por Twitter o en la Fanpage de Facebook, y aprovecho a invitarte para que me sigas en las redes.

Saludos.

Operaciones en matrices con Python – Creando la clase Base

matriz

Operaciones en matrices con Python

Hola a todos, luego de un tiempo sin escribir aquí les traigo esta entrada, la cual espero los ayude a entender este tema tan recurrente, como es el realizar operaciones en matrices con Python. En esta entrada veremos que es una matriz, y crearemos la clase que nos servirá de base para realizar las operaciones en las pr

Hasta el momento las entradas de esta serie han sido las siguientes:

Creando la clase Base

Suma de matrices

Producto por un escalar

Producto de matrices (Pendiente)

Transpuesta (Pendiente)

¿Qué es una matriz?

Las matrices son arreglos k-dimensionales donde se almacenan valores que pueden ser accedidos por indices. En las matemáticas, se conocen desde el año 200 a.C. y siempre han estado vinculadas al estudio de sistemas de ecuaciones. Toda una rama de esta ciencia está dedicada al estudio de matrices y durante mucho tiempo han sido ampliamente invetigadas.

Probablemente el caso más conocido de matriz se tenga cuando k = 2 (bidimensional), con n filas y m columnas, básicamente lo que se entiende por una tabla. A continuación podemos observar una matriz cuadrada donde n = m = 3.

operaciones en matrices con python

operaciones en matrices con python

Entre las operaciones más comunes en matrices se encuentran la suma, la resta y la multiplicación. Para comenzar el estudio de dichas operaciones, primero crearemos una clase matrix que represente a la estructura de datos y que en su momento servirá como contendor para diferentes funciones aplicadas sobre matrices.

#!/usr/bin/python
# -*- coding: utf-8 -*-
# author: Gabriel Cueto <TheMushr00m - @Mushr00m_Dev>


class Matrix:
    _n = 0
    _m = 0
    _elems = None

    def __init__(self, n, m):
        """Inicializa la matriz con valor 0 en cada posición"""
        self._n = n
        self._m = m
        self._elems = []
        for i in range(self._n):
            self._elems.append([])
            for j in range(self._m):
                self._elems[i].append(0)

    def define_elem(self, i, j, v):
        """ Sobreescribe el valor de una celda """
        self._elems[i][j] = v

    def show_matrix(self):
        """ Imprime los valores almacenados en la matriz """
        for i in range(self._n):
            for j in range(self._m):
                # Imprime de una forma elegante la matriz
                print("| {0} ".format(self.get_value_of_position(i, j)), sep=',', end='')
            print('|\n')

    def get_cols(self):
        """ Devuelve el número de columnas en la matriz """
        return self._m

    def get_rows(self):
        """ Devuelve el número de filas en la matriz """
        return self._n

    def get_value_of_position(self, i, j):
        return self._elems[i][j]

    cols = property(fget=get_cols)
    rows = property(fget=get_rows)

Como podrás observar, la matriz se inicializa con valor 0 en cada celda, y la modificación de estos valores tiene lugar mediante el método define_elem. Ahora es el momento de escribir el código para poder lograr nuestro objetivo, realizar operaciones en matrices. Esta de más decir, que los próximos métodos serán declarados como parte de la clase anterior.

Si deseas probar el código y visualizar como se genera la matriz, corre lo siguiente ya que tengas el código de la clase:

m = Matrix(3, 3)
m.show_matrix()

Espero el código de nuestra clase base haya quedado claro, si tienes alguna pregunta no dudes en hacerla en los comentarios, o mediante twitter.

Nuevamente te hago la invitación de que me sigas en mis redes, Twitter, Facebook, para que estes pendiente de nuevas entradas, charlas, proyectos, compartas contenido, etc.

Te pido una disculpa por si el código no se visualiza correctamente (sin identación), ya me encuentro trabajando en revisar esto, aunque creo que voy a enfocarme en el rediseño que estoy llevando a cabo para poder tenerlo pronto, sin embargo puedes encontrar todo el código en su repositorio de GitHub.

Gracias por leer la entrada, y no te pierdas las próximas donde realizaremos las operaciones con matrices. Saludos.