Mostrando entradas con la etiqueta Programación. Mostrar todas las entradas
Mostrando entradas con la etiqueta Programación. Mostrar todas las entradas

viernes, 14 de junio de 2024

Inicio


Definición de programación


Programar es ordenar una secuencia de pasos para conseguir el funcionamiento esperado en un ordenador. También se puede definir como la acción de crear programas o aplicaciones mediante el uso de un lenguaje de programación.


Existen múltiples lenguajes de programación, pero todos comparten características comunes, en su definición, en sus componentes y en la forma en que podemos esperar que funcionen.

Un lenguaje de programación es un lenguaje artificial que contiene signos, términos y estructuras, se rige por unas reglas sintácticas y produce unos resultados que son consecuencia del procesamiento de los datos con los que trabaja.

Los lenguajes de programación son lenguajes intermediarios entre el programador y el ordenador. Éste traduce a lo que se denomina "código máquina" las instrucciones que el programador escribe en determinado lenguaje de programación. El ordenador interpreta esas instrucciones, traduciéndolas a su lenguaje y ejecutándolas.

Lo interesante de la programación es que podemos adaptar el funcionamiento del ordenador a nuestras necesidades. Lenguajes como OOo Basic, por sus características especiales, nos permiten adaptar el funcionamiento de servicios de uso común en nuestro trabajo, como el procesador de texto, la hoja de cálculo o el programa de creación de presentaciones, para que se adapten a necesidades concretas y específicas de funcionamiento, lo que conlleva un ahorro de tiempo de trabajo.

No obstante también exige que aprendamos en qué consisten y cómo se usan esos lenguajes, lo que supone un tiempo de aprendizaje y una práctica. Pero podemos contar con la existencia de ciertas funcionalidades, como Crear macro, que nos facilitan el primer acercamiento al uso del lenguaje de programación. Gracias a ellas podemos empezar a "crear programas" sin otras exigencias de las que conlleva aprender a usar esas funcionalidades. No son suficientes para aprender a programar, pero ayudan a iniciar el camino.

Este blog está pensado para ayudar a que ese proceso de aprendizaje sea más llevadero, pero sobre todo que sea más funcional, al estar centrado en la solución de necesidades profesionales concretas. No es, por tanto, un blog para aprender a programar, ni tampoco para aprender a programar en OOo Basic; se trata (eso pretendo) de un blog para ayudar a los orientadores educativos en concreto, pero en general a los diferentes componentes de los SEO, a crear soluciones informáticas, funcionales y ajustadas a sus necesidades profesionales concretas. Y por tales entiendo el manejo de la documentación prescriptiva y la creación de la que resulta de la práctica profesional.

Otra forma de entender el para qué de este blog, es la de verlo como un recurso para el desarrollo de la competencia digital de los componentes de los SEO, la cual presenta ciertas particularidades que hace que, a mi juicio, las propuestas y los planes de la Administración educativa resulten demasiado genéricos ( o se se prefiere, poco específicos), dejando sin cubrir lo que deriva de la especificidad de estos (y otros) servicios educativos.

jueves, 13 de junio de 2024

LENGUAJES. Python

POO. Métodos

Modelos de programación

Cuando hablamos de los métodos como componentes de una clase, asimilamos éstos con las funciones, llegando incluso a insinuar que eran denominaciones intercambiables. Así son considerados por muchos autores, aunque puede que no de forma explícita, y no faltan razones para ello, ya que básicamente un método es una función. No obstante, el ser parte constituyente de una clase otorga a los métodos algunas diferencias respecto a las funciones que es necesario conocer para entender el código de terceros y para trabajar adecuadamente con ambos.

En esta entrada vamos a exponer las diferencias existentes entre una función y un método, las cuales radican fundamentalmente en el uso de parámetros y en las implicaciones que tiene la pertenencia del método a la clase para su uso por parte de los objetos.

La primera diferencia que debemos señalar entre una función y un método es que en los métodos no vamos a encontrarnos nunca el paréntesis vacío; como mínimo (y muy frecuentemente, como único) nos encontraremos con el parámetro self, que referencia a la clase y en su momento al objeto).

La segunda diferencia es que aunque el método utilice parámetros/atributos de la clase, no es necesario establecerlos como tales parámetros (y no se debe hacerlo), siendo suficiente con utilizar la formula self. nombre_atributo dentro de la función para que ésta utilice adecuadamente el valor que el parámetro tenga en el objeto.

La tercera diferencia es que para llamar al método desde el objeto no es necesario incluir valor alguno como argumento: ni para self ya que es el propio objeto, ni para los argumentos, ya que están definidos previamente en la construcción del objeto.

Bien podría ser que el método en su formulación abstracta (como parte de la clase) cuente con parámetros o con variables específicas (y privadas) no contempladas como atributos. En ese caso deberemos proceder del mismo modo que hacemos con las funciones tanto en la construcción del método como en el momento de llamarlo desde (y en función del) objeto.

Vamos a presentar un ejemplo en el que el método de una clase cuenta con un parámetro no incluido como atributo (aunque en realidad bien podría serlo) y una variable privada. Podemos comparar el funcionamiento de este script con el que se desarrolló en su momento para comprobar unas diferencias que explicaremos a continuación.

En el archivo actual, ni los argumentos ni el constructor de la clase se diferencia del archivo inicial...



def __init__(self,nombre,edad):
        self.nombre = nombre
        self.edad = edad


... pero sí el método sentarse(). Observa el original...



