SUPUESTO 1

LA LAURISILVA DE ANAGA, EL BOSQUE MÁGICO. NORESTE DE TENERIFE.

      La razón de este título es la intención de hacer un pequeño paréntesis en la introducción de contenidos del lenguaje para mostrar un ejemplo, un poco más elaborado que los habituales a los que hemos recurrido hasta ahora, para poner "negro sobre blanco" algunos aspectos interesantes que hemos aprendido juntos hasta ahora. En él, un simple módulo Python cien por cien operativo que hemos dado en llamar seguridad.py, veremos aspectos que ya conocemos relacionados sobre todo con la Programación Orientada a Objetos en la que estamos actualmente inmersos, como las clases, por ejemplo, y algunos destellos de programación más avanzada, con los métodos estáticos.



El módulo seguridad.py crea un sistema de consultas que, en un taller de mecánica del automóvil,  permite valorar el estado de respuesta (revisión) de los diferentes dispositivos y mecanismos del vehículo relacionados con la seguridad.
Lo que vamos a hacer a continuación es mostrar el módulo tal cual para luego ir comentándolo paso a paso.



seguridad.py

class Seguridad(): 1
  """EVALÚA SUCINTAMENTE EL ESTADO DE LOS DISPOSITIVOS Y MECANISMOS DE        SEGURIDAD DEL VEHÍCULO -> STRING"""
  def __init__(self): 2
pass
print("*****************************")
print("***** ÁREA DE SEGURIDAD *****") 3
print("*****************************")
@staticmethod 4
def observaciones_y_recomendaciones():
obs = input("Observaciones: ")
        print(obs)
        recom = input("Recomendaciones: ")
        print(recom)
        print(" ")
@staticmethod 4
def estado():
print("Criterio de evaluación")
print("******************")
print("1: óptimo\n"
          "2: mejorable\n"
          "3: funcionalidad limitada\n"
          "4: mal estado")
dictevalest = {
"1":"óptimo",
"2":"mejorable",
"3":"funcionalidad limitada",
"4":"mal estado"
}
valest = input("Introducir una valoración general del estado de los dispositivos y mecanismos de seguridad del automóvil de acuerdo a los números de la izquierda: ")
print("El estado general del elemento es: ", dictevalest.get(valest))
def cinturones_de_seguridad(self):
"""Evalúa el estado general de los cinturones de seguridad -> string"""
print("CINTURONES DELANTEROS")
print("**********************")
cintdel = input("¿Observa algún tipo de rotura y/o desgaste en alguna de las correas de sujeción delanteras? (s/n): ") 5
self.cintdel = cintdel
if cintdel == "n":
pass
if cintdel == "s":
Seguridad().observaciones_y_recomendaciones() 6
print("ANCLAJES/BLOQUEADORES")
print("··············")
anclajesdel = input("¿Funcionan correctamente los anclajes/bloqueadores? (s/n): ")
self.anclajesdel = anclajesdel
if anclajesdel == "s":
pass
if anclajesdel == "n":
Seguridad().estado()
Seguridad().observaciones_y_recomendaciones()
print("TENSORES")
print("···············")
tnsdel =  input("¿Tensan adecuadamente los tensores de las correas de sujeción delantera? (s/n): ")
self.tnsdel = tnsdel
if tnsdel == "s":
pass
if tnsdel == "n":
Seguridad().estado()
Seguridad().observaciones_y_recomendaciones()
print("RECOGIDA")
print("···············")
recdel =  input("¿Se recogen adecuadamente las correas de sujeción delanteras? (s/n): ")
self.recdel = recdel
if recdel == "s":
pass
if recdel == "n":
Seguridad().estado()
Seguridad().observaciones_y_recomendaciones()
print("CINTURONES TRASEROS")
print("********************")
cinttra = input("¿Observa algún tipo de rotura y/o desgaste en alguna de las correas de sujeción            delanteras? (s/n): ")
self.cinttra = cinttra
if cinttral == "n":
pass
if cinttral == "s":
Seguridad().observaciones_y_recomendaciones()
print("ANCLAJES/BLOQUEADORES")
print("··············")
anclajestra = input("¿Funcionan correctamente los anclajes/bloqueadores? (s/n): ")
self.anclajestra = anclajestra
if anclajestra == "s":
pass
if anclajestra == "n":
Seguridad().estado()
Seguridad().observaciones_y_recomendaciones()
print("TENSORES")
print("···············")
tnstra =  input("¿Tensan adecuadamente los tensores de las correas de sujeción delanteras? (s/n): ")
self.tnstra = tnstra
if tnstra == "s":
pass
if tnstra == "n":                      
Seguridad().estado()
Seguridad().observaciones_y_recomendaciones()
print("RECOGIDA")
print("···············")
rectra =  input("¿Se recogen adecuadamente las correas de sujeción delanteras? (s/n): ")
self.rectra = rectra
if rectra == "s":
pass
if rectra == "n":
Seguridad().estado()
Seguridad().observaciones_y_recomendaciones()
def segnaletica_cuadro_mandos(self):
        """Evalúa el estado de la señalética del cuadro de mandos --> string"""
Seguridad().observaciones_y_recomendaciones()
def cierre_centralizado(self):
        """Evalúa el estado del dispositivo de cierre centralizado --> string"""
        Seguridad().observaciones_y_recomendaciones()
def reposacabezas(self):
        """Evalúa el estado de los reposacabezas --> string"""
        Seguridad().observaciones_y_recomendaciones()
