INTRODUCCIÓN AL CÓMPUTO
“Primera computadora” creada por los griegos, calcula la posición del sol, luna y algunas constelaciones.
En 1801, Telar de Jacquar, separa el resultado de la información que contiene las instrucciones.
Siglo XIX, Motor analítico de Babbage, haciendo uso del avance en mecánica (engranajes) de su época logra separar instrucciones de cálculo y realizar varios cálculos a la vez.
Finales siglo XIX, ENIAC (Eectronic Numerical Integrator and Computer) usaba sistema decimal. creada por Alan Turing y Alonso. Esta época exigía exactitud en los cálculos que hacían que compañías dependieran de esta (Compañías Ferroviarias, por ejemplo). Turing y Alonso, Descubrieron que matemáticamente todos los algoritmos podíamos reducirlos a una secuencia de soluciones matemáticas.
En 1945, Arquitectura de Von Neumann, EDVAC (Electronic Discrete Variable Automatic Computer) usaba sistema binario. Su aporte fue el descubrimiento que dentro de los componentes electrónicos se puede usar una serie de hadward para realizar el cómputo y almacenar datos dentro de memoria.
En 1950, Microchip, ejemplo Apple 1
En siglo XX, Arquitectura de Feymann, aporta las bases matemáticas de cómputo cuántico.
Arquitectura de Paul Newman
Cómputo y los computadores actuales
¿QUÉ ES UN LENGUAJE DE PROGRAMACIÓN?
Es un lenguaje formal que, mediante una serie de instrucciones, le permite a un programador escribir un conjunto de órdenes, acciones consecutivas, datos y algoritmos para, de esa forma, crear programas que controlen el comportamiento físico y lógico de una máquina.
¿Qué tipos de lenguaje de programación existen?
El lenguaje de programación es la base para construir todas las aplicaciones digitales que se utilizan en el día a día y se clasifican en dos tipos principales: lenguaje de bajo nivel y de alto nivel.
Lenguaje de programación de bajo nivel
Son lenguajes totalmente orientados a la máquina.
Este lenguaje sirve de interfaz y crea un vínculo inseparable entre el hardware y el software.
Además, ejerce un control directo sobre el equipo y su estructura física. Para aplicarlo adecuadamente es necesario que el programador conozca sólidamente el hardware. Éste se subdivide en dos tipos:
Lenguaje máquina
Es el más primitivo de los lenguajes y es una colección de dígitos binarios o bits (0 y 1) que la computadora lee e interpreta y son los únicos idiomas que las computadoras entienden.
Ejemplo: 10110000 01100001
No entendemos muy bien lo que dice ¿verdad? Por eso, el lenguaje ensamblador nos permite entender mejor a qué se refiere este código.
Lenguaje ensamblador
El lenguaje ensamblador es el primer intento de sustitución del lenguaje de máquina por uno más cercano al utilizado por los humanos.
Un programa escrito en este lenguaje es almacenado como texto (tal como programas de alto nivel) y consiste en una serie de instrucciones que corresponden al flujo de órdenes ejecutables por un microprocesador.
Sin embargo, dichas máquinas no comprenden el lenguaje emsamblador, por lo que se debe convertir a lenguaje máquina mediante un programa llamado Ensamblador.
Este genera códigos compactos, rápidos y eficientes creados por el programador que tiene el control total de la máquina.
Ejemplo: MOV AL, 61h (asigna el valor hexadecimal 61 al registro “AL”)
Lenguaje de programación de alto nivel
Tienen como objetivo facilitar el trabajo del programador, ya que utilizan unas instrucciones más fáciles de entender.
Además, el lenguaje de alto nivel permite escribir códigos mediante idiomas que conocemos (español, inglés, etc.) y luego, para ser ejecutados, se traduce al lenguaje de máquina mediante traductores o compiladores.
¿CÓMO DAR INSTRUCCIONES?
Conocimiento declarativo vs imperativo:
Declarativo: qué tipo de relaciones existen entre diversas variables u objetos. Ejemplo: una fórmula matemática
Imperativo: como llegar a un resultado (algoritmos
Algoritmo: primeros programas de computación, desarrollados para la primera computadora (nuestro cerebro). Un algoritmo es una lista de instrucciones que describen un cómputo, que cuando se ejecuta con ciertas entradas (inputs) ejecuta pasos intermedios para llegar a un resultado (output).
El primer algoritmo para la generación automática de números de Bernoulli fue descrito por primera vez por Ada Byron en sus notas del año 1843 sobre la máquina analítica de Charles Babbage.
Grace Murray Hopper entre las décadas de los 50 y 60 desarrolló el primer compilador para un lenguaje de programación, así como también propició métodos de validación.
C es un lenguaje de programación de propósito general originalmente desarrollado por Dennis Ritchie entre 1969 y 1972 en los Laboratorios Bell,1 como evolución del anterior lenguaje B, a su vez basado en BCPL.
Guido van Rossum es un informático, conocido por ser el autor del lenguaje de programación Python. Eliminando casi todos los símbolos que nos hacían tener problemas cognitivos, creando un lenguaje de programación más sencillo de leer.
Programación actual:
Turing completess (Implementan todos los primitivos que se necesitan para realizar cualquier tipo de cómputo)
Los lenguajes de programación modernos nos dan ciertas herramientas que hace que escribir programas sea mucho más sencillo que con los primitivos de Turing.
Leguajes
Sintaxis: Definen la secuencia de símbolos que está bien formada
Semántica estática: Define que enunciado con sintaxis correcta tienen significado
Semántica: Define el significado. En los lenguajes de programación solo hay un significado
Al igual que B, es un lenguaje orientado a la implementación de sistemas operativos, concretamente Unix. C es apreciado por la eficiencia del código que produce y es el lenguaje de programación más popular para crear softwares de sistemas y aplicaciones.
¿QUÉ ES UN LENGUAJE DE PROGRAMACIÓN?
Es un lenguaje formal que, mediante una serie de instrucciones, le permite a un programador escribir un conjunto de órdenes, acciones consecutivas, datos y algoritmos para, de esa forma, crear programas que controlen el comportamiento físico y lógico de una máquina.
GARBAGE COLLECTO
Un recolector de basura (del inglés garbage collector) es un mecanismo implícito de gestión de memoria implementado en algunos lenguajes de programación de tipo interpretado o semi interpretado.
Recolección de basura informática. El espacio de memoria se va llenando con diferentes “objetos”, también pueden destruirse algunos de ellos, dejando “huecos” en el espacio de memoria. Cuando ya no queda espacio disponible, o cuando lo decide la rutina de recolección de basura, la memoria es “compactada”, colocando todos los “objetos” que se están usando al principio, y consolidando todos los “huecos” de memoria al final, quedando así una gran área de memoria disponible para la futura creación de objetos.
ASIGNACIÓN DE VARIABLES
CADENAS
Las cadenas son secuencias de caracteres.
Los operadores que utilizamos tienen otros significados. Cuando utilizamos el operador multiplicar (*) lo que haremos es multiplicar la cadena por el número de veces que deseamos, y con el operador suma (+) concatenaremos varias cadenas, sin embargo, Python nos permite concatenar de una forma más legible
A las cadenas les podemos asignar diversas funciones:
Entradas
Las entradas son una forma recibir información para que las computadoras logren realizas cómputos.
Python tiene la función input para recibir datos del usuario del programa
Input siempre regresa cadenas, por lo que, si queremos utilizar otro tipo, tenemos que hacer type casting. El type casting es transformar el tipo de dato en otro, con esto podemos transformar el tipo y guardarlo en memoria asignándolo a una variable.
PROGRAMAS RAMIFICADOS
Para que nuestros programas realicen trabajos interesantes estos deben ser capaces de tomar decisiones, test o pruebas, es desde este concepto donde salen las ramificaciones. Dentro de los test que podemos realizar son los operadores de comparación y estos nos devolverá si la comparación es verdadera (True) o falsa (False).
Igual (==): Lo utilizaremos para comparar 2 objetos.
Distinto (!=): Verificamos que los objetos sean distintos.
Mayor que (>): Igual que en algebra, comparamos si el primer término es mayor que el segundo.
Menor que (<): Verificamos que el primer término sea menor que el segundo.
Mayor igual que (>=): Verificamos que el primer término sea mayor igual al segundo.
Menor igual que (<=): Verificamos que el primer término sea menor igual al segundo.
Además de los operadores de comparación también tenemos los operadores lógicos, estos son 3 (and, or, not).
Una vez que podemos entender bien los operadores de comparación y lógicos podemos generar nuestros programas ramificados. Una forma típica de ocupar los operadores es con el método if.
ITERACIONES
Estructuras de control que me permiten llevar un flujo siempre que una condición se cumpla. Si esta condición se cumple eternamente, y no le decimos al programa que se detenga se generará un infinit loop. Podemos usar un break para salir anticipadamente de una interacción
BUCLES FOR
Los bucles, en diversos lenguajes de programación pueden ser definidos o indefinidos. Los bucles definidos preestablecen las condiciones de la iteración por adelantado. Por su parte, los bucles indefinidos establecen la condición en la que una iteración terminará. En este último tipo de bucles existe el riesgo de que el bucle se vuelva infinito (cuando la condición de suspensión nunca se cumple).
Los bucles definidos se implementan en Python a través del keyword for. Por su parte, los bucles indefinidos se implementan con el keyword while.
Iterables
En Python, un iterable es un objeto que se puede utilizar en un bucle definido. Si un objeto es iterable significa que se puede pasar como argumento a la función iter. El iterable que se pasa como parámetro a la función iter regresa un iterator
¿Qué pasa si le pasamos a la función iter un objeto que no es iterable? Obtendremos un TypeError que señala que el objeto no es un iterable. Esto es un ejemplo de programación defensiva en el que Python verifica el tipo del objeto antes de proceder al cómputo.
Es importante señalar que estos no son los únicos tipos de objetos que pueden ser iterable. Existen gran cantidad de ejemplos en la librería estándar y, de hecho, casi cualquier objeto se puede convertir en un iterable
Iterators
Un iterator es un objeto que regresa sucesivamente los valores asociados con el iterable
¿Cómo implementa Python los bucles definidos?
Ahora ya conocemos todos los elementos necesarios para entender que es lo que sucede en Python cuando ejecutamos un bucle for.
Bucles for con diccionarios
Para iterar a lo largo de un diccionario tenemos varias opciones:
Modificación del comportamiento de un bucle for
Podemos modificar el comportamiento de un bucle for mediante los keywords
break y continue.
break termina el bucle y permite continuar con el resto del flujo de nuestro
programa.
continue termina la iteración en curso y continua con el siguiente ciclo de
iteración.
++Resumen ++
Esto es lo que sucede al querer ejecutar un ciclio for:
Una función interna del ciclo llamada iter() se encargará de verificar si nuestro objeto realmente es iterable.
Si NO es iterable saltará un error llamado TypeError y ahí de tendrá el proceso
Si SI es iterable
Se ejecutará una segunda función interna del ciclo for, llamada next() (la cual es el iterador) OJO: Lo que hará next() será ejecutarse sobre cada uno de los elementos que están dentro del objeto iterable (que en este caso son números) y cada una de estas ejecuciones representan una vuelta del ciclo for.
Cada ejecución de next() produce un output (la salida de cada número) que será almacenado directamente en la variable que itera (variable storage).
ENUMERACIÓN EXHAUSTIVA
También llamado “Adivina y verifica”
Las computadoras actuales son muy rápidas
Uno de los primeros algoritmos que deber tratar
APROXIMACIÓN DE SOLUCIONES
BÚSQUEDA BINARIA
Cuando la respuesta se encuentra en un conjunto ordenado, podemos utilizar búsqueda binaria
Es altamente eficiente, pues corta el espacio de búsqueda en dos por cada iteración
FUNCIONES Y ALCANCE DE LAS FUNCIONES
La abstracción significa que tu no necesitas entender la forma en la que algo opera internamente, para poderlo utilizar. Una de las habilidades más importantes de los ingenieros de software es generar estas abstracciones, por que utilizan librerías escritas por otras personas en donde no necesariamente les interesa como se implemento algo o como está escrito el código internamente, sino lo q interesa es como utilizarlo.
La decomposición permite dividir el código en componentes que colaboran con un fin en común. Se puede pensar como mini programas dentro de un programa mayor
SCOPE O ALCANCE
El scope o alcance básicamente define las variables, funciones demás a los que una parte del código tiene acceso. El scope va cambiando conforme la ejecución avanza en el programa, por ejemplo, al invocarse una función, el scope actual queda guardado en memoria y se crear un nuevo scope para la función.
Se puede visualizar como esas muñecas rusas que se pueden meter una dentro de otra, de la misma forma hay scopes dentro de un scope dentro de otro scope y así sucesivamente
ESPECIFICACIONES DEL CÓDIGO
El docstring o la documentación está dividido en tres partes importantes que son las siguientes:
RECURSIVIDAD
Algorítmica: Es simplemente una forma de crear soluciones utilizando el principio de divide y vencerás que significa divide y vencerás. Significa que un problema podemos resolverlo utilizando versiones más pequeñas del mismo problema. Es decir, un problema que en principio puede parecería difícil. Podemos encontrar una solución base que es muy sencilla de resolver y utilizarla para que nosotros iterativamente
Programática: Una técnica programática mediante la cual una función se llama a si misma.
FUNCIONES COMO OBJETOS
Una de las características más poderosas de Python es que todo es un objeto, incluyendo las funciones. Las funciones en Python son “ciudadanos de primera clase”.
Esto, en sentido amplio, significa que en Python las funciones:
Hasta ahora hemos visto que las funciones pueden recibir parámetros para realizar los cómputos que definen. Algunos de los tipos que hemos pasado son tipos simples como cadenas, números, listas, etc. Sin embargo, también pueden recibir funciones para crear abstracciones más poderosas.
Funciones en expresiones
Una forma de definir una función en una expresión es utilizando el keyword lambda.
lambda tiene la siguiente sintaxis: lambda <vars>: <expresion>.
Otro ejemplo interesante es que las funciones se pueden utilizar en una expresión directamente. Esto es posible ya que como lo hemos platicado con anterioridad, en Python las variables son simplemente nombres que apuntan a un objeto (en este caso a una función).
Funciones en estructuras de datos
Las funciones también se pueden incluir en diversas estructuras que las permiten almacenar. Por ejemplo, una lista puede guardar diversas funciones a aplicar o un diccionario las puede almacenar como valores.
TUPLAS (1,)
RANGOS: range( , , )
LISTAS Y MUTABILIDAD [ ]
Son secuencias de objetos, pero a diferencia de las tuplas, si son mutables
Cuando modificas una lista, pueden existir efectos secundarios (side effects)
Es posible iterar con ellas
Para modificar una lista podemos:
Asignar via índice (mylista[0] = 5)
Utilizar los métodos de la lista
Clonación de listas
Casi siempre es mejor clonar una lista en vez de mutarla
Para clonar una lista podemos utilizar rebanadas (slice) o la función list
c = list(a) clona la lista a sin ser la lista a
d = a[::] hace lo mismo solo q es otra notación
List comprenhension
DICCIONARIO {:, :,}
Son como listas, pero en lugar de usar índices utilizan llaves
No tienen orden interno
Los diccionarios son mutables
Pueden iterarse
Códigos
My_dict(‘xxx’, numero). Crea una nueva variable xxx y le asigna el valor de número, si es q no existe. Si existe te bota el numero original
My_dict[‘xxx’] = numero. Reasigna el número.
del My_dict[‘xxx’] elimina el valor xxx
PRUEBAS DE CAJA NEGRA
PRUEBAS DE CAJAS DE CRISTAL
DEBUGGING
Reglas generales para evitar los buggs
Diseño de experimentos
Errores comunes
MANEJO DE EXCECPCIONES
++Excepciones como control de flujo ++
Es mejor usar excepciones que nos permitan controlar los posibles errores que pueden ocurrir en nuestro código. Pero por que no es mejor usar un control de flujo con if elif o else. Python esta basado en el principio de EAFP (easier to ask for forgiveness than permission, es más fácil pedir perdón que permiso, por sus siglas en inglés). Este estilo de programación es común pyhton en el cual se asumen llaves, índices o atributos validos y se captura la excepción si la suposición resulta ser falsa. Es importante resaltar que otros lenguajes de programación favorecen el principio LBYL (look before you leap, revisa antes de saltar) en el cual el código verifica de manera explícita las precondiciones antes de realizar llamadas.
**AFIRMACIONES **