def sentarse(self):
        print(f"{self.nombre} se sienta cuando yo se lo ordeno (y ell quiere, claro).")
        

... y el actual.



 def sentarse(self,sexo):
        if sexo =="perrito":
            tratamiento = "educado"
        else:
            tratamiento= "educada"
        print(f"Mi {sexo} {self.nombre} tiene {self.edad} años. Está muy bien {tratamiento} y se sienta cuando se lo pido.")
        

  • Podemos identificar ambos como métodos (y no funciones) por el hecho de que ni en el primero ni en el segundo nombre y edad (ambos atributos identificados como tales en la construcción de la clase) son declarados como parámetros y por ser empleados dentro de print() mediante la auto-referencia self.nombre, por ejemplo)
  • Además, el parámetro self presente en ambos métodos, nos confirma que se trata de métodos, ya que este parámetro no se usa en funciones.

De hecho si formulásemos el método como función podríamos hacerlo como sigue (obviamente en este caso no se generan atributos ni se utiliza una función de inicialización):



def sentarse(nombre,edad,sexo):
    if sexo=="perrito":
        tratamiento = "educado"
    else:
        tratamiento = "educada"
    print(f"Mi {sexo} se llama {nombre} y tiene {edad} años. Es muy {tratamiento} ya que se sienta cuando yo se lo ordeno.")
    

Fíjate que, a consecuencia de ello, además de trabajar con los parámetros de una forma claramente diferente, en el print() de la función las variables incluidas como parte de la cadena f no se expresan mediante la sintaxis del punto, como sí hacemos en sus dos formulaciones como método.

Finalmente vamos a ver las diferencias en el modo de hacer la llamada a la función y al método.



# Función (tras cuestionario asociado a variables/argumentos)

sentarse(perro_nombre,perro_edad,perro_sexo)

# Método (formulación simple)

perrita = MiPerro("Atenea",10) -> Creación del objeto
perrita.sentarse() -> Llamada al método

# Método (formulación similar a función, esto es: con cuestionario previo)

perro = MiPerro(perro_nombre,perro_edad) -> Creación del objeto
perro.sentarse(perro_sexo) -> Llamada al método


Al margen de lo que implica trabajar con clase-objeto, primero nos vamos a fijar en las similitudes y diferencias entre la llamada a la función y la llamada al método.

Llamar a la función equivale a desarrollar en una única instrucción el doble proceso de creación de objeto y de llamada al método que se produce cuando trabajamos con clases y objetos. La presencia necesaria de argumentos se concreta en la función en el momento de ser llamada, mientras que en el método se diferencia en función del doble proceso de creación del objeto, que se produce una vez y ya no tiene que volver a repetirse, lo que supone una ahorro importante de trabajo en caso de utilizar el objeto múltiples veces y con diferentes métodos, y la llamada al método propiamente dicho, que se resume como llamada a método sin más en su forma más simple, o que puede incluir algún parámetro en caso de haberse incluido alguno, como es el caso del segundo método.

Pero volvamos al análisis de la formulación del método en sus dos versiones: la más simple no incluye parámetros añadidos ni variables privadas, por lo que se presenta en su forma más simple, tanto en su definición como parte de la clase...



def sentarse(self):
        print(f"{self.nombre} se sienta cuando se lo ordeno (y quiere, claro).")

... como al ser llamada desde el objeto
perrita.sentarse()


La segunda formulación incluye el uso de un parámetro no establecido como argumento en la definición de la clase sexo, y una variable privada tratamiento.



def sentarse(self,sexo):
        if sexo =="perrito":
            tratamiento = "educado"
        else:
            tratamiento= "educada"
        print(f"Mi {sexo} {self.nombre} tiene {self.edad} años. Está muy bien {tratamiento} y se sienta cuando yo se lo pido.")
        

Fíjate en las implicaciones de la presencia de este parámetro y de esta variable en cómo se escriben las variables en la cadena f: ninguno de los dos se formula con self, mientras que sí se utiliza con las variables-argumentos.

Esta diferencia en el tratamiento se traslada después a la llamada al método, que incluye explicitar el argumento asociado al parámetro sexo: perro.sentarse(perro_sexo)

Esta diferencia entre ambos métodos es más importante en lo que estamos tratando en la presente entrada que el hecho de que en la creación del objeto en una formulación introduzcamos directamente los valores que concretan los parámetros perrita = MiPerro("Atenea",10).

Mientras que en la segunda asociamos dichos parámetros a sendas variables que nos permiten modificar de forma interactiva (input) el valor de los atributos.



perro_nombre = input("Nombre del perro: ")
perro_edad = eval(input("Edad del perro: "))
perro_sexo = input("perrito o perrita: ")

perro = MiPerro(perro_nombre,perro_edad)
perro.sentarse(perro_sexo)


Aunque esta formulación se asemeje aparentemente a la fórmula empleada en la función...



perro_nombre = input("Dime el nombre de tu perro: ")
perro_edad = eval(input("¿Cuántos años tiene? "))
perro_sexo = input("¿Es perrito o perrita? ")

sentarse(perro_nombre,perro_edad,perro_sexo)


... si te fijas bien hay una diferencia que revela que se trata de dos formas diferentes de abordar la cuestión: en la función empleamos los tres argumentos, mientras que en el objeto utilizamos dos argumentos para establecer el contenido de los parámetros en la construcción del objeto y utilizamos el tercero perro_sexo como parámetro del método, dado que (el método) cuenta con ese parámetro en su definición y lo utiliza para dar contenido a la variable privada que tiene el método tratamiento