def seguridad__vial(self):
"""Evalúa la existencia, estado y funcionalidad de los elementos de seguridad del vehículo en              caso de accidente o avería del vehículo --> string"""
print("*********************************")
print("***** ÁREA DE SEGURIDAD VIAL *****")
print("*********************************")
print("TRIÁNGULOS (Juego de triángulos)")
print("·················································")
triangulos = input("¿Existe juego de triángulos? (s/n): ")
self.triangulos = triangulos
if triangulos == "s":
pass
if triangulos == "n":
print("Reponer triángulos con urgencia")
trihom = input("¿El juego de triángulos está homologado de acuerdo a las directivas vigentes              de la DGT? (s/n): ")
self.trihom = trihom
if trihom == "s":
pass
if trihom == "n":
print("Adecuar el juego de triángulos a la normativa vigente lo antes posible")
Seguridad().observaciones_y_recomendaciones()
print(" ")
print("GATO (Elevador manual del vehículo)")
print("····················································")
gato = input("¿Existe gato/elevador? (s/n): ")
self.gato = gato
if gato == "s":
pass
if gato == "n":
print("Reponer el gato con urgencia")
Seguridad().observaciones_y_recomendaciones()
print(" ")
print("RUEDA DE REPUESTO TRADICIONAL")
print("·····················································")
ruedarepuesto = input("¿Existe rueda de repuesto? (s/n): ")
self.ruedarepuesto = ruedarepuesto
if ruedarepuesto == "s":
pass
if ruedarepuesto == "n":
print("Reponer la rueda de repuesto con urgencia")
rdarepresion = input("¿Tiene la presión adecuada? (s/n): ")
self.rdarepresion = rdarepresion
if rdarepresion == "s":
pass
if rdarepresion == "n":
print("Regular cuanto antes la presión de la rueda de repuesto de acuerdo a las especificaciones del fabricante")
Seguridad().observaciones_y_recomendaciones()
print(" ")
print("KIT ANTIPINCHAZOS") 7
print("·····························")
kitanti = input("¿Utiliza el vehículo un kit antipinchazos como sustituto de la rueda de repuesto tradicional? (s/n): ")
self.kitanti = kitanti
if kitanti == "n":
pass
if kitanti == "s":
setkitanti = input("¿Dispone el vehículo de kit antipinchazos? (s/n): ")
self.setkitanti = setkitanti
if setkitanti == "s":
pass
if setkitanti == "n":
print("Reponer cuanto antes el kit antipinchazos")
kitantihom = input("¿Está homologado el kit antipinchazos de acuerdo a la normativa en vigor? (s/n): ")
self.kitantihom = kitantihom
if kitantihom == "s":
pass
if kitantihom == "n":
print("Sustituir cuanto antes el kit antipinchazos por otro homologado según la normativa vigente")
Seguridad().observaciones_y_recomendaciones()
print(" ")
print("RUEDA DE REPUESTA TIPO GALLETA")
print("limitación de velocidad y/o distancia")
print("···················································")
rrg = input("¿El vehículo utiliza como rueda de repuesto una rueda de tipo 'galleta'? (s/n): ")
self.rrg = rrg
if rrg == "n":
pass
if rrg == "s":
setrrg = input("¿Dispone el vehículo de una rueda de repuesto de tipo galleta? (s/n): ")
self.setrrg = setrrg
if setrrg == "s":
pass
if setrrg == "n":
print("Reponer la rueda de repuesto con urgencia")
Seguridad().observaciones_y_recomendaciones()
print(" ")
print("NEUMÁTICOS DE TIPO RUNFLAT")
print("***** rodaje sin presión *****")
print("············································")
runflat = input("¿El vehículo dispone de ruedas de repuesto con neumáticos de tipo RUNFLAT? (s/n): ")
self.runflat = runflat
if runflat == "n":
pass
if runflat == "s":
print("Reponer el neumático inmediatamente")
Seguridad().observaciones_y_recomendaciones()
print(" ")
print("NEUMÁTICOS DE TIPO SEALANT")
print("****** autorreparables ******")
print("············································")
sealant = input("¿El vehículo dispone de ruedas de repuesto con neumáticos de tipo SEALANT? (s/n): ")
self.sealant = sealant
if sealant == "n":
pass
if sealant == "s":
print("Reponer el neumático inmediatamente")
Seguridad().observaciones_y_recomendaciones()
print(" ")
print("CHALECOS REFLECTANTES")
print("·····································")
chalecos = input("¿Dispone el vehículo de suficientes chalecos reflectantes? (s/n): ")
self.chalecos = chalecos
if chalecos == "s":
pass
if chalecos == "n":
print("Reponer un número adecuado de chalecos reflectantes con urgencia")
chalhom = input("¿Están los chalecos reflectantes homologados de acuerdo a las directivas de seguridad de la DGT? (s/n): ")
self.chalhom = chalhom
if chalhom == "s":
pass
if chalhom == "n":
print("Sustituir cuanto antes los chalecos actuales por chalecos homologados")
Seguridad().observaciones_y_recomendaciones()
print(" ")
def cajetin__de__herramientas(self):
"""Evalúa el contenido y pertinencia del cajetín de herramientas --> string"""
cajher = input("¿El vehículo cuenta con una caja de herramientas? (s/n): ")
self.cajher = cajher
if cajher == "n":
pass
if cajher == "s":
setcajher = input("¿Dispone el vehículo de cajetín de herramientas? (s/n): ")
self.setcajher = setcajher
if setcajher == "s":
pass
if setcajher == "n":
print("Reponer cuanto antes el cajetín de herramientas")
print("EVALUACIÓN DEL SET DE HERRAMIENTAS")
print("*****************************************")
print("LLAVES DE TUBO")
print("························")
llavtub = input("¿Incluye llaves de tubo de calibre 6 a 24 y 30 y 32? (s/n): ")
self.llavtub = llavtub
if llavtub == "s":
pass
if llavtub == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("LLAVES PLANAS (MIXTAS)")
print("·····································")
llavplan = input("¿Incluye llaves planas de calibre 6 a 24 y tipo 'carraca'? (s/n): ")
self.llavplan = llavplan
if llavplan == "s":
pass
if llavplan == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("LLAVES DE CODO")
print("·························")
llavcod = input("¿Incluye llaves de codo de calibre 6 a 24? (s/n): ")
self.llavcod = llavcod
if llavcod == "s":
pass
if llavcod == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("CAJA DE BOQUILLAS TAMAÑO 4 A 14")
print("····················································")
b1 = input("¿Incluye la caja de boquillas? (s/n): ")
self.b1 = b1
if b1 == "s":
pass
if b1 == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("CAJA DE BOQUILLAS TAMAÑO 8 A 32 + CARRACA")
print("·····································································")
b2 = input("¿Incluye la caja de boquillas? (s/n): ")
self.b2 = b2
if b2 == "s":
pass
if b2 == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("LLAVES TIPO ALLEN")
print("····························")
llavall = input("¿Incluye llaves de tipo Allen de calibre 4 a 10? (s/n): ")
self.llavall = llavall
if llavall == "s":
pass
if llavall == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("LLAVES TIPO TORX")
print("···························")
llavtorx = input("¿Incluye llaves de tipo Torx de calibre 10 a 50? (s/n): ")
self.llavtorx = llavtorx
if llavtorx == "s":
pass
if llavtorx == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("DESTORNILLADORES DE PUNTA PLANA Y ESTRELLA")
print("········································································")
dest = input("¿Incluye, al menos, 4 tamaños distintos por tipo? (s/n): ")
self.dest = dest
if dest == "s":
pass
if dest == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("DESTORNILLADORES DE TIPO TORX")
print("··················································")
destorx = input("¿Incluye destornilladores Torx de calibre 10, 15, 20, 25 y 30? (s/n): ")
self.destorx = destorx
if destorx == "s":
pass
if destorx == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("ALICATES")
print("··············")
alireg = input("¿Incluye unos alicates de tipo regular? (s/n): ")
self.alireg = alireg
if alireg == "s":
pass
if alireg == "n":
print("Reintegrar piezas faltantes")
alicor = input("¿Incluye unos alicates de tipo corte? (s/n): ")
self.alicor = alicor
if alicor == "s":
pass
if alicor == "n":
print("Reintegrar piezas faltantes")
aliuni = input("¿Incluye unos alicates de tipo universal? (s/n): ")
self.aliuni = aliuni
if aliuni== "s":
pass
if aliuni== "n":
print("Reintegrar piezas faltantes")
print(" ")
print("HERRAMIENTAS ESTÁNDAR")
print("······································")
print("Espejo")
print("-------")
espejo = input("¿Contiene un espejo pequeño o de mano? (s/n): ")
self.espejo = espejo
if espejo == "s":
pass
if espejo == "n":
print("Reponer pieza")
print("Llaves para filtro del aceite")
print("··································")
llavfil = input("¿Contiene una llave para el filtro del aceite? (s/n): ")
self.llavfil = llavfil
if llavfil == "s":
pass
if llavfil == "n":
print("Reponer pieza")
print("Martillo")
print("···········")
martillo = input("¿Contiene un martillo? (s/n): ")
self.martillo = martillo
if martillo == "s":
pass
if martillo == "n":
print("Reponer pieza")
print("Buril")
print("·······")
buril = input("¿Contiene un buril? (s/n): ")
self.buril = buril
if buril == "s":
pass
if buril == "n":
print("Reponer pieza")
print("Cutter")
print("········")
cutter = input("¿Contiene un cutter? (s/n): ")
self.cutter = cutter
if cutter == "s":
pass
if cutter == "n":
print("Reponer pieza")
print("Linterna/lámpara portátil")
print("······························")
lint = input("¿Contiene una linterna o lámpara portátil? (s/n): ")
self.lint = lint
if lint == "s":
pass
if lint == "n":
print("Reponer pieza")





      HEMOS PROCURADO QUE ESTE PRIMER EJEMPLO EN SUPUESTO 1 (ESPERAMOS SUMAR ALGUNOS SUPUESTOS MÁS) SEA BASTANTE SENCILLO PARA FACILITAR LA CURVA DE APRENDIZAJE, Y NO FATIGAR EN EXCESO LA CONCENTRACIÓN, POR LO QUE HEMOS PRESCINDIDO DE IMPORTACIONES Y SE HA DESARROLLADO PARA EL CASO UNA ARQUITECTURA REITERATIVA, CON UN USO AMPLIO DE CONDICIONALES (BIFURCACIONES EN EL FLUJO DE EJECUCIÓN) QUE PERMITAN APUNTALAR EN LA MEMORIA, SIN MUCHO ESFUERZO, CADA CONCEPTO EXPUESTO.

En 1 modelizamos la clase Seguridad sin mayor complejidad, tal y como ya hemos aprendido a hacerlo, y justo debajo, insertamos un docstring con información casi telegráfica, como dictan los cánones pythónicos, sobre lo que la clase (y el módulo seguridad.py en sí mismo ya que, como veremos, se trata de un módulo monoclase, es decir, de un módulo Python que sólo contiene una única clase y no varias relacionadas entre sí, ergo el módulo ejecutará exactamente lo que ejecute la clase). En él señalamos que lo que vamos a obtener como devoluciones, al menos, en la mayoría de los casos, son cadenas de texto (string). Podríamos, y es recomendable, introducir en el propio docstring algún/os ejemplos de ejecución del código para dar una mejor idea de lo que nuestro módulo seguridad.py es capaz de hacer. Podríamos proceder del modo siguiente: seleccionamos un par de métodos que consideremos representativos y lo insertamos en el docstring. Lo vemos.