Es posible que todo esto te haya parecido algo lioso, incluso poco relevante. No lo es, créeme. De no ser tenido en cuenta se producirán errores que impiden que funcione todo correctamente y tú no comprenderías el código de terceros que empleen parámetros y variables dentro de los métodos.

Para ayudarte a comprender con ejemplos estas diferencias te dejo acceso a los tres archivos que me han servido de ejemplo:

LENGUAJES. Python

POO. Atributos II

Modelos de programación

Una de las tareas que con más frecuencia debemos realizar al trabajar con objetos es dar valor a los atributos y modificar esos valores. En la entrada anterior en la que comparamos funciones con métodos ya estuvimos trabajando sobre ello, así como en la entrada referida a los atributos. Ahora nos vamos a centrar en esta cuestión de forma específica.

Caben tres posibilidades para modificar el valor de un atributo:

  • Modificarlo directamente
  • Modificarlo mediante un método específico
  • O modificarlo de forma incremental, también mediante un método

Partiremos de una clase simple, en cuyos objetos no se tiene pensado modificar el contenidos de los atributos, para ir mostrando las tres opciones enunciadas antes.



class coche:
    def __init__(self,marca,modelo,anno):
        self.marca=marca
        self.modelo=modelo
        self.anno=anno

    def descripcion(self):
        coche_descripcion= f"Mi coche es un {self.marca} {self.modelo} de {self.anno}"
        return coche_descripcion

mi_coche=coche("Seat","Toledo",1996)
texto=mi_coche.descripcion()
print(texto)


La única novedad que presenta este script es que el método descripcion(self) devuelve return una cadena f que describe el objeto, por lo que su uso debe asociarse a una variable texto Por lo demás, presenta un funcionamiento de sobre conocido.

Para explicar las implicaciones de la modificación de atributo, deberemos incluir en la definición de atributos uno que no figure como parámetro, por ejemplo, el valor del cuentakilómetros, así como un método para mostrar el cuentakilómetros actual del vehículo. Esto modifica la definición de la clase como sigue:



class coche:
    def __init__(self,marca,modelo,anno):
        self.marca=marca
        self.modelo=modelo
        self.anno=anno
        self.cuentakilometros=0 

    def descripcion(self):
        coche_descripcion= f"Mi coche es un {self.marca} {self.modelo} de {self.anno}"
        return coche_descripcion

    def cuentaK(self):
        print(f"El cuentakilómetros de mi coche marca {self.cuentakilometros} kilómetros")
        

Procedamos ahora a introducir/modificar el valor inicial del parámetro cuentakilometros directamente en la definición del objeto mi_coche



mi_coche=coche("Seat","Toledo",1996)
mi_coche.cuentakilometros = 1200
texto=mi_coche.descripcion()
print(texto)
mi_coche.cuentaK()


Una vez definido el objeto mi_coche=coche("Seat","Toledo",1996) establecemos el valor del atributo no definido como parámetro (y en consecuencia no establecido ya como valor en la definición del objeto) mediante la expresión basada en la sintaxis del punto mi_coche.cuentakilometros = 1200. Posteriormente llamaremos a este método de forma directa mi_coche.cuentaK() ya que originalmente no cuenta con la instrucción return.

La segunda opción consiste en modificar el atributo mediante un método específico, el siguiente...



    def cuentaK(self, km_actuales):
        self.cuentakilometros = km_actuales
   print(f"El cuentakilómetros de mi coche marca {self.cuentakilometros} kilómetros")
   

... que asocia el valor dado al atributo km_actuales al parámetro cuentakilometros que después se imprime por pantalla mediante print(): mi_coche.cuentaK(1200)

Finalmente veamos cómo se concreta el método que permite incrementar el valor del parámetro, añadiéndolo como método nuevo.



class coche:
    def __init__(self,marca,modelo,anno):
        self.marca=marca
        self.modelo=modelo
        self.anno=anno
        self.cuentakilometros=0

    def descripcion(self):
        coche_descripcion= f"Mi coche es un {self.marca} {self.modelo} de {self.anno}"
        return coche_descripcion

    def cuentaK(self,kilometraje):
        self.cuentakilometros =kilometraje

    def leer_cuentaK(self):
        print(f"Este coche ha recorrido {self.cuentakilometros} Km")

    def incrementarKm(self,km):
        self.cuentakilometros += km
        

Observa que he eliminado la instrucción print() del método cuentaK() primitivo y he creado un método específico de escritura de los Km que lleva recorridos el coche leer_cuentaK(). De este modo diferenciamos ambos procesos: dar valor al atributo cuentakilometros y escribir el resultado. El objetivo es reutilizar este método cuando incrementemos los kilómetros, que es lo que hacemos con el método incrementarKm()

Este es el método que nos permite incrementar los kilómetros inicialmente establecidos mediante el método cuentaK(). Observa que incrementarKm() tiene dos parámetros: el obligatorio self y km, que serán los km que incrementemos cada vez que usemos el método. La instrucción de este método consiste en añadir km al dato que contiene el atributo cuentakilometros.

Desde el lado de la creación de un objeto asociado a la variable mi_coche...



mi_coche=coche("Seat","Toledo",1996)
texto=mi_coche.descripcion()
print(texto)
mi_coche.cuentaK(1200)
mi_coche.leer_cuentaK()
mi_coche.incrementarKm(100)
mi_coche.leer_cuentaK()


... podemos apreciar los cuatro métodos de la clase, incluyendo el uso repetido del método leer_cuentaK(): primero para informar de los km del cuentakilómetros y después para informar del resultante tras el incremento.

Te dejo a continuación el código de estos script:

LENGUAJES. Python

POO. Atributos(I)

Modelos de programación

Aunque ya vimos qué son los atributos, no está demás completar la información ya que la definición de atributo no se limita a lo expuesto y esas carencias tienen repercusiones.

Ahora sigo a Matthes, E (2021:186-191) en lo que se refiere a las formas en que se puede plantear la modificación de los atributos. Por ello, en principio, trataré sobre la definición de atributos y posiblemente en una próxima entrada sobre su modificación.

Los tributos son, como ya sabemos, los datos que caracterizan a una clase y se concretan como tales en los objetos o instancias de esa clase. Como tales datos se guardan en memoria, identificando esa dirección de memoria con un nombre de variable, de ahí que podamos redefinir los atributos como las variables que caracterizan al objeto.

Como tales variables, en el momento de la construcción de la clase (o lo que es lo mismo: en el momento en que utilizamos esa función especial a la que llamamos constructor, y que en Python se expresa como función __init__() tenemos tres opciones para definir las variables/atributos:

  • Opción A, la utilizada en la entrada referenciada al inicio de la actual siguiendo a Matthes, E(2021:182-186), estableciendo los atributos como parámetros de la función, tras el parámetro self
  • Opción B, la que utiliza Cuevas, A (2016:186-192) en su completa y complicada explicación de cómo se construye una clase: incluyéndolas como parte del desarrollo de la función __init__() pero sin incluirlas como parámetros de la función-constructor.
  • Y la opción C, mezcla de las anteriores: incluyendo unos como parámetros y otros según B.

Todas estas opciones son válidas y es posible encontrarlas como explicación en diferentes documentos, incluyendo los vídeos de YouTube. Lo que no siempre encontrarás es una explicación de por qué estas diferencias y qué implicaciones tienen. Vamos a hablar de ello a continuación.

En primer lugar, no existe (que yo sepa) implicación respecto al funcionamiento de la clase y de los objetos derivados de ella: tan clase y tan objeto es una que utilice parámetros en el constructor como que no los use, al margen de self, claro, cuyo uso es obligado. Pero las implicaciones son evidentes: si usamos parámetros "atributivos" en __init__() esto va a tener consecuencias en la sintaxis de escritura de la clase y de los objetos:

  • En cómo se escribe la función __init__():
    • Lo obvio: con/sin parámetros
    • Y en la forma en que inicializa el parámetro
  • En cómo se definen los atributos del objeto
  • Y finalmente en cómo se aborda el cambio de esos atributos

Veamos cada una de estas cuestiones en un ejemplo concreto como puede ser la clase perro utilizada en otra entrada. En ella se utilizaba exclusivamente la opción A.



def __init__(self,nombre,edad):
    self.nombre = nombre
    self.edad = edad
    

Al declarar los atributos como parámetros nombre, edad inicializarlos consiste en referenciarlos a la propia clase mediante la expresión self.nombre = nombre

Por ello crear un objeto exige responder a la lógica de la relación parámetro-argumento que ya vimos en las funciones, incluyendo el dato en que se concreta el atributo: MiPerro(Atenea,10)

Frente a esto, la opción B resolvería la función __init__() y la inicialización de los atributos como sigue:



def __init__(self):
    self.nombre = ""
    self.edad = 0 


Ahora la inicialización de los atributos (de clase) no es una auto-referencia como cuando los declaramos como parámetros self.nombre = nombre. Aunque seguimos utilizando la auto-referencia y la sintaxis del punto (de pertenencia jerárquica, podríamos decir) self.nombre, ya no podemos remitir a la propia variable (que después se concretará como dato-argumento en la declaración del objeto). Debemos inicializarlo con un valor, que puede ser 0 y su equivalente (cadena vacía), como es el caso self.nombre = ""

Al crear el objeto ya no podemos incluirlo como argumento en la función correspondiente, como si sucedía en el modelo A perrita = MiPerro("Atenea",10). Auqnue mejor habría que decir "ni debemos", ya que en A no emplear estos argumentos genera error. En B sucede lo mismo si lo hacemos (ya que no existen como parámetros en __init__(): perrita = MiPerro() es ahora la forma de crear el objeto como perteneciente a la clase MiPerro, el cual queda identificado mediante la variable que lo referencia perrita ya que, en caso de no realizarse esta asignación del objeto a la variable, se crearía el objeto, pero como objeto anónimo. Obsérvese que tras el nombre de la clase se sitúan dos paréntesis MiPerro(), mientras que en la identificación de la clase no se hace uso de tales class MiPerro:. Por contra, no se utilizan los dos puntos (:, que sí lo están en la definición de la clase (y de las funciones). En resumen, estamos usando la sintaxis de la llamada a una función.

La alternativa es asignar contenido a los argumentos utilizando la sintaxis del punto, tomando como referencia el nombre del objeto al que se asocia el argumento en la definición de la clase perrita.nombre = "Azucena". De ello se deriva que mientras en A la creación del objeto y la asignación de valores a los atributos se resuelve como parte de la llamada a la función (identificación como miembro de la clase perrita = MiPerro("Atenea",10), en B primero se define la relación de pertenencia del objeto a la clase y después se asignan datos/valores a los atributos, que se identifican como tales (y no come meras variables) por medio de la sintaxis del punto:

perrita = MiPerro()
perrita.nombre = "Azucena"
perrita.edad = 10

Nótese la ausencia de sangrado y lo que esto supone entre la línea de creación del objeto y las de datación de los atributos.

El resultado de ambos procedimientos (A y B) es el mismo si aplicamos las mismas demandas:



print(f"Nombre: {perrita.nombre}")
print(f"Edad: {perrita.edad}")
print(f"Mi perrita se llama {perrita.nombre} y tiene {perrita.edad} años")
perrita.sentarse()


Nombre: Atenea
Edad: 10
Mi perrita se llama Atenea y tiene 10 años
Atenea se sienta cuando yo se lo ordeno (y ella quiere, claro).

... y cabe entender que el uso del modelo mixto (C) supone aplicar ambos procedimiento tanto en la inicialización de los atributos como en la creación del objeto. Un ejemplo sencillito, añadiendo sexo como tercer parámetro. Supongo que intuyes cual puede ser el resultado...



class MiPerro:
    def __init__(self,nombre,edad):
        self.nombre = nombre
        self.edad = edad
        self.sexo =""
    def sentarse(self):
        print(f"{self.nombre} se sienta cuando yo se lo ordeno (y ella quiere, claro).")
perro = MiPerro("Casimiro",10)
perro.sexo = "perrito"
print(f"Nombre: {perro.nombre}")
print(f"Edad: {perro.edad}")
print(f"Mi {perro.sexo} se llama {perro.nombre} y tiene {perro.edad} años")
perro.sentarse()


LENGUAJES. Ptthon

POO. Clase y objeto

Modelos de programación

Después de introducirnos en los conceptos básicos de la POO, en esta entrada vamos a aprender a identificar y crear (en abstracto) una clase y un objeto o instancia de esa clase. Esto nos servirá de base para iniciarnos en la práctica de la POO en lenguajes de programación y más concretamente en Python.

Una clase se define, como vimos en la entrada anterior, por ser una representación abstracta de objetos concretos que son, a su vez, instancias o concreciones de esa clase. La clase posee características (en POO atributos) y funcionalidades (que se concretan mediante funciones y que en POO se denominan métodos). La POO permite tratar ambas (características y funciones -> atributos y métodos) como un todo, lo que facilita el manejo del código.

Para crear una clase debemos utilizar la palabra reservada (por ejemplo Class), y darle un nombre identificador. Por convención, los nombres de las clases se inician con mayúscula, lo que la diferencian del nombre del objeto y de los métodos de la clase. Según los lenguajes, este proceso inicial puede precisar ser marcado de algún modo, por ejemplo, mediante (:) En Python class ClaseNombre:

El paso siguiente es utilizar un constructor de la clase, variando de procedimiento según en el lenguaje. En Python se realiza como sigue:

  • Definimos una función especial que consta de las siguientes partes:
    • El definidor def
    • El nombre de la función __init__, que se caracteriza por ir precedido y seguido por dos guiones bajos sucesivos
    • Y la definición de parámetros, que inician por convención por self, que hace referencia a la clase y a su constructor...
    • finalizando mediante :, como cualquier otra función def __init__(self,param1,param2):.
  • Referenciamos los parámetros que nos permiten identificar y dar valor inicial a los atributos de la clase, utilizando la referencia a la propia clase y a su constructor, al que queda asociado el atributo mediante la sintaxis del punto:
    • self.param1 = param1
    • self.param2 = param2

Finalmente creamos los métodos, de modo similar a como creamos las funciones. Estos métodos pueden contar con parámetros (o no) y devolver return datos (o no). En su formulación más simple (sin parámetros ni retorno) se expresan (en Python) como sigue:



def metodo1(self):
    contenidoDelMétodo
	

    Instanciar un objeto de la clase anterior consiste, básicamente, en hacer referencia de esa clase a la hora de declarar el objeto para posteriormente acceder a sus atributos y a sus métodos recurriendo a la sintaxis del punto.

    • Nombramos (declaramos) la instancia u objeto asociándolo a modo de variable a la clase y concretando como argumentos sus atributos. En Python mi_objeto = ClaseNombre(ValorArg1,ValorArg2) -> Los argumentos son concreciones de los atributos de la clase en el objeto.
    • Accedemos a los atributos mediante la sintaxis del punto... mi_objeto.param1 Recuerda que el parámetro es en realidad el atributo1 de la clase que se ha concretado en la creación del objeto como ValorArg1
    • ... y de forma similar a los métodos mi_objeto.metodo1()

    Ya que un ejemplo puede aclarar las cosas, paso a desarrollar uno en Python. El objetivo es mostrar el desarrollo de una concreción del proceso anterior siguiendo las explicaciones que proporciona Eric Matthes (2020:181-185)

    
    
    # Clase Perro
    
    class MiPerro:
    
     def __init__(self,nombre,edad):
    
    self.nombre = nombre
    
    self.edad = edad 
    
     def sentarse(self):
    
             print(f"{self.nombre} se sienta cuando yo se lo ordeno (y ella quiere, claro).")
    
    # Instancia u objeto de la clase MiPerro
    
    perrita = MiPerro("Atenea",10)
    
    # Acceso a los atributos de perrita:
    
     print(f"Mi perrita se llama {perrita.nombre} y tiene {perrita.edad} años")
    
    # Acceso al método creado en la clase
    
    perrita.sentarse() 
    
    
    

    Evidentemente es posible desarrollar clases mucho más complejas en cuanto a atributos y métodos, así como crear tantas instancias de la clase (objetos) como necesitemos. Pero para el propósito de esta entrada es suficiente con lo anterior. Su resultado (output) es el siguiente:

    Mi perrita se llama Atenea y tiene 10 años
    Atenea se sienta cuando yo se lo ordeno (y ella quiere, claro).

jueves, 14 de marzo de 2024

LENGUAJES. OOo Basic

Imperativa vs. Estructurada

Modelos de programación

No vamos a entrar en explicaciones teóricas complejas sobre estos temas, ya que el lector puede encontrar buena documentación en la web o en la bibliografía especializada. Pero ciertas nociones al respecto son necesarias para nuestra práctica. Así que iniciamos aquí una brever sección sobre modelos de programación tratsando sobre dos modelos básicos de programación: la lineal (o imperativa) y la estructurada (o modular).

Estas denominaciones pueden no ser muy precisas para la teoría y la historia de los modelos de programación, pero nos son útiles ya que nos permitirán diferenciar dos estrategias, hoy por hoy las de mayor uso en este blog.

Las tres estructuras básicas de la programación son la linealidad o sucesión lineal, la bifurcación y la iteración. Con ellas se construyen los algoritmos que son, en lo fundamental, combinaciones más o menos complejas y más o menos extensa de estas tres estrategias, si bien, según el modelo de programación, primarán unas u otras. Por ejemplo, en la programación imperativa es fundamental el uso de la estrategia lineal.

La programación imperativa, que yo voy a asimilar al concepto de linealidad, es el modelo de programación más antiguo, según el cual un programa es una secuencia de instrucciones sucesivas. Integra también el uso de ciclos o bucles y condicionales, pero se caracteriza por el uso de la instrucción GoTo.

Mediante GoTo se redirige el programa a una posición determinada de la secuencia de instrucciones, en función de determinadas condiciones. Este modo de proceder es fuente de que un código lo que en principio parece simple, termine por convertirse en complejo, y sobre todo difícil de seguir y actualizar.

Es el modelo de programación que subyace a los lenguajes Basic iniciales. Hoy en día no se emplea debido a las dificultades de gestión y mantenimiento que colleva y por requerir largas secuencias de instrucciones.

Como alternativa, surgió el modelo de programación estructurada (década de 1960), una de cuyas evoluciones a posteriori fue el modelo de programación modular.

Al contrario de la programación imperativa, en la programación estructurada no se hace uso de la sentencia GoTo, optando por el uso de subrutinas ejecutadas (eso sí) secuencialmente, y privilegiando el uso de las estructuras de control (condicionales, ciclos e iteraciones o ciclos con condición inicial)

Una evolución (según algunos autores) de la programación estructurada es la programación modular que se caracteriza por subdividir un programa en módulos o subprogramas a los que se recurre en función del desarrollo del algoritmo, lo que la diferencia de la programación estructurada, que mantiene el principio de linealidad en es uso de las subrutinas. Una ventaja añadida del modelo modular es la posibilidad de reutilizar código (módulos) en función de necesidades, lo que reduce la extensión del programa final.

Después de esta breve introducción, me interesa justificar su utilidad de cara a que entendamos el proceso de diferenciación que paulatinamente vamos a ver desarrollado cuando nos iniciemos, por ejemplo, en el conocimiento de los procedimientos de trabajo que vamos a implementar en OOo Basic.

También será de interés a la hora de analizar cómo trabajar de forma más funcional con el código que genera Grabar macro y nuestra conversión del mismo en subrutinas o en funciones diferenciadas.

miércoles, 13 de marzo de 2024

Inicio


La programación como recurso para los SEO


Queda mucho para que la programación informática se considere parte de la competencia digital de los SEO; el estado actual de esta competencia está muy lejos de este objetivo, en mentalidad y en conocimientos, por lo que no se puede esperar que los orientadores asuman que el pensamiento computacional forma parte de su perfil competencial. 


La Administración educativa asume que esta competencia tiene carácter genérico, lo que, en la práctica, implica suponer que viene "de serie", con lo que no parece dispuesta a exigirla ni a considerarla específicamente como parte de la formación que ofrece. Y por lo visto, en la práctica, tampoco a dar ejemplo de su aplicación.

Por si éramos pocos, las muchas veces simplemente falsas promesas de la IA hacen aun más difícil que se plantee siquiera ese objetivo: ¿para qué aprender a programar si ya lo hace la IA?.

Nada de esto es cierto, al menos no en la forma simplista en que lo expreso, pero me temo que sea el planteamiento más frecuente, y no sólo en nuestro colectivo profesional. Sin duda la IA puede aportar mucho (menos de lo que pretende, posiblemente), pero no va a ser ninguna panacea, salvo que alguien interesado en el tema cree una IA específicamente diseñada para resolver estas nuestras necesidades. Mientras tanto, como tantas veces, podemos esperar sentados... o aprender a programar.

Saber programar supone un salto cualitativo fundamental para que los SEO sean competentes a la hora de crear las herramientas de trabajo  que necesitan, bien para automatizar la gestión de la documentación profesional, bien para crear herramientas que se ajusten a nuestras necesidades.

No es un proceso sencillo, ya que se requiere conocimiento y práctica, por lo que lleva tiempo. Pero tampoco es tan difícil en sus formas básicas pero suficientes para producir recursos que respondan satisfactoriamente a lo que necesitamos. Y para muestra el botón que ejemplifica el uso de los lenguajes de macros (script) basados y desarrollados sobre los propios documentos y pensados para automatizar su elaboración.

Con el objetivo de fundamentar el desarrollo de esta competencia (programar), he creído necesario empezar por el conocimiento de los elementos básicos del lenguaje OOo Basic. Estos conocimientos, además de necesarios para manejarse con este lenguaje, son en gran medida compartidos por todos los lenguajes de programación, con lo que sirve para futuros procesos de aprendizaje. Puedes encontrar estos conocimientos introductorios en la sección OOo Basic.

sábado, 15 de julio de 2023

OOo Basic. Script

Macros. Programación modular

Además de utilizar las macros como resultado de la ejecución de Grabar macro también podemos utilizarlas como elementos discretos a modo de subrutinas. Este enfoque se encuentra a medio camino entre la creación de macros y la escritura de script o programación. Ambos procedimientos pueden ser, además, complementarios. En todo caso remite a [lo que expuse] sobre la programación lineal o imperativa y la programación modular.



Es importante remarcar esa idea de complementariedad, ya que en informática (también) las cuestiones pueden se resolver de diferentes maneras (aunque unas pueden ser mejores que otras), así que lo que no sepamos resolver mediante un script, podemos abordarlo mediante una macro.

Pues bien, si en la [entrada anterior] aprendimos a identificar el contenido de una macro secuencial y a diferenciar diferentes funciones, en esta entrada vamos a profundizar en el modo de trabajo que podemos llamar programación modular que podemos caracterizar por el uso de secuencias de acciones (macros unitarias o de función única) combinadas. 

Este modo de trabajo admite la combinación entre macros unitarias y script, combinación que permite desarrollar programas de cierta complejidad. Algunos ejemplos de ello podemos verlos en [aquí]

Para el correcto desarrollo de un docap basado en este tipo de macros es necesario posicionar correctamente las variables básicas de toda macro, así como crear una macro específica en la que dichas variables se asocien a sus contenidos. Esta macro deberá ser llamada desde las macros individuales, permitiendo así su reutilización, con el consiguiente ahorro de tiempo.

A parte de esto, es importante crear colecciones de macros individuales, necesariamente asociadas al servicio-soporte, las cuales pueden ser aplicadas modularmente cuando sea necesario.

Aunque puede considerarse que es este un modo un tanto rudimentario de "programar", podemos decir que es similar al enfoque funcional y que algunos programas de cierta complejidad (FileMaker, por ejemplo) disponen de recursos de "programación" que, en síntesis, no son otra cosa que una colección amplia de funcionalidades, algo similar en filosofía a lo que aquí se plantea.


jueves, 2 de febrero de 2023

LENGUAJES. Python

POO. Conceptos básicos

Modelos de programación

Para empezar, desde la perspectiva con la que estamos trabajando, podemos decir que la programación orientada a objetos (POO) es un desarrollo de la programación funcional en la que "empaquetamos" juntos (en una clase) una serie de variables que contienen datos relevantes sobre ese algo con el que queremos trabajar (atributos) y una serie de funciones, que ahora llamamos métodos y que representa el comportamiento típico e igualmente relevante de ese algo. Ese algo es la concreción de la clase y se llama objeto, que no es otra cosa que una instancia de la clase.

La clase es una abstracción y el objeto es su concreción. Como tal abstracción, la clase contiene la definición de las característica relevantes que se concretarán en cada objeto que instanciemos, además de las acciones o funciones potencialmente relevantes (para nuestro algoritmo) que después desarrollarán (o no y cuando resulte pertinente) los objetos que instanciemos.

La POO se acerca al modo en que funcionan las cosas en la realidad, lo que facilita el desarrollo de programas sostenibles y fáciles de mantener, compuesto por piezas simples y reutilizables que interaccionan entre si. Además, al igual que sucede con la programación funcional, son pertinentes los conceptos de abstracción y encapsulamiento, ambos complementarios entre sí. Esta pertinencia refuerza la idea de que la POO está emparentada con la programación funcional:

  • Abstracción: Es posible utilizar una clase sin conocer cómo está implementada, siempre que sepamos cómo hacerla funcionar, lo que consigue mediante un contrato o conjunto de instrucciones.
  • Encapsulamiento: Este desconocimiento hace que la clase funciones como una caja negra, de modo que ignorar cómo está constituida no afecta a nuestra capacidad de utilizarla.

Basado en Alberto Cuevas(2016. img pag 185)

Gracias a la aplicación de estos conceptos, es factible evitar el acceso no deseado a la configuración de las clases en el uso de los objetos instanciados, evitando alteraciones en su funcionamiento.

Otros dos conceptos fundamentales en la POO son la herencia y el polimorfismo:

  • Por herencia entendemos que una clase puede provenir de una super clase (clase o nivel de abstracción superior) o ser base para la creación de clases derivadas, secundarias o subclases. Entre la superclase, la clase y las subclases existe una relación que denominamos herencia por la cual las clases derivadas heredan las características de las clases de las que proceden.
  • Finalmente, el polimorfismo permite que una característica (definida en la superclase) se concrete de forma diferente en cada una de las clases derivadas.

Para una mejor comprensión de los conceptos anteriores te propongo este vídeo de BitBoss en You Tube.

jueves, 26 de enero de 2023

LENGUAJES. Ooo Basic

Programación funcional. Conceptos básicos

Modelos de programación

Hemos estado hablando de funciones y es momento para detenernos brevemente en comprender qué implica su uso y qué supone basarnos en ellas para desarrollar un algoritmo.

Trabajar con funciones consiste, en esencia, en subdividir un problema general en partes y afrontar cada una de esas partes de modo independiente. Reconstruir el todo consiste en desarrollar procedimientos para interrelacionar las partes dando respuesta al interrogante que inicialmente constituyó el todo.

Aunque esto pueda parecer muy abstracto, en realidad es una forma muy común de proceder cuando nos encontramos con problemas complejos. El famoso "vamos por partes..." no es más que la vulgarización de esta filosofía de trabajo.

Desde el punto de vista de la programación, el siguiente esquema representa el procedimiento de trabajo que supone aplicar el modelo funcional.

A partir de un problema planteado genéricamente, vamos identificando sucesivamente las diferentes partes en que se puede descomponer, ideándolas como funciones, hasta llegar a la función más simple que ya no es necesario o no es posible descomponer. Este procedimiento se denomina diseño de arriba abajo y consiste en aplicar un proceso de refinamiento gradual o por etapas.

En esto consistirá la primera fase del desarrollo del proyecto, siendo la segunda el desarrollo de cada una de las funciones y su implementación en la estructura de relaciones que hemos representado esquemáticamente en la imagen anterior. Este segundo proceso se puede desarrollar, a su vez, mediante dos estrategias básicas:

  • De arriba abajo
  • De abajo arriba

Las ventajas de este modo de trabajar se pueden resumir como sigue:

  • Simplifica la resolución de problemas complejos.
  • Facilita la comprensión del algoritmo
  • Simplifica la realización de pruebas y la depuración del código
  • Permite reutilizar código
  • Reduce el tiempo de escritura del programa
  • Genera programas más fáciles de mantener y de modificar
  • Facilita trabajar en grupo y la propia organización de este modo de trabajo.

La programación funcional hace uso intensivo de dos conceptos que podemos considerar interrelacionados: abstracción y encapsulamiento.

Aplicándola a la programación funcional, entendemos por abstracción la cualidad que posee una función de poder diferenciar su definición de su uso. Definir una función implica saber cómo es su funcionamiento interno. La abstracción nos permite desconocer dicho funcionamiento sin que ello afecte al uso de la función, siempre que respetemos su forma de funcionar.

Desde esta perspectiva, la función se comporta como una caja negra (encapsulamiento), de modo que desconocer su código no nos impide beneficiarnos de su funcionalidad. Si la función es mejorada, seguiremos ajenos a su conocimiento, pero nos beneficiaremos de esta mejora igualmente. Esto tiene muchas ventajas (ver el listado anterior), siendo posible, por ejemplo, diferenciar el trabajo de los diferentes creadores del código, y el de estos del que precisa un usuario. También hace posible realizar mejoras parciales sin afectar al funcionamiento general del programa.

Para finalizar esta breve incursión por la programación funcional, decir que existen funciones recursivas que son especialmente interesantes por simplificar procesos de programación que, de realizarse de modo lineal, supondrían aplicar complejos procesos iterativos. Una función recursiva es sencillamente aquella que se llama a si misma. Veamos un sencillo ejemplo realizado en Python:



def factorial(n):
    if n==0:
        return 1
    else:
        return n * factorial(n-1) # En este punto se produce la reutilización de la función
   dentro de la misma función (recursividad)

def main():
    n=eval(input("Introduce un entero positivo para calcular su factorial: "))
    print("El factorial de ", n , " es ", factorial(n))

main()


lunes, 7 de noviembre de 2022

LENGAUJES. OOo Basic

Programación modular

Modelos de programación

Cuando un programa o una aplicación es de cierta complejidad, ésta se refleja en su extensión en número de líneas, pero también, en su complejidad. Dentro de estos dos parámetros podemos incluir la repetición de una serie de líneas de código con funcionalidad específica que se pueden identificar como unidades de acción.

Cuando tomamos estas unidades de acción como objeto de análisis, las aislamos del desarrollo del script principal y las llamamos desde éste, pasamos de usar un modelo lineal de programación a un modelo modular. Este modelo supone una simplificación de los procedimientos de trabajo y una economía de tiempo. Esto es posible porque los segmentos de código pueden ser llamados desde el algoritmo principal tantas veces como sea necesario, ahorrándonos así su reescritura.

La programación modular no rompe la lógica del modelo lineal, simplemente hace más eficiente la codificación, más sostenible y más robusta. Además, esos segmentos pueden ser reutilizados en otros programas o aplicaciones, lo que incrementa la eficiencia a la hora de desarrollar proyectos.

En líneas generales, el comportamiento de estos módulos que llamaremos funciones, en sentido general, por cumplir una función específica, presentan estos comportamientos:

  • En este esquema he representado el script principal y dos funciones que son empleadas por dicho script. La flecha verde representa el discurrir del algoritmo, que, como se puede ver, sigue un proceso lineal (de arriba abajo).
  • La funciónSecundario A toma el control del flujo en el momento en que es llamada (en ese momento es A quien determina qué hace nuestro algoritmo), finaliza su cometido y devuelve el control al script principal, que reanuda el desarrollo del algoritmo
  • La función Secundario B es llamada (utilizada) por el script principal, se ejecuta y devuelve al script principal el resultado de su propio procesamiento, pero no toma el control del desarrollo del algoritmo, que sigue siendo responsabilidad del script principal.

Esta simplificación nos permite apreciar el modo en que funciona la relación entre el programa principal y sus auxiliares. También nos muestra que existen diferentes formas de concretarse el papel de estos auxiliares, aunque depende del lenguaje de programación que estemos empleando.