En 2 incluimos el inicializador (también llamado comúnmente, constructor, aunque, como ya hemos dicho aquí, el "auténtico" constructor es el método especial __new__(), que opera en segundo plano, y que es el encargado real de construir "el coche", valga la analogía, (observemos que no lleva el autorreferente self en su zona de parámetros, ya que no actúa sobre los objetos que vayamos a instanciar de la clase sino sobre la clase misma, dándole, por así decirlo, "carta de vida") mientras que el método especial __init__(self), el inicializador, es el encargado de "arrancar el motor", de "girar la llave de contacto", valga de nuevo la analogía, para que nuestro flamante coche haga precisamente aquéllo para lo que lo hemos comprado (observemos que lleva el autorreferente self en su zona de parámetros, ya que actúa sobre los objetos que vayamos a instanciar de la clase transfiriéndoles las propiedades/atributos y los métodos que hayamos instanciado en la clase).
Si ejecutamos el programa sin más, obtenemos esto:


La razón de este comportamiento singular está en 3. Aquí tenemos tres funciones print() indentadas al mismo nivel que el resto de los métodos de la clase Seguridad y situadas por debajo del inicializador. Podríamos haber situado estas funciones por encima del inicializador, que sería lo más lógico, pero lo hemos hecho así a propósito para demostrar la manera en que funciona __init__() y, con él, en segundo plano, insistimos, el verdadero constructor __new__() en una clase.
Se muestra al principio de todo porque, a pesar de que ya hemos modelizado la clase Seguridad, todavía no hemos instanciado ningún objeto de la clase, por lo que el método __init__(self) descansa, duerme, reposa aún, dulcemente, en los laureles del Olimpo sin hacer absolutamente nada.
Observemos lo que ocurre a continuación en cuanto instanciamos un objeto a partir de la clase Seguridad y que llamaremos, de aquí en adelante, coche:



Fijémonos que es en el momento de comenzar a instanciar un objeto/instancia de Seguridad (todavía no lo está porque no hemos dado el salto a una nueva línea de código señalada con un nuevo prompt) cuando se nos muestra la información que pertenece a la clase: el docstring.
En el momento en que cerramos el paréntesis de la clase y pulsamos ENTER para saltar a una nueva línea de código, se produce una INSTANCIACIÓN, es decir, la CREACIÓN de una instancia (o un objeto, que también por este nombre podemos llamar a la criatura) mediante la ejecución del código interno, con lo que ya tenemos entre nuestros brazos amorosos una nueva instacia/objeto de clase (de la clase que hemos asignado al objeto mediante el operador = de asignación, ojo, al crear la instacia/objeto, en nuestro supuesto, Seguridad(), y no de otras clases y subclases posibles que hayamos modelizado en nuestro módulo) recién alumbrada al maravilloso mundo de Python.



De manera sucinta, la idea básica por la que se instacia un objeto (a partir de aquí prescindiremos de usar ambos nombres, instancia/objeto, y usaremos sólo el nombre objeto) es la de crear un elemento (objeto Python) capaz de hacer algo (normalmente, devolver un resultado) mediante el uso de las propiedades y métodos que le proporciona (le transmite) la clase al objeto que hemos creado (instanciado) de ella.
Por esta razón, como vemos en la captura superior, cuando aplicamos la sintaxis del punto (dott method) sobre nuestro objeto coche, nada más colocarlo al pie, a su derecha, el IDLE de Python, así como cualquier otro IDE de nuestro gusto que queramos utilizar para programar, nos abrirá por defecto un menú contextual con todas las propiedades y métodos de la clase donde se instanció susceptibles de ser aplicados (transmitidos) al objeto. Como los programadores de Python son gente consciente y de buen corazón, se han preocupado de mostrar las opciones en orden alfabético y subrayar en azul la opción que podemos elegir, pudiendo navegar entre ellas a través de los cursores de arriba/abajo, ⇧⇩, para seleccionar la que queremos invocar (transmitir de la clase al objeto) sobre nuestro objeto coche.

PÍJARA, WOODWARDIA RADICANS. HELECHO TÍPICO DE LAS ZONAS MÁS HÚMEDAS DE LA LAURISILVA Y EL MONTEVERDE DE TENERIFE.

Como ya sabemos, los métodos que podemos invocar de la clase "madre" para transmitir a coche (en nuestro ejemplo no hemos instanciado propiedad alguna que podamos invocar) son aquéllos que hayamos instanciado previamente en el cuerpo o ámbito de nuestra clase Seguridad(), convenientemente indentados o sangrados como no puede ser menos de acuerdo a la sintaxis de Python, de modo análogo al cuerpo o ámbito de las funciones definidas por el usuario, funciones def, que ya hemos estudiado y que, recordemos, es la manera en que instanciamos métodos dentro de las clases. De hecho, todo método en una clase es, en un 99%, o un método especial (como __init__() que llamamos directamente del objeto clase como tal y que ya estudiaremos más adelante), o una función def, definida por nosotros mismos en el cuerpo o ámbito de la clase con mayor o menor dolor de cabeza por nuestra parte.
En nuestra clase, en 4, contamos con dos métodos estáticos, static methods, que no vamos a ver ahora con profundidad ya que le dedicaremos su capítulo correspondiente más adelante, pero del que sí veremos un poquito su funcionalidad por aquéllo de ir haciendo boca.
Estos métodos se declaran de forma parecida a los decoradores, decorators, (v. decorators) con su arroba delante, @, y el  nombre predeterminado staticmethod detrás: @saticmethod. De manera muy básica, estos métodos, aunque se declaran dentro de la clase, es como si existieran "fuera" o "al margen" de ella, ya que no llevan ninguna referencia ni a la propia clase donde se instancian (self), en nuestro supuesto, la clase Seguridad(), ni al objeto que podamos instanciar de ella y, claro, si no llevan la autorreferencia self no pueden acceder ni a las propiedades ni a los métodos de la clase por lo que, por sí mismas, no aportan nada al objeto (coche, en nuestro supuesto) dado que ni siquiera pueden acceder a él. Su función fundamental es "redondear" las virtudes de la clase, complementar el trabajo, extender alguna que otra funcionalidad.

      PODEMOS IMAGINARNOS LA SIGUIENTE ANALOGÍA: UN ESCRITOR O ESCRITORA (PROGRAMADOR) ESCRIBE UN NUEVO LIBRO, UNA NOVELA DE AVENTURAS, (CLASE), "EL CAPITÁN McPYTHON CONTRA EL REY DE JAVALANDIA.py", DENTRO DE LA SERIE DE AVENTURAS ESCRITAS SOBRE EL CAPITÁN McPYTHON (MÓDULO "AVENTURASDELCAPITÁNMcPYTHON.py"). LA CLASE  CONTIENE A SU VEZ VARIOS MÉTODOS: UN ÍNDICE, LA NOVELA EN SÍ, CON SUS CAPÍTULOS (SUBMÉTODOS, CLOSURES), Y UNA SINOPSIS DE LOS PERSONAJES DE LA OBRA.  CUANDO UN USUARIO/A INSTANCIA EL OBJETO "LECTURA",  PODRÁ SUMERGIRSE AL INSTANTE EN EL RELATO, PODRÁ LEER LOS CAPÍTULOS PARA VER CÓMO SE DESARROLLA LA HISTORIA, CONSULTAR EL ÍNDICE, PARA VER CÓMO TRANSCURRE LA HISTORIA, O CONSULTAR LA SINOPSIS PARA NO OLVIDARSE DE LAS CARACTERÍSTICAS DE LOS PERSONAJES PRINCIPALES DE LA HISTORIA Y NO PERDERSE EN LA TRAMA. ES DECIR, TODOS LOS MÉTODOS QUE HEMOS MENCIONADO AYUDAN AL USUARIO QUE HA INSTANCIADO EL OBJETO "LECTURA" A LEER, COMPRENDER Y DISFRUTAR DE LA HISTORIA: GIRAN EN TORNO AL CONSTRUCTO HISTORIA.
PERO HE AQUÍ QUE DENTRO DEL LIBRO  CONTAMOS CON DOS MÉTODOS MÁS: UN APARTADO DEDICADO A ESBOZAR LA TRAYECTORIA VITAL Y PROFESIONAL DEL AUTOR/A DE LA NOVELA, Y OTRO DEDICADO A RESEÑAR OTRAS OBRAS DEL AUTOR/A. AMBOS ESTÁN EN LA CLASE LIBRO, PERO NINGUNO DE LOS DOS CONTRIBUYE A MEJORAR NUESTRA EXPERIENCIA DE LECTURA, NO FORMAN PARTE DE LA HISTORIA Y NO AFECTAN AL OBJETO LECTURA: NADA TIENEN QUE VER CON ELLOS. Y SIN EMBARGO COMPLEMENTAN LO QUE NOS APORTA LA CLASE: CONOCEMOS MEJOR A NUESTRO ESCRITOR/A DE NOVELAS DE AVENTURAS FAVORITO Y NOS ENTERAMOS DE LA EXISTENCIA DE OTRAS OBRAS ESCRITAS POR ÉL/ELLA CON LOS QUE PODER DISFRUTAR DE NUEVAS DELICIOSAS NOCHES DE LECTURA EN LA CAMA A LA LUZ DE UNA LÁMPARA DE MESA.


Aunque en este ejemplo no tiene mucho sentido aplicarla, podemos ilustrar el uso que podemos hacer de la función predefinida isinstance() en nuestro modelo. Recordemos que cualquier función nativa o definida que Python contenga en su seno generoso, si ésta comienza con la partícula "is" ("es...", en castellano) debemos interpretarla como una pregunta (para la función isinstance(), "¿Es una instancia?") que obtendrá por respuesta un tipo de dato booleano: o True, si es verdad, o False, si no lo es. La función lleva dos argumentos obligatorios: el nombre que le hemos dado a nuestro objeto/instancia, y el nombre de la clase en la que suponemos que lo hemos instanciado. Esto viene bien para saber si tal nombre corresponde a un simple nombre de variable (la versión técnica, que ya hemos visto al comienzo de este manual vendría a ser: si tal referencia a un espacio de memoria...) o un simple dato/valor, con lo que la función isinstance() devolvería False sin pensárselo dos veces, o si por el contrario es el nombre de un objeto instanciado a partir de la clase cuyo nombre pasamos como segundo argumento, con lo que la función isinstance() devolvería un True como la copa de un pino. También devolverá True si dicho objeto ha sido instanciado en la clase que le pasamos como segundo argumento, o False si el nombre de la clase es otro DISTINTO a donde se instanció el objeto en cuestión.
De todas formas, siempre nos servirá como un medio seguro para certificar que, efectivamente, se ha instanciado ese objeto (el primer argumento de la función) en la clase (el segundo argumento de la función), con lo que podremos relajarnos y codificar con absoluta tranquilidad.


Para el caso que nos ocupa obtenemos lo siguiente:



Más adelante volveremos a hablar de la función isinstance(), repasando lo que acabamos de decir y relacionándola con la herencia en Python, pero lo más importante, por así decirlo, está dicho ya.
Continuamos probando nuestra clase y llamamos sobre el objeto coche que acabamos de instanciar de la clase Seguridad(), por ejemplo, el método cinturones_de_seguridad(). Este método, junto a todos los demás, pertenecen a la clase Seguridad(): se han instanciado dentro de su cuerpo, en su propio ámbito, en el "ecosistema de la clase". Por eso, llevan la autorreferencia self en su zona de parámetros como primer argumento obligatorio (self siempre debe ser el primer argumento de la zona de parámetros de un método instanciado en una clase cualquiera. A partir de él podremos insertar todos los argumentos que creamos oportunos siguiendo el orden correcto, recordemos: argumentos obligatorios primero, y argumentos opcionales después). Cuando instanciamos un objeto de la clase, este objeto, coche en nuestro ejemplo, hereda TODOS los métodos y propiedades de la clase a la que pertenece. Y para llamarlos, invocarlos, sobre nuestro objeto y poder hacer uso de ellos, recurrimos a la sintaxis del punto, al dott method.



Veamos qué sucede en cuanto llamamos al método cinturones_de_seguridad() sobre nuestro objeto coche:



¿Qué ha sucedido? Pues que el flujo de ejecución del programa se desplazó al área/zona del código donde se encuentra el método cuyo nombre coincide con el que hemos seleccionado en virtud del método o notación del punto, el dott method, con el que lo llamamos. Esto lo consigue Python, básicamente, gracias al namespace (el espacio de nombres). De aquí la importancia de diferenciar claramente los elementos del programa que deban invocarse por un nombre, como las variables, los nombres con los que definimos nuestras funciones, los métodos y las propiedades que instanciamos en una clase, etc.

ADENTRÁNDONOS EN LA LAURISILVA DE ANAGA, NORESTE DE TENERIFE.

Observamos que para poder llamar al método, como tal, hay que abrir y cerrar paréntesis al final del nombre. En el inconsciente profundo de Python, estos paréntesis no son otra cosa que tuplas normales y corrientes, pseudotuplas, más bien, si se nos permite el "palabro", que delimitan un espacio donde podemos colocar los parámetros que necesitemos para que la función se ejecute correctamente: es lo que se llama "zona de parámetros". Y son tuplas y no listas, conjuntos o diccionarios porque esperamos que los parámetros que pasemos a su interior no puedan ser modificados directamente, salvo en el caso de los parámetros opcionales, los argumentos de tipo **kwargs, que incorporan el operador = y que podemos modificar en la llamada a la función, actuando como pares clave/valor de manera análoga a los diccionarios. En el caso de que no los lleve, se usará igualmente un espacio delimitado entre paréntesis, dado que esto es preceptivo de acuerdo a la sintaxis del lenguaje y debemos hacerlo sí o sí, pero vacío, limpio, sin nada en su interior.
De hecho, podemos espaciar cuanto queramos la zona de parámetros (la distancia entre entre el paréntesis de apertura y el de cierre) y la llamada al método continuará siendo válida para Python:


En el caso de que llamáramos a una propiedad no incluiríamos los paréntesis ya que esto es un rasgo exclusivo de las llamadas a métodos justo por lo que acabamos de mencionar más arriba, y que en la gramática simple de Python permite discriminar entre métodos y propiedades instanciados en una clase de manera rápida y eficaz, como hemos comprobado en los capítulos anteriores.
Fijémonos en el detalle de que en la llamada al método cinturones_de_seguridad() no incluimos la autorreferencia self, precisamente, por ser eso: una referencia establecida por convención para señalar que tal método pertenece a la clase pero que, por sí mismo, no tiene incidencia alguna para su ejecución, que es lo que queremos (que se ejecute, que actúe) sobre el objeto que hemos instanciado de la clase, que es para lo que lo hemos llamado. Comprobémoslo:


Si remontamos en la capturas de pantalla de este capítulo y localizamos aquélla en la que llamamos al método cinturones_de_seguridad() por primera vez, veremos que en el docstring, que es el lugar donde se nos proporciona información sobre el método, al principio, en la primera línea, se muestra un paréntesis, una zona de parámetros, vacío. Dado que no muestra parámetro de ningún tipo, es así como debemos invocar al método. Por eso, si incluimos en la llamada la autorreferencia self, Python lanzará una excepción de tipo NameError, en tanto que Python no tiene ni la más remota idea de qué es eso de self dado que no se encuentra en los namespaces correspondientes a la clase ni a sus instancias.
Para ilustrar esto que acabamos de explicar, vamos a hacer una pequeña modificación en nuestra clase Seguridad(), donde la cabecera (header) del método cinturones_de_seguridad() quedaría así:


Sencillamente, lo que hemos hecho ha sido añadir el parámetro numero (recordemos que como la ortografía de Python, como en casi todos los lenguajes de programación, se basa en el inglés, es preferible no utilizar símbolos y grafos propios de las lenguas vernáculas de cada cual, como la tilde o la ñ en caso del español, para evitar errores de codificación, salvo en las impresiones y salida de información (outputs)) a la zona de parámetros de nuestro método cinturones_de_seguridad(), y para que se pueda comprobar su funcionalidad, añadimos en el cuerpo (ámbito, scope) del mismo, un simple print() para que nos informe del número total de cinturones de seguridad de nuestro objeto coche.
Si instanciamos el objeto y llamamos al método método cinturones_de_seguridad() para aplicarlo sobre él, esto es lo que obtenemos cuando se dispara el docstring:


Y cuando completamos los requisitos del método con el paso de argumentos (le damos a numero el valor 5), esto es lo que obtenemos:


Tengamos en cuenta que numero es un parámetro que pertenece al método pero no a la clase, por lo que no podemos llamarlo con el parámetro self de autorreferencia, esto es, self.numero porque nos daría un error de tipo AtributteError, advirtiéndonos que el objeto Seguridad, es decir, la clase, no tiene un atributo o propiedad que se llame numero. Veámoslo en una nueva pequeña modificación y en la llamada posterior.


Si hubiéramos optado por pasar numero como un parámetro opcional, el resultado hubiera sido el mismo. En nuestro caso, le asignamos a numero el valor de inicialización None, aunque podríamos haber pasado un número cualquiera. Lo vemos:




Como observamos, el flujo de código se sitúa en la primera entrada de datos, input, en 5, a través del método input() que usa Python para obtener datos externos (los proporcionados por el usuario, por ejemplo). La opción es s (sí) o n (no). Imaginemos, pues, que estamos revisando los cinturones delanteros, tal y como nos informa el intitulado, y como no encontramos roturas ni desgastes apreciables en los cinturones de piloto y copiloto, seleccionamos la opción n.
Al hacerlo, el dato esperado (n o s), en nuestro caso, n, entra al programa asignándose a la variable cintdel y éste compara el dato obtenido con el objeto de comparación (==) del primer condicional if dado que la lectura va siempre de arriba a abajo y de izquierda a derecha. La comparación determina que "n", que es el dato que hemos proporcionado, pues, tengámoslo en cuenta, todo dato/valor que entra a través de un input() lo hace como un tipo de dato string (cadena), coincide como tal con "n", como dato en sí  y como tipo de dato (es una string). La evaluación resulta pues, positiva y, automáticamente, se ejecuta el código correspondiente estableciéndose la bifurcación. Como el código para el caso es la cláusula pass, Python no ejecuta nada (no hay nada que ejecutar) y sale de la bifurcación para ejecutar el segundo condicional if, que es lo siguiente que se encuentra en el flujo de lectura, dado que se halla al mismo nivel de indentación.
Aquí, podríamos haber introducido la cláusula else en lugar de repetir de nuevo  if. Pero como damos dos opciones, o s o n, hemos preferido usar dos veces la cláusula if y tan campantes.
Cuando el programa efectúa la consiguiente comparación comprueba que "n" != "s" y se sale de la bifurcación sin leer su código interno continuando con el flujo:


Como vemos, el programa ha saltado al siguiente epígrafe: ANCLAJES/BLOQUEADORES con un modelo de introducción de datos, input, similar al anterior.
Todo correcto. Salvo por un detalle.
Tal y como está escrito el código, si introdujéramos como dato de entrada, por ejemplo, z, que en la variable cintdel tomaría el tipo de dato string como "z", o cualquier otro valor, que no sea n o s, el programa simplemente proseguiría con su lectura: no encontraría semejanzas con los elementos a comparar de ninguno de los dos condicionales if (ni con "s" ni con "n") pero no pasaría nada, y el mundo seguiría girando en torno al Sol:


Pues bien: para evitar esto, deberíamos introducir un último condicional if que atienda a estas posibilidades, modificando el código tal cual se muestra a continuación:



En 1. introducimos el condicional if estableciendo una doble comparación mediante la partícula and: si cintdel no es ni "n" ni "s"...
En 2., con la indentación o sangrado preceptivo, imprimimos un texto de aviso para advertir de lo que ha ocurrido.
En 3., igualmente con la indentación o sangrado preceptivo, salimos del flujo de lectura llamando nuevamente al método cinturones_de_seguridad() de la clase Seguridad() mediante la notación del punto (fijémonos que la llamada al método ya no la efectúa nuestro objeto coche, la instancia que creamos, sino que llamamos al método desde la clase directamente dado que, obviamente, estamos trabajando desde la estructura del propio código y no en tiempo de ejecución, runtime) para que nos devuelva al punto de partida.
Si ejecutamos el código, ahora sí, obtendríamos un resultado más adecuado:





SENDEROS EN LA LAURISILVA DE ANAGA, NORESTE DE TENERIFE.
Vamos a continuar con la ejecución del programa a ver qué cosas más suceden. En esta ocasión, a la pregunta de si observamos algún tipo de rotura y/o desgaste en alguna de las correas de sujeción delanteras, vamos a responder que sí pulsando s en el teclado, dado que es la opción que nos da el programa. Cuando hacemos esto, sucede lo siguiente:



Notemos que, automáticamente, nos salta una input: Observaciones, donde podremos escribir un texto descriptivo de los fallos que hayamos detectado. ¿Por qué ha ocurrido ésto? La respuesta a este comportamiento está en 6:  Seguridad().observaciones_y_recomendaciones().
Ocurre que el condicional establece una bifurcación entre ambas respuestas posibles: si es n, se aplica la cláusula pass y el programa continúa con el flujo de lectura en sentido descendente saliéndose del ámbito del condicional para regresar al ámbito del método; en cambio, si es s, el flujo de lectura entra en el ámbito de esta opción y encuentra la línea que resaltamos más arriba. ¿ Y qué le dice esta línea al programa? Pues, primero, que se remonte de nuevo a la clase Seguridad(), es decir, que deshaga el camino hecho hasta ahora y comience a re-ejecutar el código. Pero, ¡ojo!, 👀, en base al método del punto (notación del punto o dott method), llamamos a continuación al método estático observaciones_y_recomendaciones() que está en el cuerpo de la clase, pero que no pertenece a la clase misma porque, al carecer de la autorreferencia self en su zona de parámetros, la clase Seguridad() no lo "reconoce" como una instancia suya, nacida con dolor y amor de madre de lo más profundo de sus entrañas, como sí lo es el método cinturones_de_seguridad(), por ejemplo, que lleva la autorreferencia self en su zona de parámetros, como ya explicamos más arriba. A pesar de ello, como está dentro del cuerpo (del ámbito, scope) de la clase Seguridad() por mor del indentado, de la sangría, podemos llamar al método desde la clase sin ningún problema y esperar que se ejecute.
Ahora, el flujo de lectura está dentro del método estático observaciones_y_recomendaciones(), y fijémonos en el detalle: el flujo de lectura está ahora varias líneas de código por encima de donde ha hecho su "parada" (justo debajo de if cintdel == "s":) y empieza a ejecutar el código correspondiente al método estático desde donde éste está ubicado en nuestro script.



Y, claro, una vez dentro del método estático observaciones_y_recomendaciones(), comenzará de nuevo el flujo de ejecución del código de arriba a abajo. Y lo primero que encuentra es una función input() para la entrada externa de datos (por el usuario) asignada a la variable obs con el texto "Observaciones".
Hagamos correr nuestro código:


Como vemos, respondemos en observaciones y, cuando pulsamos enter para finalizar, el programa vuelve a reproducir nuestra respuesta ya que así se lo hemos pedido con la instrucción print(obs). Lo hace, y prosigue su descenso hacia la siguiente línea de código. Aquí encuentra una nueva entrada de datos por el usuario similar a obs pero asignada en esta ocasión a la variable recom, y que recoge las recomendaciones, como indica el texto de la zona de parámetros de la función, "Recomendaciones". La rellenamos y el programa nuevamente reproduce en pantalla nuestro texto con una nueva llamada a la función print(recom) modificando, obviamente, el argumento, recom por obs.
Finalmente, lee la última línea de nuestro método estático observaciones_y_recomendaciones() y la ejecuta (es una fórmula, como otra cualquiera, de escribir una línea vacía, como print(" ") o print("\n"), si buscamos un salto de línea, por ejemplo).

      CUANDO ESCRIBIMOS NUESTRA RESPUESTA EN LOS input, COMO EN EL CASO DEL PRIMERO DE ELLOS ASIGNADO A LA VARIABLE obs, PODEMOS COMPROBAR COMO LAS PALABRAS DEL IDIOMA EN QUE ESCRIBIMOS QUE, CASUALMENTE, COINCIDAN CON NOMBRES DE PALABRAS RESERVADAS EN PYTHON, EN EL CASO QUE NOS OCUPA, LA CONTRACCIÓN del (de + el) ASIMILABLE, ORTOGRÁFICAMENTE, A LA KEYWORD del QUE IMPLICA UN BORRADO O ELIMINACIÓN (delete), POR DEFECTO, SE TINTAN EN SU COLOR DE RESALTADO, NARANJA, SIN QUE ELLO TENGA MAYOR TRASCENDENCIA.

Una vez concluida la lectura del código del método estático, nuestro flujo de ejecución salta de nuevo código abajo como una aguerrida cabra montés hasta donde hizo su "paréntesis", su stand by, en la llamada al mencionado código estático del condicional cuando escogimos la opción s y, hecho el trabajo, continúa con la lectura anunciándonos mediante una instrucción print() que nos encontramos ya en el apartado siguiente de nuestro flamante método cinturones_de_seguridad(), "ANCLAJES/BLOQUEADORES".
Sin embargo, como podemos ver en la siguiente captura, no podemos recuperar el valor que asignamos a las propiedades obs y recom:





Observemos como cuando en el prompt (indicativo de que el programa a terminado de leer el código del método cinturones_de_seguridad() y se sale del flujo del código de la clase a la paciente espera de lo que vayamos a hacer) escribimos el nombre de nuestra instancia, coche, no se nos muestra en el cuadro de diálogo las propiedades obs ni recom (son propiedades porque no hacen nada: sólo son una variable y un valor asignado a esa variable en concreto). Es decir, no son ACCESIBLES para la clase Seguridad(). ¡Mecachis! 😾. Vamos a verlo:



¡Diantre! ¿Y por qué no son accesibles? Pues por una razón muy simple que ya explicamos en el capítulo FUNCIONES DEFINIDAS POR EL USUARIO I: se trata de variables locales, es decir, variables que se han declarado dentro del cuerpo de una función/método, en nuestro caso, dentro del  método cinturones_de_seguridad() y cuyo espacio vital se circunscribe exclusivamente al cuerpo, ámbito o scope de la función donde se han declarado. ¿Y cómo solucionamos esto? Fácil: declaramos las variables que nos interesan obs y recom como VARIABLES DE CLASE y les asignamos un valor de partida, de inicio, por ejemplo, None. Al cabo, sólo tendremos que  llevarlas a nuestro método estático observaciones_y_recomendaciones() llamándolas como lo que son: variables de clase, lo que implica anteponer el nombre de la clase, el punto (método del punto) y el nombre de la variable, tal y como mostramos a continuación:




Y si ahora ejecutamos el código...


¡Problema resuelto! Simplemente, hemos procedido del mismo modo que si quisiéramos hacer lo propio en un script normal, sin haber modelizado clase alguna: declaramos una variable global, le asignamos el valor que queramos desde el cuerpo de la función definida por el usuario, y luego la llamamos. En nuestro supuesto, declaramos a modo de variables globales (se encuentran FUERA del cuerpo los métodos de la clase, de nuestro método cinturones_de_seguridad(), por ejemplo, pero DENTRO del cuerpo de la clase) a obs y recom, sólo que en vez de utilizar la sintaxis global nombre_variable usamos la llamada propia, la sintaxis característica, de las llamadas a variables de clase: Classname.nombre_variable, y que actúa de manera análoga a la anterior. Así, ya podemos acceder a los valores almacenados en las variables obs y recom.
El siguiente esquema nos aclara un poco más la idea.


A fin de cuentas, es el zen de Python: ideas simples, esquemas sencillos, que se repiten en niveles diferentes. No hay más.



Aún así, persiste un problema con nombre propio: sobreescritura. Si nos fijamos atentamente en el supuesto vemos que podemos llamar al método estático observaciones_y_recomendaciones() en varias partes de nuestro código, del mismo modo que lo hacemos también con el segundo método estático de nuestro script, estado(), que almacena, en su caso también, la información desde un input(), una entrada externa de datos proporcionada por el usuario, en la variable valest, de modo análogo a como en el primer método estático, la información se almacena en las variables obs y recom.
Pero, claro, como el nombre de la variable es indiferenciado, esto es, siempre es obs y no obs1, obs2, obs3, obs4, etc., y siempre es recom, y no recom1, recom2, recom3, recom4, etc.; y en su caso, con valest sucede lo mismo, y no hemos implementado ningún código para que con cada llamada a los métodos estáticos la información proporcionada por el usuario se almacene cada vez en una variable distinta (obs1obs2obs3obs4,... recom1recom2recom3recom4,.. valest1, valest2, valest3, valest4,...), cada vez que llamamos a obs, a recom o a valest para que nos muestren la información contenida en la variable, como procedemos en la columna derecha del esquema anterior, nos mostrará la ÚLTIMA que tenga guardada, sobreescribiendo (y, en consecuencia, borrando) toda la información anterior CADA VEZ QUE RECIBE UNA NUEVA ENTRADA DE DATOS a través de la función integrada input().
Es decir, si la primera vez que llamamos al método estático observaciones_y_recomendaciones() ingresamos a través de input() las valoraciones obs = "Correcto" y recom = "Nada en especial" para CINTURONES DELANTEROS; para la segunda llamada, obs = "Anclajes recios" y recom = "Aceitar las lengüetas" para ANCLAJES/BLOQUEADORES, y para una tercera llamada, obs = "Tensores laxos" y recom = "Recoger más cinta" para la llamada a TENSORES, y hacemos una parada para consultar las observaciones y recomendaciones, el programa nos mostrará tan solo obs = "Tensores laxos" y recom = "Recoger más cinta", que es la ÚLTIMA información almacenada en ambas variables. ¡Ah! ¿Pero que pasa con las observaciones y recomendaciones que establecimos para CINTURONES DELANTEROS y ANCLAJES/BLOQUEADORES? Pues, llanamente, que se han sobreescrito con cada nueva llamada al método estático y se han borrado para siempre, persistiendo sólo el último valor almacenado en ambos casos.
Vamos a proponer una solución para salir del paso y mostrar los resultados adecuados. No es la mejor posible, pero nos sirve al menos para contextualizar lo que estamos hablando y sortear la majadería ésta de la sobreescritura.
Vamos a proponer el siguiente cambio en nuestro código:



Lo que este código va a hacer es, tomando como base la variable de clase obs, a la que asignamos el dato externo que introduzcamos a través de la función integrada input(), almacenar dicho dato y, en la siguiente línea de código, insertarla en la lista observaciones, que es también una variable de clase. Así, cada vez que llamamos al método estático observaciones_y_recomendaciones() se generará un nuevo dato que se almacenará primero en la variable de entrada Seguridad.obs y luego en la variable lista Seguridad.observaciones. El procedimiento es el mismo para recom/recomendaciones y valest/valests.
Luego, al final, podremos discriminar la información desde la lista observaciones invocando cada dato por su índice. Veámoslo en un ejemplo:


Y cuando hacemos la comprobación...


Como vemos, se han almacenado en las variables de clase observaciones y recomendaciones los distintos valores que hemos ido otorgando a las variables de clase obs y recom respectivamente a lo largo de la ejecución del código. Así, podremos recuperarlas por su índice siempre y cuando sepamos a qué llamada corresponde cada variable almacenada: el primer elemento de la lista observaciones se corresponde con el dato almacenado en obs en la primera llamada al método estático y, por lo tanto, le corresponde el índice 0. El segundo elemento de la lista observaciones se corresponde con el dato almacenado en obs en la segunda llamada al método estático y, por lo tanto, le corresponde el índice 1...
Así sucesivamente. Por pura obviedad, este procedimiento también es válido para la lista recomendaciones como podemos comprobar. También lo es para la lista valets, con la salvedad de que el valor lo toma de  una clave (key) de diccionario (dictevalest) que nosotros seleccionamos mediante la función integrada input() y que ya se encuentra dentro del cuerpo, del ámbito o scope, como queramos decirlo,  del método estático estado(), por lo que no podemos configurar valest como una variable de clase, aunque su valor si viaja y se almacena como Python y Dios mandan en la variable de clase, la lista, valets.

LAURISILVA Y SOTOBOSQUE DE HELECHOS, EN ALGÚN LUGAR MÁS O MENOS RECÓNDITO DEL MACIZO DE ANAGA, NORESTE DE TENERIFE.

La opción evidente pasa, sin duda, por declarar una variable distinta para cada dato, y prescindiendo del método estático, cuya función en un código "real" pasa por no implementar variables que puedan contener datos externos pues acabamos de comprobar más arriba sus limitaciones, crearlas dentro de los métodos de la propia clase Seguridad(). cada una con su propio nombre (recordemos, como siempre, una referencia a un espacio de memoria) diferenciado.
Podemos modificar nuestro código de la siguiente forma:


Aquí hemos suprimido los métodos estáticos para clarificar mejor lo que acabamos de hacer así como las variables de clase, que ya no nos serán necesarias. Declaramos sendas variables diferenciadas dentro de cada método, y hacemos que mediante el concurso de la autorreferencia self y por el método o notación del punto (dott method) → self. asignemos cada variable a la clase, por lo que luego podremos llamarla para que nos muestre su valor almacenado correspondiente sobre cualquier objeto que instanciemos de ella con sólo llamar a la variable por su santo nombre.
Lo vemos a continuación:


Y el resultado de efectuar las llamadas sería el esperado (y deseado):




Podemos ver en  otros métodos como  segnaletica_cuadro_mandos(self)cierre_centralizado(self) y en reposacabezas(self) que recurrimos directamente a una invocación desde la clase Seguridad() del método estático observaciones_y_recomendaciones(), sin adicionar más código, lo que nos demuestra que es posible crear métodos que llamen a otros métodos desde su propio cuerpo, ámbito o scope, de una manera absolutamente funcional y sin que al pobre Python le de un síncope por semejante herejía. Esto enlaza con lo que explicábamos en la entrada dedicada a los closures en Python, y que podemos visitar aquí:

                                    

                                     T4. CLOSURES: LA SONRISA DE LAS MATRIUSKAS.

        
Un puñado de líneas de código más abajo, en el método seguridad__vial(self), en la línea señalada con 7, tenemos un ejemplo simple de condicional if anidado, donde debemos ser cautos y precisos en el momento de implementar la indentaciones adecuadas para no incurrir en errores de sintaxis ( SyntaxError: invalid syntax) o, directamente, de indentación (SyntaxError: unindent does not match any outer indentation level) donde se nos dice que la indentación que hemos colocado no coincide con ningún nivel de sangrado externo. Esto ocurre siempre en relación con el condicional inmediatamente superior en la jerarquía de niveles, y suele ser el error más común en estas situaciones.
Y aquí terminamos este SUPUESTO 1 con el que pretendemos ejemplificar algunas de las cosas que hemos estudiado hasta ahora de una manera clara y sencilla, para ir haciendo boca. Os dejamos más abajo el código modificado por si queréis trastear con él, cosa que recomendamos enfáticamente porque es la mejor forma de aprender cualquier cosa, y no sólo programación.
Nuestra intención es subir más supuestos (de ahí la numeración) para ejemplificar andando el tiempo y conforme vayamos adquiriendo nuevos conocimientos, modelos prácticos que nos ayuden a comprender mejor las posibilidades y beneficios de programar con Python.

seguridad.py

class Seguridad(): 
  """EVALÚA SUCINTAMENTE EL ESTADO DE LOS DISPOSITIVOS Y MECANISMOS DE        SEGURIDAD DEL VEHÍCULO -> STRING"""
  def __init__(self): 
pass
print("*****************************")
print("***** ÁREA DE SEGURIDAD *****"
print("*****************************")
def cinturones_de_seguridad(self):
"""Evalúa el estado general de los cinturones de seguridad -> string"""
print("CINTURONES DELANTEROS")
print("**********************")
cintdel = input("¿Observa algún tipo de rotura y/o desgaste en alguna de las correas de sujeción delanteras? (s/n): "
self.cintdel = cintdel
if cintdel == "n":
pass
if cintdel == "s":
obs1 = input("Observaciones: ")
              self.obs1 = obs1
      recom1 = input("Recomendaciones: ")
      self.recom1 = recom1
          if cintdel != "n" and cintdel != "s":
              print("Dato no válido")
          print("Criterio de evaluación")
print("******************")
print("1: óptimo\n"
              "2: mejorable\n"
              "3: funcionalidad limitada\n"
              "4: mal estado")
dictevalest = {
"1":"óptimo",
"2":"mejorable",
"3":"funcionalidad limitada",
"4":"mal estado"
}
valest1 = input("Introducir una valoración general del estado de los dispositivos y mecanismos de seguridad del automóvil de acuerdo a los números de la izquierda: ")
print("El estado general del elemento es: ", dictevalest.get(valest1))
print("ANCLAJES/BLOQUEADORES")
print("··············")
anclajesdel = input("¿Funcionan correctamente los anclajes/bloqueadores? (s/n): ")
self.anclajesdel = anclajesdel
if anclajesdel == "s":
pass
if anclajesdel == "n":
obs2 = input("Observaciones: ")
               self.obs2 = obs2
       recom2 = input("Recomendaciones: ")
       self.recom2 = recom2
           if anclajesdel != "n" and anclajesdel != "s":
               print("Dato no válido")
           print("Criterio de evaluación")
print("******************")
print("1: óptimo\n"
              "2: mejorable\n"
              "3: funcionalidad limitada\n"
              "4: mal estado")
dictevalest = {
"1":"óptimo",
"2":"mejorable",
"3":"funcionalidad limitada",
"4":"mal estado"
}
valest2 = input("Introducir una valoración general del estado de los dispositivos y mecanismos de seguridad del automóvil de acuerdo a los números de la izquierda: ")
print("El estado general del elemento es: ", dictevalest.get(valest2))
print("TENSORES")
print("···············")
tnsdel =  input("¿Tensan adecuadamente los tensores de las correas de sujeción delantera? (s/n): ")
self.tnsdel = tnsdel
if tnsdel == "s":
pass
if tnsdel == "n":
obs3 = input("Observaciones: ")
              self.obs3 = obs3
      recom3 = input("Recomendaciones: ")
      self.recom3 = recom3
          if tnsdel != "n" and tnsdel != "s":
              print("Dato no válido")
print("RECOGIDA")
print("···············")
recdel =  input("¿Se recogen adecuadamente las correas de sujeción delanteras? (s/n): ")
self.recdel = recdel
if recdel == "s":
pass
if recdel == "n":
obs4 = input("Observaciones: ")
              self.obs4 = obs4
      recom4 = input("Recomendaciones: ")
      self.recom4 = recom4
           if recdel != "n" and recdel != "s":
               print("Dato no válido")
           print("Criterio de evaluación")
print("******************")
print("1: óptimo\n"
              "2: mejorable\n"
              "3: funcionalidad limitada\n"
              "4: mal estado")
dictevalest = {
"1":"óptimo",
"2":"mejorable",
"3":"funcionalidad limitada",
"4":"mal estado"
}
valest3 = input("Introducir una valoración general del estado de los dispositivos y mecanismos de seguridad del automóvil de acuerdo a los números de la izquierda: ")
print("El estado general del elemento es: ", dictevalest.get(valest3))
print("CINTURONES TRASEROS")
print("********************")
cinttra = input("¿Observa algún tipo de rotura y/o desgaste en alguna de las correas de sujeción            delanteras? (s/n): ")
self.cinttra = cinttra
if cinttral == "n":
pass
if cinttral == "s":
obs5 = input("Observaciones: ")
              self.obs5 = obs5
      recom5 = input("Recomendaciones: ")
      self.recom5 = recom5
           if cinttral != "n" and cinttral != "s":
               print("Dato no válido")
print("ANCLAJES/BLOQUEADORES")
print("··············")
anclajestra = input("¿Funcionan correctamente los anclajes/bloqueadores? (s/n): ")
self.anclajestra = anclajestra
if anclajestra == "s":
pass
if anclajestra == "n":
Seguridad().estado()
obs6 = input("Observaciones: ")
              self.obs6 = obs6
      recom6 = input("Recomendaciones: ")
      self.recom6 = recom6
           if anclajestra != "n" and anclajestra != "s":
               print("Dato no válido")
           print("Criterio de evaluación")
print("******************")
print("1: óptimo\n"
              "2: mejorable\n"
              "3: funcionalidad limitada\n"
              "4: mal estado")
dictevalest = {
"1":"óptimo",
"2":"mejorable",
"3":"funcionalidad limitada",
"4":"mal estado"
}
valest3 = input("Introducir una valoración general del estado de los dispositivos y mecanismos de seguridad del automóvil de acuerdo a los números de la izquierda: ")
print("El estado general del elemento es: ", dictevalest.get(valest3))
print("TENSORES")
print("···············")
tnstra =  input("¿Tensan adecuadamente los tensores de las correas de sujeción delanteras? (s/n): ")
self.tnstra = tnstra
if tnstra == "s":
pass
if tnstra == "n":                      
obs7 = input("Observaciones: ")
              self.obs7 = obs7
      recom7 = input("Recomendaciones: ")
      self.recom7 = recom7
           if tnstra != "n" and tnstra != "s":
               print("Dato no válido")
           print("Criterio de evaluación")
print("******************")
print("1: óptimo\n"
              "2: mejorable\n"
              "3: funcionalidad limitada\n"
              "4: mal estado")
dictevalest = {
"1":"óptimo",
"2":"mejorable",
"3":"funcionalidad limitada",
"4":"mal estado"
}
valest4 = input("Introducir una valoración general del estado de los dispositivos y mecanismos de seguridad del automóvil de acuerdo a los números de la izquierda: ")
print("El estado general del elemento es: ", dictevalest.get(valest4))
print("RECOGIDA")
print("···············")
rectra =  input("¿Se recogen adecuadamente las correas de sujeción delanteras? (s/n): ")
self.rectra = rectra
if rectra == "s":
pass
if rectra == "n":
obs8 = input("Observaciones: ")
              self.obs8 = obs8
      recom8 = input("Recomendaciones: ")
      self.recom8 = recom8
           if rectra != "n" and rectra != "s":
               print("Dato no válido")
           print("Criterio de evaluación")
print("******************")
print("1: óptimo\n"
              "2: mejorable\n"
              "3: funcionalidad limitada\n"
              "4: mal estado")
dictevalest = {
"1":"óptimo",
"2":"mejorable",
"3":"funcionalidad limitada",
"4":"mal estado"
}
valest5 = input("Introducir una valoración general del estado de los dispositivos y mecanismos de seguridad del automóvil de acuerdo a los números de la izquierda: ")
print("El estado general del elemento es: ", dictevalest.get(valest5))
def segnaletica_cuadro_mandos(self):
        """Evalúa el estado de la señalética del cuadro de mandos --> string"""
 obs9 = input("Observaciones: ")
          self.obs9 = obs9
  recom9 = input("Recomendaciones: ")
  self.recom9 = recom9
def cierre_centralizado(self):
        """Evalúa el estado del dispositivo de cierre centralizado --> string"""
        obs10 = input("Observaciones: ")
          self.obs10 = obs10
  recom10 = input("Recomendaciones: ")
  self.recom10 = recom10
def reposacabezas(self):
        """Evalúa el estado de los reposacabezas --> string"""
        obs11 = input("Observaciones: ")
          self.obs11 = obs11
  recom11 = input("Recomendaciones: ")
  self.recom11 = recom11
def seguridad__vial(self):
"""Evalúa la existencia, estado y funcionalidad de los elementos de seguridad del vehículo en              caso de accidente o avería del vehículo --> string"""
print("*********************************")
print("***** ÁREA DE SEGURIDAD VIAL *****")
print("*********************************")
print("TRIÁNGULOS (Juego de triángulos)")
print("·················································")
triangulos = input("¿Existe juego de triángulos? (s/n): ")
self.triangulos = triangulos
if triangulos == "s":
pass
if triangulos == "n":
print("Reponer triángulos con urgencia")
trihom = input("¿El juego de triángulos está homologado de acuerdo a las directivas vigentes              de la DGT? (s/n): ")
self.trihom = trihom
if trihom == "s":
pass
if trihom == "n":
print("Adecuar el juego de triángulos a la normativa vigente lo antes posible")
obs12 = input("Observaciones: ")
              self.obs12 = obs12
      recom12 = input("Recomendaciones: ")
      self.recom12 = recom12
          if trihom != "n" and trihom != "s":
              print("Dato no válido")
print(" ")
print("GATO (Elevador manual del vehículo)")
print("····················································")
gato = input("¿Existe gato/elevador? (s/n): ")
self.gato = gato
if gato == "s":
pass
if gato == "n":
print("Reponer el gato con urgencia")
obs13 = input("Observaciones: ")
              self.obs13 = obs13
      recom13 = input("Recomendaciones: ")
      self.recom13 = recom13
          if gato != "n" and gato != "s":
              print("Dato no válido")
print(" ")
print("RUEDA DE REPUESTO TRADICIONAL")
print("·····················································")
ruedarepuesto = input("¿Existe rueda de repuesto? (s/n): ")
self.ruedarepuesto = ruedarepuesto
if ruedarepuesto == "s":
pass
if ruedarepuesto == "n":
print("Reponer la rueda de repuesto con urgencia")
rdarepresion = input("¿Tiene la presión adecuada? (s/n): ")
self.rdarepresion = rdarepresion
if rdarepresion == "s":
pass
if rdarepresion == "n":
print("Regular cuanto antes la presión de la rueda de repuesto de acuerdo a las especificaciones del fabricante")
obs14 = input("Observaciones: ")
              self.obs14 = obs14
      recom14 = input("Recomendaciones: ")
      self.recom14 = recom14
          if rdarepresion != "n" and rdarepresion != "s":
              print("Dato no válido")
print(" ")
print("KIT ANTIPINCHAZOS"
print("·····························")
kitanti = input("¿Utiliza el vehículo un kit antipinchazos como sustituto de la rueda de repuesto tradicional? (s/n): ")
self.kitanti = kitanti
if kitanti == "n":
pass
if kitanti == "s":
setkitanti = input("¿Dispone el vehículo de kit antipinchazos? (s/n): ")
self.setkitanti = setkitanti
if setkitanti == "s":
pass
if setkitanti == "n":
print("Reponer cuanto antes el kit antipinchazos")
kitantihom = input("¿Está homologado el kit antipinchazos de acuerdo a la normativa en vigor? (s/n): ")
self.kitantihom = kitantihom
if kitantihom == "s":
pass
if kitantihom == "n":
print("Sustituir cuanto antes el kit antipinchazos por otro homologado según la normativa vigente")
obs15 = input("Observaciones: ")
                 self.obs15 = obs15
         recom15 = input("Recomendaciones: ")
         self.recom15 = recom15
             if kitantihom != "n" and kitantihom != "s":
                 print("Dato no válido")
print(" ")
print("RUEDA DE REPUESTA TIPO GALLETA")
print("limitación de velocidad y/o distancia")
print("···················································")
rrg = input("¿El vehículo utiliza como rueda de repuesto una rueda de tipo 'galleta'? (s/n): ")
self.rrg = rrg
if rrg == "n":
pass
if rrg == "s":
setrrg = input("¿Dispone el vehículo de una rueda de repuesto de tipo galleta? (s/n): ")
self.setrrg = setrrg
if setrrg == "s":
pass
if setrrg == "n":
print("Reponer la rueda de repuesto con urgencia")
obs16 = input("Observaciones: ")
             self.obs16 = obs16
     recom16 = input("Recomendaciones: ")
     self.recom16 = recom16
         if setrrg != "n" and setrrg != "s":
             print("Dato no válido")
print(" ")
print("NEUMÁTICOS DE TIPO RUNFLAT")
print("***** rodaje sin presión *****")
print("············································")
runflat = input("¿El vehículo dispone de ruedas de repuesto con neumáticos de tipo RUNFLAT? (s/n): ")
self.runflat = runflat
if runflat == "n":
pass
if runflat == "s":
print("Reponer el neumático inmediatamente")
obs17 = input("Observaciones: ")
             self.obs17 = obs17
     recom17 = input("Recomendaciones: ")
     self.recom17 = recom17
         if runflat != "n" and runflat != "s":
             print("Dato no válido")
print(" ")
print("NEUMÁTICOS DE TIPO SEALANT")
print("****** autorreparables ******")
print("············································")
sealant = input("¿El vehículo dispone de ruedas de repuesto con neumáticos de tipo SEALANT? (s/n): ")
self.sealant = sealant
if sealant == "n":
pass
if sealant == "s":
print("Reponer el neumático inmediatamente")
obs18 = input("Observaciones: ")
             self.obs18 = obs18
     recom18 = input("Recomendaciones: ")
     self.recom18 = recom18
         if sealant != "n" and sealant != "s":
             print("Dato no válido")
print(" ")
print("CHALECOS REFLECTANTES")
print("·····································")
chalecos = input("¿Dispone el vehículo de suficientes chalecos reflectantes? (s/n): ")
self.chalecos = chalecos
if chalecos == "s":
pass
if chalecos == "n":
print("Reponer un número adecuado de chalecos reflectantes con urgencia")
chalhom = input("¿Están los chalecos reflectantes homologados de acuerdo a las directivas de seguridad de la DGT? (s/n): ")
self.chalhom = chalhom
if chalhom == "s":
pass
if chalhom == "n":
print("Sustituir cuanto antes los chalecos actuales por chalecos homologados")
obs19 = input("Observaciones: ")
             self.obs19 = obs19
     recom19 = input("Recomendaciones: ")
     self.recom19 = recom19
         if chalhom != "n" and chalhom != "s":
             print("Dato no válido")
print(" ")
def cajetin__de__herramientas(self):
"""Evalúa el contenido y pertinencia del cajetín de herramientas --> string"""
cajher = input("¿El vehículo cuenta con una caja de herramientas? (s/n): ")
self.cajher = cajher
if cajher == "n":
pass
if cajher == "s":
setcajher = input("¿Dispone el vehículo de cajetín de herramientas? (s/n): ")
self.setcajher = setcajher
if setcajher == "s":
pass
if setcajher == "n":
print("Reponer cuanto antes el cajetín de herramientas")
print("EVALUACIÓN DEL SET DE HERRAMIENTAS")
print("*****************************************")
print("LLAVES DE TUBO")
print("························")
llavtub = input("¿Incluye llaves de tubo de calibre 6 a 24 y 30 y 32? (s/n): ")
self.llavtub = llavtub
if llavtub == "s":
pass
if llavtub == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("LLAVES PLANAS (MIXTAS)")
print("·····································")
llavplan = input("¿Incluye llaves planas de calibre 6 a 24 y tipo 'carraca'? (s/n): ")
self.llavplan = llavplan
if llavplan == "s":
pass
if llavplan == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("LLAVES DE CODO")
print("·························")
llavcod = input("¿Incluye llaves de codo de calibre 6 a 24? (s/n): ")
self.llavcod = llavcod
if llavcod == "s":
pass
if llavcod == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("CAJA DE BOQUILLAS TAMAÑO 4 A 14")
print("····················································")
b1 = input("¿Incluye la caja de boquillas? (s/n): ")
self.b1 = b1
if b1 == "s":
pass
if b1 == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("CAJA DE BOQUILLAS TAMAÑO 8 A 32 + CARRACA")
print("·····································································")
b2 = input("¿Incluye la caja de boquillas? (s/n): ")
self.b2 = b2
if b2 == "s":
pass
if b2 == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("LLAVES TIPO ALLEN")
print("····························")
llavall = input("¿Incluye llaves de tipo Allen de calibre 4 a 10? (s/n): ")
self.llavall = llavall
if llavall == "s":
pass
if llavall == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("LLAVES TIPO TORX")
print("···························")
llavtorx = input("¿Incluye llaves de tipo Torx de calibre 10 a 50? (s/n): ")
self.llavtorx = llavtorx
if llavtorx == "s":
pass
if llavtorx == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("DESTORNILLADORES DE PUNTA PLANA Y ESTRELLA")
print("········································································")
dest = input("¿Incluye, al menos, 4 tamaños distintos por tipo? (s/n): ")
self.dest = dest
if dest == "s":
pass
if dest == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("DESTORNILLADORES DE TIPO TORX")
print("··················································")
destorx = input("¿Incluye destornilladores Torx de calibre 10, 15, 20, 25 y 30? (s/n): ")
self.destorx = destorx
if destorx == "s":
pass
if destorx == "n":
print("Reintegrar piezas faltantes")
print(" ")
print("ALICATES")
print("··············")
alireg = input("¿Incluye unos alicates de tipo regular? (s/n): ")
self.alireg = alireg
if alireg == "s":
pass
if alireg == "n":
print("Reintegrar piezas faltantes")
alicor = input("¿Incluye unos alicates de tipo corte? (s/n): ")
self.alicor = alicor
if alicor == "s":
pass
if alicor == "n":
print("Reintegrar piezas faltantes")
aliuni = input("¿Incluye unos alicates de tipo universal? (s/n): ")
self.aliuni = aliuni
if aliuni== "s":
pass
if aliuni== "n":
print("Reintegrar piezas faltantes")
print(" ")
print("HERRAMIENTAS ESTÁNDAR")
print("······································")
print("Espejo")
print("-------")
espejo = input("¿Contiene un espejo pequeño o de mano? (s/n): ")
self.espejo = espejo
if espejo == "s":
pass
if espejo == "n":
print("Reponer pieza")
print("Llaves para filtro del aceite")
print("··································")
llavfil = input("¿Contiene una llave para el filtro del aceite? (s/n): ")
self.llavfil = llavfil
if llavfil == "s":
pass
if llavfil == "n":
print("Reponer pieza")
print("Martillo")
print("···········")
martillo = input("¿Contiene un martillo? (s/n): ")
self.martillo = martillo
if martillo == "s":
pass
if martillo == "n":
print("Reponer pieza")
print("Buril")
print("·······")
buril = input("¿Contiene un buril? (s/n): ")
self.buril = buril
if buril == "s":
pass
if buril == "n":
print("Reponer pieza")
print("Cutter")
print("········")
cutter = input("¿Contiene un cutter? (s/n): ")
self.cutter = cutter
if cutter == "s":
pass
if cutter == "n":
print("Reponer pieza")
print("Linterna/lámpara portátil")
print("······························")
lint = input("¿Contiene una linterna o lámpara portátil? (s/n): ")
self.lint = lint
if lint == "s":
pass
if lint == "n":
print("Reponer pieza")


CASCADAS DE AGUA TRAS LA LLUVIA EN ANAGA. 


No hay comentarios:

Publicar un comentario