[MÚSICA DE FONDO]
DAVID: Muy bien, esto es CS50, y esta es la lección 9.
Recientemente, nos sumergimos en varios
lenguajes, entre ellos, HTML, CSS, y últimamente Python.
Y dentro de poco veremos JavaScript,
veremos SQL y más.
En un momento, veremos si podemos entender lo que
pasa con varios de esos lenguajes.
¿Para qué se usa HTML?, el lenguaje que estudiamos hace un par de semanas.
PÚBLICO: Para sitios web.
DAVID: Para sitios web.
OK, pero seamos más específicos.
¿Qué acerca de los sitios web?
PÚBLICO: Para el marcado.
DAVID: Para el marcado.
OK, seamos más específicos que el marcado.
¿A qué me refiero con eso?
PÚBLICO: La manera en que lucen.
DAVID: La manera en que lucen.
El marcado de un sitio web, la estructura del sitio web,
y los contenidos del sitio web, son lo que queremos marcar al usar HTML,
Lenguaje de marcado de hipertexto.
No es un lenguaje de programación, porque no
tiene funciones, bucles, condiciones,
y el sentido del control lógico que usamos desde hace tiempo.
De hecho, se trata de como se presenta la información.
Hacer algo en negritas,
hacer letra cursiva.
poner algo centrado y así sucesivamente.
CSS nos permite llevar las cosas hasta las últimas consecuencias
y obtener la estética correcta.
Así, lo que acabo de describir, en negrita, cursiva y centrado,
lo hicimos como en la primera versión de HTML.
No existía CSS.
Actualmente, el mejor enfoque es el factor fuera de ese tipo de estética
de HTML, y en su lugar ponerlos en el lenguaje CSS
con hojas de estilos en cascada,
HTML se convirtió en un lenguaje para colocar texto en una columna,
poner este otro texto en otra columna,
estructurar nuestros datos de cierta manera,
y al emplear CSS, se estiliza con colores, fuentes y ubicación.
Hace poco, presentamos Python.
¿Y qué cosas sobresalientes se pueden decir sobre Python?
¿Qué fue lo que obtuvimos?
¿Alguien?, ¿allá atrás?
Python...
PÚBLICO: Una sintaxis más directa.
DAVID: Una sintaxis más directa, sí, de alguna manera,
y veremos alguna sintaxis donde, retiro lo dicho, creo.
En general, ese es el tipo de caso,
porque se usan paréntesis si son estrictamente necesarios,
no necesitamos llaves, solo porque sí.
Por otra parte, cosas como la sangría se vuelven más importantes,
es un poco molesto, pero por otro lado,
se refuerzan los buenos hábitos,
probablemente eso es algo bueno.
Al final de la última lección,
hicimos algo, que con suerte, fue maravillosamente inspirador,
qué fue implementar, ¿qué en Python?
PÚBLICO: ¿El diccionario?
DAVID: El diccionario.
Prácticamente reimplementamos
todo el problema speller de la serie 5, al usar 15, 20, 25 líneas de código,
sin mencionar que se pudo escribir en 30 segundos.
Eso no es solo porque sabía lo que quería escribir,
es porque se debe escribir en pocas líneas de código.
Con Python, dentro de poco con JavaScript, e incluso otros lenguajes,
obtenemos mucha más funcionalidad gratuitamente.
Si deseamos conocer la longitud de una cadena, llamamos a una función,
si queremos una lista vinculada, crearemos una estructura de datos llamada Lista,
igualmente si deseamos una tabla hash, utilizaremos la estructura Dictionary,
no la implementamos nosotros mismos.
Por debajo del agua, alguien más ahí afuera
implementó toda esa funcionalidad para nosotros,
y ahora nos apoyamos en sus hombros.
El día de hoy, que iniciamos la transición
a la última parte del curso, donde no solo dominamos una línea de comando
ni un punto diagonal algo, en la programación web las ideas son más bien
iguales, siempre y cuando las comprendamos, con suerte
comenzaremos con lo que es HTTP, y cómo la web y el internet
funcionan por sí mismas.
Recordemos que hace un momento buscamos una URL como esta,
visitamos https://www.facebook.com y presionamos
Enter en nuestro navegador, para enviar algún tipo de mensaje
en un sobre, que en nuestro mundo físico podría lucir así.
desde luego, en su lugar, es digital.
¿Qué hay dentro de ese sobre, si en pocas palabras,
escribimos esa URL antes de que trate de llegar a Facebook?
PÚBLICO: Un mensaje de error que lo redirige a
me imagino que [INAUDIBLE] ese.
DAVID: Sí, es posible que no exista un mensaje de error, porque esa URL
tenía el HTTPS.
No sería como un mensaje de error,
sería una preferencia para ir a una ubicación diferente.
PÚBLICO: ¿Se movió?
DAVID: ¿Perdón?
PÚBLICO: Se movió,
parecido a un traslado permanente.
DAVID: ¡Oh, se movió!
No se movió, la URL solo se acortó.
Recordemos todos esos 301 redireccionamientos
que fueron el resultado de, por ejemplo, duplicar, duplicar, duplicar
o quitar la S. Así que, en realidad esto es lo bueno.
Este fue el final de la historia, donde todo funcionó y regresamos
a 200 OK.
Si presiono Enter en mi laptop e intento visitar esa URL,
¿Qué puse, o qué puso mi laptop dentro de ese sobre?
PÚBLICO: Una solicitud.
DAVID: La solicitud para obtener una ubicación, era como el verbo obtener,
como consígueme, diagonal, porque la última cosa en esta URL es la diagonal,
que probablemente tiene un encabezado del servidor.
Recordemos que vimos servidor, dos puntos, el nombre del dominio del sitio web,
y hubo muchos otros encabezados, por así decirlo,
de los que hicimos caso omiso.
En esencia, sobre un pedazo de papel, que virtualmente
está dentro de este sobre, o al menos en estas dos líneas, como un recordatorio
de un protocolo, o una convención de un acuse de recibo
que tratamos de usar con el servidor.
Ahora, cuando el servidor responde con su propio sobre,
¿Cómo cambian estos encabezados?
¿Qué hay dentro de los sobres que regresan con los encabezados HTTP de Facebook?
Lo estropeé hace un momento.
¿Qué?
PÚBLICO: ¿La dirección IP?
DAVID: En algún sitio..., sin embargo,
consideraremos el exterior del sobre,
así es como me llega.
¿Qué hay en su interior?
¿Cuál será el código de estado cuando visite la página de inicio de Facebook?
PÚBLICO: 200 OK
DAVID: 200 OK, y vimos 200, OK solo cuando
buscamos por debajo del agua, por así decirlo, para ver
que había dentro de estos sobres al usar la barra de herramientas del Inspector de
Chrome, las herramientas de desarrollador, o cURL, que usa líneas de comandos.
Las probabilidades son, que hay otros encabezados ahí,
como: Content-Type: text/html.
Creo que ese es el único que vimos
que avanza, mientras creamos nuestras propias aplicaciones basadas en la web,
vimos a Chrome y muchas otras herramientas
de diferentes tipos de contenido.
Veremos imágenes como /png o /jpg,
es más, cada vez que descarguemos una imagen
de un gato o de algo del Internet, se incluyen
los encabezados de ese sobre en dos líneas como esta.
Pero un gato no es una página web,
tampoco es HTML.
Así que, sería como imagen /jpg, si es una fotografía de un gato.
Debajo de esos tres puntos
es donde las cosas se pusieron interesantes en la última mitad
de nuestra lección sobre HTTP, ¿qué vino debajo de todos los encabezados HTTP
dentro de este sobre de Facebook?
¿Qué hay dentro del sobre?
PÚBLICO: ¿Nada?
DAVID: Nada..., sí, técnicamente es una respuesta.
Pero...
PÚBLICO: ¿No son como piezas del archivo?
DAVID: Sí, son las piezas del archivo.
Me refiero a que, es el archivo en sí.
Cuando escribimos una carta en el mundo humano,
en general, ponemos la fecha,
y la dirección de la persona,
además de escribirle, estimado fulano de tal.
Podemos pensar en todo eso como metadatos,
las cosas que no son el meollo de nuestro mensaje para el humano,
se consideran los encabezados HTTP.
Una vez que comenzamos a redactar nuestro primer párrafo
y la parte sustancial de nuestra carta, estará aquí abajo,
por así decirlo.
Ese será el HTML dentro de este sobre.
Si descargo la página de inicio de Facebook a mi computadora,
y veo la página de inicio de Facebook o sus noticias, o si me conecto,
todo ese HTML está adentro de este sobre.
A fin de cuentas, son todos esos ceros y unos,
ahora que ya no estamos en la semana cero,
y que pensamos en términos de lenguaje, hay una gran cantidad de HTML.
¿Cómo se veía ese HTML?
En el caso más sencillo, pudo lucir así.
Esta es una página web más simple que la que posee Facebook,
pero sería un ejemplo del primer párrafo, parecida
a la página de inicio de Facebook que va del servidor al navegador.
Esa es la relación entre HTTP, HTML y
CSS, aunque no se describió aquí.
HTTP es ese protocolo, ese conjunto de convenciones,
como el apretón de manos, que asegura que los datos están formateados
de cierta manera y que me llegan desde el servidor
al navegador, o del navegador al servidor.
Más abajo existe un lenguaje muy específico llamado
HTML, el cual es el contenido real.
¿Qué hace mi navegador tras recibir esto?
Al igual que los humanos, lee el primer párrafo de la carta,
un navegador leerá esto de arriba hacia abajo, de izquierda a derecha,
y dice lo siguiente:
Hola navegador, aquí hay una página web,
aquí está el titular de la página,
aquí está el título.
Colócalo en la barra de pestañas.
Hola navegador, aquí está el cuerpo.
Ponlo en la gran región rectangular de la ventana.
Eso es todo para la página web.
Podemos pensar en abrir y cerrar etiquetas, o iniciar y terminar
etiquetas, que son las directrices
para realizar algo o detener algo.
Eso es lo que hace el navegador por debajo del agua.
La última vez presentamos Python, y no se relacionó
con todo esto.
Es solo otro lenguaje de programación.
Pudimos presentar Python en la semana 1,
justo después de echar un vistazo a Scratch, en vez de estudiar a C.
En vez de eso, iniciamos con el programa gráfico Scratch,
posteriormente pasamos a un nivel muy bajo con C,
construimos, construimos, y construimos por encima de él,
hasta que echamos un vistazo a Python, y resolvimos todos esos mismos problemas
con Python.
De hecho, uno de los retos de la serie
de problemas 6 es retroceder algunas semanas y volver a implementar Mario,
Cash or Credit, Caesar, o Vigenere en Python,
para que tengan sus propias soluciones a mano, o las soluciones
del equipo en C. Y será una especie ejercicio de
calentamiento y un ejercicio reconfortante simplemente para traducir algo que
saben que funciona, o que debería funcionar para un nuevo lenguaje,
y ver el mapeo de uno a otro, tal como lo hicimos con Speller,
pero más poderoso.
También vamos a empezar a construir aplicaciones usando Python
que no hemos construido antes.
Hoy, por ejemplo, haremos
un puñado ejemplos que usan Python
para generar HTML de un servidor para mí.
Porque podríamos escribir esto en nuestra Mac o PC,
podríamos guardarlo,
o subirlo a un servidor en la nube,
y la gente podría visitarlo.
Si visitamos esta página hoy, mañana o al siguiente día
siempre será lo mismo.
Dirá, hola título, hola cuerpo todos los días.
Facebook, Gmail, y cualquier sitio web en estos días es mucho más dinámico.
El contenido cambia según lo que nosotros u otros humanos,
en general, o incluso en el mismo día, es un sitio nuevo.
Hoy exploraremos como se utiliza la programación
en particular en Python, para generar contenido dinámico,
con base en datos en las interacciones de su base de datos
del usuario o cualquier cantidad de otras cosas.
¿Cómo lograremos hacer esto?
Abriré el IDE por solo un momento
con un ejemplo del código fuente de hoy, llamado serve.py.
Este es un ejemplo, algunas de sus características parecerían familiares,
pero no todas ellas.
Primero me desplazaré a la parte inferior.
Este es un programa escrito en Python que implementa un servidor web.
Recordemos, un servidor,
aunque la mayoría crecimos pensando en ella
como una máquina física,
es una pieza de software que se ejecuta en una máquina física.
Para ser claros, ¿qué hace un servidor web?
¿Cuál es su propósito en la vida?
PÚBLICO: Conectarse a Internet.
DAVID: Conectarse, es un poco más grande,
su funcionalidad está mucho más definida.
¿Qué es un servidor web?
Es como un enrutador interconecta cosas.
PÚBLICO: ¿Una puerta?
DAVID: ¿Qué es eso?
PÚBLICO: Nuestra puerta al Internet.
DAVID: Una puerta a... es una descripción
demasiado elegante, en realidad se establecerá lo que hace la funcionalidad.
PÚBLICO: ¿Escucha las solicitudes y luego las responde?
DAVID: Correcto, es una respuesta mucho menos interesante,
más concreta y objetiva en cuanto a lo que hace el servidor.
Es una pieza de software que solo escucha solicitudes HTTP
en Internet que entran por conexiones por cable o inalámbricas.
Tan pronto como se escucha una solicitud HTTP, se obtiene una diagonal,
que responde a esas solicitudes,
eso es lo que hace un servidor web.
Facebook.com y Google.com, y todas estas compañías
tienen el software en servidores web que se ejecutan en máquinas físicas que
escuchan de manera constante esas solicitudes.
La foto que mostré, la última vez, de ese viejo estante en la sede de Google
es un ejemplo de muchos servidores
que ejecutan el mismo software, del mismo modo todos
tenían conexiones de internet que solo escuchaban conexiones HTTP,
si queremos ser precisos, desde algunas semanas atrás,
en el puerto TCP 80, en una cierta dirección IP.
De nueva cuenta, nos podemos abstraer en eso,
al escuchar conexiones en Internet.
¿Cómo funciona esta pieza de software?
Para demostrar lo relativamente fácil que es
escribir en un servidor web, sin importar el contenido que sirve, en la línea 24.
Si pudieran traducir eso al inglés por mí,
con base en el material de la semana pasada, ¿qué hace la línea 24?
No es configurar el servidor.
¿Qué hace la línea 24 en Python?
PÚBLICO: Asigna el puerto al número 8080.
DAVID: ¿Para?
Oh, sí, OK, a port.
¿Qué es exactamente port?
PÚBLICO: Es únicamente una variable.
DAVID: Solo una variable, ¿Cuál es este tipo de datos?
PÚBLICO: Es un entero.
DAVID: ¿Cómo lo sabes?
No veo entero.
PÚBLICO: O la entrada se da como un entero.
Python lo calculó de modo dinámico de alguna manera.
DAVID: Exactamente, a diferencia de C, ya no se especifican los tipos,
pero existen.
Enteros, cadenas, flotantes y así sucesivamente.
Sinceramente, ¿por qué necesitamos especificar enteros
si es obvio para el humano, sin mencionar que debería serlo para la computadora,
que lo que está a la derecha es un entero.
Simplemente, la cosa de la izquierda se hace entero.
Esta es una de las funciones que obtuvimos de Python, en general en
los lenguajes modernos.
La línea 25 es similar.
Dame una variable llamada server_adress.
De esto no hablamos mucho la última vez,
mencioné la palabra solo de pasada,
esto es un poco raro.
Nunca vimos esta sintaxis en C en este contexto,
paréntesis, algo, coma, algo, se cierra paréntesis: ("0.0.0.0", port).
Vimos esa sintaxis cuando llamamos funciones y demás,
o cuando tuvimos las condiciones if o similares, bucles, bucles while,
y bucles for.
Nunca vimos, que yo recuerde, un par de paréntesis
que abren y cierran, y que no tienen nada junto a ellos
aparte del, en este caso, signo igual.
¿Qué hace que esto sea diferente de las otras clases que usamos?
[VOCES QUE SE INTERRUMPEN]
DAVID: Sí, lo siento, ¿lo podrías decir otra vez?
¿Quieres ir en orden con tu compañero?
Si pensamos en cualquier clase de matemáticas o clase de gráficos,
en cualquier momento que tratamos con x y y, son comunes ciertas palabras
para tener pares de números, triples, o cuádruples.
Python soporta esa idea.
Si tenemos dos valores relacionados, y queremos grupos unidos de cierto modo
en nuestra mente, podemos abrir paréntesis, un valor, coma,
y otro.
El término general para esto es tuple.
T-U-P-L-E. Es como un doble o un triple,
Pero un tuple es cualquier cantidad de cosas, una o más cosas entre paréntesis.
¿Por qué están relacionados?
En TCP/IP, el protocolo estipulado en Internet,
la primer cosa es la dirección IP.
La segunda cosa es el puerto TCP.
Así que, tenemos IP y TCP, por lo tanto TCP/IP,
y almacenamos ambas variables en este,
los dos valores en esta ubicación llamada dirección del servidor.
En este tipo de código con el que aún no estaríamos familiarizados,
se declara otra variable a la izquierda denominada httpd,
d significa demonio, que es un sinónimo de servidor HTTP, alias servidor web.
Dame algún tipo de objeto de servidor HTTP.
Esta es una estructura especial, como la estructura Student,
pero esta estructura implementa un servidor web,
pasando la dirección del servidor y lo que sea que esté aquí.
Le diré adiós por el momento.
En la línea 29, la última del código, dice: dentro de esa variable
está una función, conocida como método,
que siempre llama al servidor, que siempre hace eso.
Cuando ejecutamos este programa, y ​​llega a la línea 29,
el programa nunca, nunca se termina.
Pero eso no existe,
solamente se mantiene ahí.
Nunca más veremos una línea,
esto sirve para escuchar siempre solicitudes HTTP.
A continuación, les mostraré lo que hace,
iré a mi ventana de terminal,
y ejecutaré un programa de Python.
PÚBLICO: Python [INAUDIBLE].
DAVID: Exacto, es esto.
A diferencia de C, literalmente decimos Python, que no solo es
el nombre del lenguaje, también es el nombre
del programa, el intérprete que puede entender este archivo.
Y si lo ejecuto, no puedo abrir el archivo serve.py.
No hay tal archivo en el directorio.
Técnicamente, no quise hacer eso,
fue un momento de aprendizaje, ¿qué salió mal?
PÚBLICO: No estás en la carpeta correcta.
DAVID: Sí, no estoy en la carpeta correcta.
Lo mencioné antes, este es el código fuente de hoy, source 9,
solo haré cd en el directorio correcto. Lo haré de nuevo,
Ahora nada parece suceder, para siempre.
Al parecer, el servidor se está ejecutando.
Para continuar,
iré a Web Server, hacia el menú de aquí.
Tengo una pequeña advertencia de Cloud9.
Haré clic en App.
Ahora vean lo que sucede.
Mi nueva URL podría lucir diferente a la de ustedes,
pero en mi caso, simplemente fui a,
porque ese es mi nombre de usuario en Cloud9,
ide50-malan-harvard.edu.cs50.io:8080
Debido a que este programa, este servidor, escucha las conexiones TCP
en el puerto 8080, no es el predeterminado, pero es 8080.
Tan pronto escucha una conexión,
genera un código que aparentemente dice: "hello, world".
¿De dónde viene eso?
Bueno, si hago un alejamiento y de regreso en mi programa voy a la parte superior,
veremos lo que esto es en realidad.
Y no entraremos en los detalles de por qué funciona,
sino de cómo funciona, a fin de cuentas, un servidor web.
Cuando un servidor web recibe un sobre desde el navegador de un usuario, como este
de aquí, mira dentro de él y nota: ¡oh, esta es una solicitud GET!
porque el verbo GET está dentro del sobre.
De modo que hay una función llamada doget, solo por eso.
¿y entonces qué hacemos?
Esta línea de aquí, la 13, le dice al servidor que envíe 200, OK,
le dice que envíe este encabezado: ("Content-type", "text/HTML")
y también le dice que escriba la siguiente cadena: "hello, world",
en lo que en Internet se llama Unicode o "utf8"
y eso es todo,
por lo que este es un ejemplo muy específico.
Este servidor web no es tan útil, porque no importa quién o con qué frecuencia
nos conectemos a este servidor web en el puerto 8080, con nuestro nombre
de dominio, ¿qué es lo que va a mostrar?
PÚBLICO: Hello, world.
DAVID: Hello, world,
así que no es tan interesante, bien podríamos tener que
guardar toda la maldita cosa, como index.html y terminaríamos con eso,
pero no usaríamos Python en absoluto.
Pero, ¿y si, y si en vez de hacer esto, tenemos un código en nuestro servidor web,
que dice algo como esto?
figure out what file was requested from HTTP headers
porque recordemos que podría ser una diagonal,
esto podría ser diagonal zuck, para la página principal de Mark Zuckerberg,
o para alguna otra solicitud.
check if that file exists
If so, send it back to browser
es decir, supongamos que eliminamos las cosas codificadas sobre "hello, world"
y comenzamos a escribir algún código, o al menos por ahora
un pseudocódigo, el cual haga que el servidor web sea dinámico,
Cuando recibe una solicitud en el puerto 8080, comprueba para qué es
con la primera línea 12.
Si la encuentra de manera local en el disco duro,
la enviará de vuelta al usuario.
Y por último, eso es lo que hace un servidor web.
Codifiqué uno sencillo para siempre diga,
"hello, world" pero eso es lo que hace un servidor web,
de modo que no implementaremos el servidor web como tal,
en Python.
En lugar de eso, usaremos una herramienta muy popular llamada flask.
Existen muchísimos software diferentes para servidores web
en el mundo,
y sucede que Flask es uno de ellos.
Estrictamente hablando, se le llama un micro marco,
porque es como una pequeña parte del código, que otras personas escribieron
para mejorar el servicio de los sitios web.
Y en lugar de que escribamos nosotros mismos el servidor web,
usaremos un servidor web que alguien más escribió, Flask
y escribiremos nuestras propias aplicaciones en la web, con él.
Pero, ¿qué significa esto?
De regreso en el IDE, haré lo siguiente,
Para ello desapareceré este servidor y cerraré el archivo de aquí,
luego, le diremos que haga lo que sigue,
crearé un nuevo archivo
y si busco en google, Python,
Python Flask, la única forma en la que puedo saber lo que haré
es si consulté la documentación de Flask
y seguí las instrucciones, literalmente leí toda la documentación
y en algún punto, también he leído la guía del usuario aquí,
revisé algunos ejemplos,
jugué con un poco con mi IDE, guardé algunas cosas y las probé,
y así fue como nació este ejemplo.
Si quieren usar Flask, parece que básicamente tienen que hacer esto,
primero definan una aplicación: app =
y luego dicen flask name: app = Flask (__name__)
¿Por qué?
Por ahora no sería útil entrar aquí en tantos detalles.
pero esto solo dice, hey, Flask, dame una aplicación web,
No me importa cómo se implemente,
tú te ocupas de eso, así no tengo que escribir el código
como en el archivo serve.py anterior.
Y después de eso necesito decirle a Flask qué hacer y cuándo.
Y la forma en que esto se hace en muchos softwares web modernos
es definiendo lo que llamamos rutas.
Se le dice a Flask, o más comúnmente a su servidor web,
hey, servidor, si recibes una solicitud para una diagonal, haz esto.
Si recibes una solicitud para una diagonal zuck, haz aquello.
Si recibes una diagonal para una diagonal inicio de sesión, haz esto otro.
Y el pseudocódigo en un servidor podría ser algo como esto,
if request is for /, then send back home page.
Else if request is for /zuck, lo cual fue uno de los ejemplos de URL
dos veces antes, then send Mark's Home page
Else if the request is for login, then prompt user to log in, etcétera.
Así que esta es una aplicación basada en web, aunque en pseudocódigo.
En sí, no tiene nada que ver con los TCP/IP.
Será el trabajo del servidor web lidiar con ello.
Ni siquiera deseo saber si hay sobres en Internet.
Solo quiero comenzar a escribir código en mi lógica.
Igual que en C, quiero escribir mi función principal y mis funciones auxiliares.
Esto es lo que va a hacer mi aplicación web.
¿Cómo se logra esto?
Bueno, supongamos que quieren hacer lo siguiente.
Dejen voy a...
guardaré esto como application.py, lo cual es una convención, application.py.
Y voy a crear momentáneamente otro archivo llamado index.html.
Necesito crear rápidamente una página web,
y esto se logra con la práctica, entonces
crearé aquí un pequeño titular de una página web,
title, hello, title, y luego aquí abajo, body y hello body.
Ok, es una página web muy simple, igual que la de hace unas semanas.
Eso es todo.
Está en un archivo llamado index.html.
¿Cómo conecto estos dos archivos?
Si tengo un programa escrito en Python, o técnicamente, un pseudocódigo,
y quiero que este programa haga este pseudocódigo aquí,
if request is for slash, then send back the home page.
Bifurcamos aquí... creo que expliqué brevemente un par de veces
que la página de inicio predeterminada de un sitio web
por convención humana, se llama index.html.
Este pseudocódigo es algo así.
"If the request is for slash", lo devuelve específicamente a index.html.
Pero si la solicitud es para /zuck, nos envía a la página de inicio de Mark.
Entonces, ¿qué aspecto tendría?
Voy a copiar esto y crearé un nuevo archivo.
Y solo por diversión, voy a guardarlo como zuck.html y luego hello, world,
I am Mark.
Supongamos que esta es la página de Mark.
Es súper simple.
Obviamente, no es así como se ve Facebook.
Pero es una página HTML válida.
Y ahora tengo dos archivos y una aplicación web.
Así que, técnicamente, debería devolver zuck.html.
Y si sigo con este ejemplo imaginario, le pido al usuario que inicie sesión,
eso probablemente significa mostrar al usuario login.html,
la cual es otra página que tiene un formulario.
Como el formulario que hicimos para nuestro ejemplo simple de Google.
En resumen, una aplicación web es
un programa escrito en algún lenguaje, que responde
a las solicitudes que se basan en cierta lógica.
Y esta es la lógica que no teníamos solo en HTML.
Por ese motivo necesitamos a Python, Java, Ruby, PHP
o cualquier número de otros lenguajes que puedan hacer lo mismo.
C también puede hacerlo, pero sería una verdadera pesadilla
implementarlo en C porque, solo piensen en lo molesto
que es comparar subcadenas o extraer los encabezados HTTP
de algo más largo, sería demasiado trabajo.
Hace dos años teníamos un conjunto de problemas, donde hicimos exactamente
eso, pero ahora es un poco diferente.
Así es cómo hacemos la transición para convertir esto en una aplicación web real.
Voy a traducir esto a código real.
Dejen borro esto.
Y resulta que, en Flask, si desean encontrar una ruta, por así decirlo,
para la diagonal inclinada, haces esto.
Mi aplicación tendrá una ruta para la diagonal, @app.route("/")
Y cuando esa ruta sea visitada por un usuario,
haciendo una solicitud en uno de estos sobres,
sigue y llama a una función en Python llamada index,
aunque podría llamarla como quisiera,
que simplemente devuelve el resultado de renderizar una plantilla llamada index.html.
Pero sé que Flask me da esta función especial llamada
render_template, que generará un archivo.
Pero hace más que eso y por ello tiene un nombre más elegante.
El archivo que quiero generar es index.html.
Y si quiero que sea compatible con la página de inicio de Mark Zuckerberg,
¿Pueden inferir lo que voy a hacer?
PÚBLICO: Def zuck.
DAVID: Ok, def zuck().
PÚBLICO: Y luego devuelve la plantilla renderizada.
DAVID: Sí, entonces devuelve la plantilla renderizada de zuck.html.
Y una cosa más...
PÚBLICO: [INAUDIBLE] diagonal inversa zuck.
DAVID: diagonal inversa... diagonal inversa ¿dónde?
No se necesitan diagonal inversa o caracteres de escape,
pero hay una de estas cosas que en este momento no es como la otra.
PÚBLICO: [INAUDIBLE].
DAVID: Sí, necesitamos definir esta función como,
simplemente, la función que Flask debe llamar cuando el usuario
visita /zuck.
Ahora, parece un poco tonto que hayamos escrito zuck
en tres lugares e index en dos lugares.
Así es como se hace en Flask.
Así podría ser también foo.
Esto podría ser una barra.
Los nombres de las funciones no importan.
Pero también podemos mantenernos cuerdos y usar los mismos nombres
según su relación con las mismas rutas.
Entonces hemos reemplazado dos de mis condiciones en mi pseudocódigo
con el código actual.
Y si damos un paso más allá para hacer la pantalla de inicio de sesión,
apuesto a que solo necesito algo como @app.route("/login")
y luego algo como def login(): return render_template("login.html")
lo cual no me molesté en hacer, pero que sin duda podría
con un poco de copiar y pegar y algunas ediciones.
Así que ahora tenemos una aplicación web que admite tres rutas.
Cuando recibe una solicitud en un sobre de alguien en Internet,
mirará dentro de ese sobre y revisará lo que se está solicitando.
Si se pide ("/"), me voy a esta función,
si se solicita una ("/zuck"), voy a llamar a esta función
o si es ("/login"), voy a llamar a esa función.
Y eso es todo.
La aplicación web no está completa porque observen que
al parecer no hay un código que revise los nombres de usuario y las contraseñas,
ni algunas características sofisticadas que esperarían que existieran.
Pero hay más código por venir.
Por ahora, lo que hacemos es generar, condicionalmente, diferentes archivos.
¿Cómo hago que esto funcione?
Resulta que necesito hacer un directorio llamado templates,
sería mkdir templates, o podría hacerlo con el buscador de archivos, con la GUI,
Enter.
Voy a mover ambos index.html ahí, con mv
Y voy a mover la marca con mv.
Y ahora necesito hacer otra cosa.
Aquí en mi programa, deliberadamente... ¡ups!
Oh, cerremos las pestañas porque moví los archivos.
Muy bien.
Es porque moví los archivos a un subdirectorio.
Voy a abrir de nuevo esos archivos.
Así es que deje espacio deliberadamente por un par de razones.
Primero, Flask... más bien, Python
no tiene idea de lo que es Flask.
Cuando se inventó Python hace años, Flask no existía.
Fue escrito más recientemente por una comunidad
de personas que ha creado un mejor software de servidor web desde entonces.
Si quiero usar un paquete que alguien más escribió, alias una biblioteca,
recuerden que puedo hacer algo como esto, from flask import Flask,
lo cual se ve un poco estúpido,
pero solo significa que en alguna parte del IDE
hemos preinstalado un paquete llamado Flask
dentro del cual hay una función llamada FLASK, con letras mayúsculas,
que es lo que estoy usando aquí.
Y para los fines de hoy, podemos verlo como una estructura.
No es una estructura student, que es nuestro ejemplo hasta ahora,
pero es una estructura especial de aplicación web que utilizo de algún modo.
Pero pueden confiar por el momento en que eso es lo que hace.
Pero render_template tampoco es una función que implementé.
Y, de hecho, en ningún lugar del archivo está realmente definida o implementada.
Resulta que viene con Flask, así que puedo importar una segunda función.
De la misma manera en que importé get_int, get_string o get_float,
puedo importar esta función llamada render_template
y eso es todo lo que necesito aquí.
Ahora voy a continuar y si no cometí algún error,
escribiré lo siguiente,
flask run.
Pues flask, además de ser algo como un marco, una forma de escribir
aplicaciones web, también es un pequeño programa
llamado Flask que toma algunos argumentos de línea de comandos, uno de los cuales
es run, el cual ejecuta la aplicación web en mi directorio actual.
Y ese archivo, por convención, debe llamarse application.py.
Entonces, cuando presiono Enter, veo un montón de resultados de depuración.
El depurador está activo.
Veremos lo qué significa eso en algún momento.
Y ahora está aquí la URL.
Se ve horrible porque tengo un nombre de usuario bastante largo aquí, en Cloud9,
pero tengan en cuenta que está el puerto 8080 y eso es importante.
Ahora lo abrimos
y ahora vemos "hello, body".
Pero aquí arriba... y recuerden que la diagonal está inferida,
Chrome solo se usa amigablemente y lo oculta.
Si cambio esto a zuck
y doy Enter... aparece "I am Mark".
Y si lo cambio por login, ¿qué va a pasar?
PÚBLICO: Nada, porque...
DAVID: No se encuentra, así que algo en este momento, deliberadamente,
va a salir mal porque no hice...
¡Huy! OK, entonces no me molesté en hacer esa plantilla aún.
Y entonces pronto dejarán de estar familiarizados con segfaults,
sino probablemente con algo llamado excepción.
Y veremos más de ellos a lo largo del tiempo.
Pero Python, a diferencia de C, admite algo llamado excepciones,
lo cual es un tipo de error que puede suceder.
Y esencialmente, una de las características de Flask, aunque un poco compleja,
es que cada vez que sale algo mal, como un segfault, en este caso
llamado excepción, aparecerá una página web bastante bonita
que yo no escribí.
No hice nada de este código HTML,
Flask lo genera para mí solo para mostrarme
todos los malditos errores que de alguna manera sucedieron,
para que así pueda tratar de entender lo que está pasando.
Afortunadamente, el más importante suele estar en la parte superior.
Y dice lo que necesito saber: "No se encontró la plantilla",
aunque todavía no estoy seguro de lo que significa, "login.html".
Y así, puedo inferir a partir de esto qué fue lo que salió mal.
Entonces este podría ser mi primer ejemplo.
Y los puntos clave aquí son que escribí el código de Python lógicamente
para decidir, si la solicitud entra para esto, hace esto otro.
Si la solicitud entra por alguna otra razón, hace aquello,
de lo contrario, hace otra cosa, es una especie de bifurcación de tres vías
a pesar de que los resultados son solo algunos archivos de texto.
OK, ¿tienen alguna duda o pregunta hasta este punto?
OK, entonces, ahora que tenemos un lenguaje de programación,
podemos hacer cosas mucho más poderosas,
es algo como que trataba de hacer en mis tiempos
cuando aprendí por primera vez a escribir aplicaciones web.
Y una de las primeras cosas que hice,
dejen cierro todo esto,
una de las primeras cosas que hice fue un sitio web para el programa de deportes
intramuros de los estudiantes de primer año.
Voy a ir a froshims0/, abriré algunas plantillas
y lo que estamos a punto de ver es esto.
Aquí hay una pequeña aplicación web que preparé por adelantado,
Está en una carpeta llamada froshims0/ que tiene un subdirectorio de plantillas
en el que hay un montón de páginas web
y probablemente puedan inferir para qué se usan.
El índice probablemente es predeterminado. El éxito tiene algo
que ver con que las cosas salgan bien.
El fracaso probablemente es lo opuesto.
Y aún no sabemos qué son layout.html y application.py.
Eso es.
Entonces, veamos cómo luce index.html
y es como sigue.
En index.html, tenemos un montón de HTML
y corté deliberadamente las primeras dos líneas,
pero, ¿qué es una etiqueta H1?
PÚBLICO: Un encabezado.
DAVID: Un encabezado, entonces es como un gran fragmento de texto en negritas.
Register for Frosh IMs es el texto principal en la parte superior de esta página.
Formulario, acción, registro, método, publicación, lo vimos cuando
reimplementamos Google hace unas semanas.
Aquí, "acción" significa que cuando hagan clic en Enviar,
eso será enviado al dominio "/register" actual.
Y usará un método llamado "post".
No hablamos de esto con más detalle la última vez, pero resulta
que debemos conocer al menos dos verbos en el mundo de la web,
get, que pone todo lo que escriban en la URL, y post, que
en resumen, no lo hace.
Lo esconde de una manera más profunda en el sobre.
Con base en esa definición, recuerden que Google usa get.
Si escribo Google.com/search?q=cats
y con suerte nos saldrá mejor que la vez pasada.
OK, entonces observen esta URL.
debo dejar de buscar tantas noticias.
Observen que la URL tiene mi búsqueda.
¿Por qué no siempre es bueno poner
en la URL, lo que escribió el usuario?
PÚBLICO: Porque es como una contraseña.
DAVID: Sí, y si es como una contraseña,
es posible que no quieran que aparezca en la URL.
Porque tal vez puede pasar alguien entrometido
y leer nuestra contraseña en la URL.
Pero lo peor es que muchos navegadores tienen la función de autocompletar
y recuerdan nuestro historial.
Sería lamentable que nuestro hermanito menor, por ejemplo,
hiciera clic en la pequeña flecha que está al final de esta ventana
y vea todas las contraseñas que hemos escrito en los sitios web.
Ya se imaginarán que esto no es bueno para subir contenidos como fotos.
¿Cómo suben una foto a una URL?
No parece que eso realmente funcione, aunque técnicamente
la pueden codificar como texto.
La información de su tarjeta de crédito o cualquier otra cosa,
me refiero a algo de ustedes que sea privado o que deba ser seguro,
probablemente no quieran saturar la barra de URL
porque de una u otra forma se va a guardar.
Cuando usan el modo incógnito, por ejemplo, y ese tipo de cosas
todo eso se desecha,
pero es solo una mala práctica para obligar a sus usuarios a usar ese modo.
Entonces post no lo pone allí.
Si Google usó post, lo cual no usa para su página de búsqueda,
parecería que estamos en esta URL, sin diagonal de búsqueda, sin signo de
interrogación, sin q y sin gatos, pero aún puede pasar la búsqueda,
solo que es una especie de sitio más profundo dentro del sobre.
En resumen, elegí hacer exactamente
eso porque con Frosh IMs no tenemos
necesidad de guardar los nombres de los estudiantes ni las direcciones de email
ni los dormitorios en las barras URL de las personas innecesariamente.
Entonces, input name="name", y type="text".
Esto me dará un cuadro de texto, similar a q para Google, con el fin de que
alguien escriba su nombre.
Select es un nombre algo extraño, pero, ¿qué nos da visualmente en la pantalla
un elemento seleccionado? ¿lo recuerdan?
¿Sí?
PÚBLICO: Es como una barra desplegable.
DAVID: Sí, es un menú desplegable.
Todos los elementos de ese menú se extraerán de los dormitorios
de primer año de Harvard.
Y luego hacia abajo, en la parte inferior de este archivo, si sigo desplazándome,
observen que hay otra entrada cuyo tipo es Enviar.
¿Y cómo se ve en la pantalla una entrada
cuyo tipo es Enviar, ¿lo recuerdan?
PÚBLICO: Es un botón.
DAVID: Sí, es solo un botón.
Así es.
Y pueden darle otro estilo para que luzca diferente,
pero es solo un botón predeterminado. En resumen, esta aplicación web
me da un formulario en el cual Frosh puede registrar deportes intramuros.
Y puedo verlo de la siguiente manera... si entro en froshims0,
y ejecuto Flask, veré mi misma URL como antes,
pero ahora ejecutará una aplicación diferente en el mismo puerto.
Y así es como se verá.
Es súper simple, es súper fea, pero tiene un cuadro de texto,
tiene un menú desplegable
y un botón para registrarse.
Y ahora el mundo se volvió más interesante
porque ya no tengo solamente contenido estático, como "hello, world"
o "I am Mark".
De hecho, ya tengo algo interactivo para el usuario
y si dicho usuario completa este formulario y hace clic en Enviar,
dos o tres semanas antes lo impulsamos por completo,
y dejamos que Google maneje el envío del usuario.
Pero ahora tenemos Python en un lenguaje de programación que puede
recibir, dentro del mismo sobre, la consulta de gatos del usuario
o el nombre del usuario y el dormitorio.
Y, de hecho, podemos hacer algo con eso.
Este programa aún no hace muchas cosas.
Si entro aquí y hago zoom, y registro a David de Matthews y hago clic
en Registrar, observen lo que sucede.
Termino, tal como lo prometí, en /register,
y me dice "¡Ya estás registrado! (Bueno, no realmente).
Y eso ocurre porque esta es la versión 0
y la verdad no hace gran cosa.
¿Qué hace?
Bueno, regresemos y tratemos de ser menos cooperativos.
Entonces, acabo de recargar la página
y sigue preguntando por mi nombre y mi dormitorio.
No necesitan conocer esa información,
quiero mantenerla privada.
Solo quiero registrarme anónimamente a un deporte, lo que sea que eso signifique.
Register, Ok, ¡me pillaron!
Tengan en cuenta que la URL sigue siendo /register.
Pero me están exigiendo que dé mi nombre y mi dormitorio.
De acuerdo, bien, les daré mi nombre.
Pero no quiero que sepan dónde vivo, así que solo voy a poner David...
Register.
Y me sigue pillando, de alguna manera.
Solo cuando le doy un dormitorio y un nombre, como David de Matthews,
y hago clic en Register, es cuando intenta registrarme.
¿Cómo se ve la lógica?
En pseudocódigo en inglés, incluso si nunca han escrito en Python,
¿Qué tipo de pseudocódigo habría en application.py para esta aplicación?
PÚBLICO: Si no hay texto, proporciona un mensaje de error.
DAVID: Perfecto, si no se le proporciona un texto,
nos proporciona este mensaje de error.
Entonces, demos un vistazo a cómo se implementó.
En froshims0, además de mi plantilla,
tengo de nuevo application.py.
Veamos qué hay de nuevo y qué es diferente.
En primer lugar, esto es más o menos lo mismo que antes.
Acabo de agregar otra cosa aquí llamada request,
por razones que veremos en un momento.
Aquí está la línea de código que dice, hey, Python,
dame una aplicación web llamada app.
Hey, Python, cuando el usuario visite ("/"), renderiza la plantilla index.html.
Así es como obtuve el formulario.
Pero esta es la parte interesante.
Dejen me alejo un poco.
Estas líneas de código son un poco más complicadas,
pero veamos una a la vez.
Esta primera línea, la nueve, está diciendo, hey, Python...
o específicamente Flask, cuando el usuario visite
/register usando el método post, ¿qué quiero llamar?
Para ser más claros, ¿a cuál función?
AUDIENCE: ¿Register?
DAVID: Register, entonces de nuevo, la única relación aquí,
a pesar de que la sintaxis parezca un poco compleja, si dice,
hey, servidor, cuando el usuario visite /register,
llama a la función que está justo abajo llamada register.
Y entonces, ¿qué hace esa función?
Bueno, aquí está la lógica que propusieron hace un momento.
Si no, usa request.form.get("name") or not request.form.get("dorm"):
name y dorm, entonces, return ("failure.html"),
else, implícitamente, return ("success.html").
La única parte que es algo nueva y diferente aquí es la línea 11,
porque en C, tendríamos que usar los signos de admiración.
Tendríamos que usar barras verticales o algo de esa
sintaxis que es un poco diferente.
Pero esto funciona de la siguiente manera,
existe una función llamada get que está dentro de una variable especial llamada
form, que está dentro de una variable especial llamada request a la que tengo
acceso, porque la importé aquí.
Y esa función get busca, dentro del sobre virtual,
un campo llamado name, el cual puede ser introducido en el sobre
si un usuario escribió su nombre.
Y si existe, devuelve "David",
"María", o quien sea que se registra, pero si no, lo invierte.
Si no es un nombre, o si no es un dormitorio, genera failure.html.
¿Cómo se ve failure.html?
Bueno, failure.html solo tiene este mensaje hardcoded,
"Debes proporcionar tu nombre y tu dormitorio".
Y ahora, a riesgo de introducir aquí demasiados lenguajes a la vez,
tenemos otro.
Estas llaves y estos signos de porcentaje
son lo que se llama un lenguaje de plantillas.
Pero antes de explicar qué es eso, vean que en la parte superior de este archivo
se menciona otro archivo, "layout.html".
Ese
no lo hemos visto antes.
Antes teníamos archivos index.html completos
o archivos zuck.html completos.
¿Pero qué era cierto hace un momento acerca del index.html y el zuck.html
de nuestro último ejemplo?
Voy a abrirlos de nuevo rápidamente.
Recuerden que Index.html se veía así
y zuck.html se veía así.
En pocas palabras, ¿qué notan en ambos?
PÚBLICO: [INAUDIBLE] es casi lo mismo.
DAVID: Sí, son casi idénticos, ¿verdad?
Parecen diferir solo en sus títulos,
obviamente, y en el contenido del cuerpo.
Pero todo el resto de la estructura es idéntico.
Y para ser justos, no hay mucho en rojo allí,
tampoco hay demasiadas etiquetas.
Pero quiero decir, copié y pegué esto frente a ustedes
y, generalmente, eso ya es dar un paso en la dirección equivocada.
Entonces, tenemos una oportunidad aquí.
Hay un problema por resolver
y ya lo hemos hecho antes, ¿verdad?
En C, si solo copiaban y pegaban ciegamente el código
necesitaban hacerlo en varios sitios, lo cual es un poco tonto,
es algo desordenado,
es difícil de mantener.
Por el contrario, probablemente deberían definirlo como una función
que se llama en varios lugares.
Ahora, este no es un lenguaje de programación, entonces no hay
una noción comparable de una función.
Ya que es un lenguaje de marcado que solo tiene valores hardcode,
pueden pensar que esto es una plantilla o un molde
donde ponen algo aquí y luego acá y luego más allá.
Entonces, si piensan en el mundo físico
como plantillas que se tienen, o como un molde en el que
vaciamos valores específicos, eso es de lo que estamos hablando.
Y eso es layout.html en este ejemplo de froshims.
No lo he abierto hasta ahora, pero aquí está, en cierto modo complejo,
un ejemplo de layout.html.
Observen que tiene el tipo de documento.
Tiene encabezado HTML, título, algunas otras cosas acá y cuerpo.
Pero luego, tiene este marcador de posición.
Y lo admito, la sintaxis es algo compleja e irritante,
pero solo está diciendo, pon algo aquí.
Y eso es todo.
¿Qué estamos poniendo allí?
Si volvemos a failure.html, observen que funciona de la siguiente manera.
Failure.html extiende conceptualmente esta plantilla.
Toma prestado ese molde, llamado layout.html.
Y observen que tiene aquí las mismas palabras clave, block body y block.
Esto solo significa, conecta esto en ese archivo.
Y esto me permitió romper rápidamente mi hábito
de copiar y pegar todo, aun cuando el formato de estos archivos
es casi idéntico.
Si vuelvo a application.py, observen
que este programa generó, ya sea index.html o failure.html,
o success.html.
Habría sido bastante tonto copiar y pegar mi código tres veces.
Es por eso que me dediqué un tiempo para crear un cuarto archivo, layout.html,
solo para factorizar todo lo que resulta común.
Y el lado positivo es que también, significa que todas estas páginas
tienen el mismo aspecto estructural.
Y si tuviera un logotipo elegante en mi sitio web
y una buena marca para mi sitio web, todas mis páginas
se verían igual, a excepción de un mensaje que cambia en el medio
de la página.
Y entonces, esto es Frosh IM0.
¿Alguna pregunta sobre cómo se ve?
Bien, tenemos aquí un par de oportunidades.
Creo que sería interesante recordar
que el usuario se registró, en vez de simplemente
tratar de generar un valor hardcoded, como "Está registrado".
Bueno no realmente, porque no hago nada con su nombre o dormitorio.
Entonces tal vez podríamos guardarlo en la memoria
y ver quién se registró en el sitio.
Sería incluso más genial si, como antes cuando implementé
el sitio web froshims, se pudiera enviar un correo electrónico a quien se registra
para confirmar que ya están registrados.
O mejor, ¿por qué no lo guardamos en una mini base de datos?
como un archivo CSV, que yo, como la persona que ejecuta froshims,
puedo abrir en Excel, en Numbers. en Hojas de cálculo de Google, o similares.
Pero antes de llegar a ese tema, tomemos nuestros cinco minutos de descanso
y volvamos para resolver estos problemas.
Ya estamos de vuelta
y pensé que hoy sería oportuno,
ya que es posible que se pregunten quién es ese Stelios
que estuvo en bastantes de nuestros ejemplos de memoria.
Hoy nos visita, de la Universidad de Yale, uno de nuestros asesores, Stelios.
STELIOS: Hola a todos.
PÚBLICO: ¡Te amamos!
[APLAUSOS]
STELIOS: Yale está de vacaciones, así que dije, ¿por qué no visitarlos?
Sí, estoy feliz de verlos.
He estado aquí muchas veces.
Es un espacio hermoso.
y sí, dije, ve y saluda después de la conferencia.
DAVID: Estamos muy contentos de tenerte.
Gracias, Stelios.
Algo que llamó mi atención fue que no me enfoqué
mucho en mis registros en la ventana de terminal, los cuales registran
todas las solicitudes HTTP que se reciben durante el funcionamiento de un servidor.
Y esta es una captura de pantalla de mi ventana de terminal desde hace un momento.
Recordarán que visité la diagonal y que luego traté de registrarme,
pero en el inter, aparentemente alguien del público,
o en Internet, trató de visitar la diagonal
utilizando get en su navegador.
Me deslice por algunas otras entradas de Internet,
pero las que más se podían compartir fueron estas...
bro, /David y /nice.
Así que eso fue lo último antes de que matara al servidor.
Y eso es porque, aunque aún escucho en un puerto no estándar, el 8080, a ese
nombre de dominio, compartí mi espacio de trabajo para que cualquiera pudiera
tener acceso mientras el servidor se ejecuta.
Y si están aquí físicamente o sintonizándonos
en una transmisión en vivo, es obvio que estoy
anunciando públicamente que el puerto 8080 es donde pasamos nuestro tiempo.
Pero si volvemos a Flask y minimizamos nuestros registros,
pensemos en cómo podemos recordar que los usuarios han iniciado sesión.
A continuación demostraré, entre los ejemplos de hoy,
froshims1, ejecutando flask run.
Luego voy aquí arriba, a la misma URL de antes.
Y esta vez veremos que si prosigo
y me registro como David de Matthews...
Register, observen que en lugar de ir a /register,
cambié un poco las cosas
e iré a /registrants, porque ahí,
al parecer, tengo algo de HTML que genera una lista con viñetas
de quién se ha registrado.
Y ahora tal vez registraré
a María de Apley Court...
Register.
Y ahora tenemos dos.
Además, si vuelvo a cargar la página, observen que la información persiste.
¿Cómo funciona esto?
Bueno, echemos un vistazo dentro de application.py para froshims1/
punto...
para froshims1/.
¿Qué tenemos aquí dentro?
Igual que antes, estoy configurando mi aplicación con una línea como ésta,
es como decir, hey, Flask, dame una aplicación.
Y luego, reclamo a mis registrants.
Esto es solo un comentario en Python, # Registrants.
¿Y qué representa students = []?
PÚBLICO: Una lista.
DAVID: Una lista, sí, es una lista vacía.
Es como un arreglo vacío.
Pero a diferencia de C, donde los arreglos no pueden crecer o encogerse,
en Python las listas, que son similares a un arreglo,
pueden crecer y reducirse de manera dinámica.
Si quieren una vacía, simplemente
dicen, dame una vacía.
Y descubriremos después la longitud final.
Y lo que resulta atractivo de esto, en la línea 7,
es que ahora tengo una variable llamada students
que se inicializa en una lista vacía,
pero que ahora está en la memoria de la aplicación web.
Recuerden que cuando ejecuto flask, no vuelvo
de inmediato a mi prompt.
El programa no solo se ejecuta y luego se detiene,
sino que sigue escuchando, escuchando y escuchando,
esperando a que entren más de estos sobres.
Dado que llamamos a estas diversas funciones
index o registrants, o de otro modo, como ya veremos
todas tienen acceso a esa variable global, que en este ejemplo es students,
y cualquiera de ellas puede agregar más y más y más datos
dentro de students.
Ahora, para continuar,
mostraré que en las visitas del usuario ("/"),
solo devolvemos index.html.
De lo contrario, si visitan "/register", observen
que esta vez obtenemos una lógica interesante.
Si el usuario visita "/register" por medio de ["POST"]
y la única manera en que hemos visto que esto podría pasar, hasta el momento,
¿es si el usuario hace qué?
¿Cómo se hace algo por medio de ["POST"]?
PÚBLICO: Se envía.
DAVID: Se envía un formulario.
Entonces, los humanos podemos simular get muy fácilmente
simplemente con ir a una URL y escribirla en el navegador,
ya estamos usando get de manera predeterminada.
No podemos hacer lo mismo tan fácilmente para POST.
Solo tenemos acceso a la barra de URL.
Pero si tenemos un formulario web, como el de index.html
con el menú desplegable dorm y el cuadro de texto name,
podemos enviarlo por medio de Post, que es como se puede aplicar esta ruta
a aquella ruta en particular.
Entonces, lo que digo aquí en la línea 21 es, hey, dame una variable llamada name
y pon en ella lo que el usuario haya escrito en el campo name.
Dame lo mismo para dorm.
Y observen, incluso si se trata de un gran menú desplegable de elementos,
el usuario solo seleccionará uno de ellos
y entonces recuperaremos este valor.
Y luego tenemos un poco de lógica estilo Phyton.
if not name or if not dorm, lo cual se ve bien,
es un poco conciso, y hubiera resultado extraño hace unas semanas,
pero ahora se ve mejor, quizás, de lo que hubiera sido en la primera semana en C.
Luego continúa con return ("failure.html"),
si nos falta el nombre o el dormitorio.
Si no es el caso, y no nos ha devuelto un error,
entonces va a students.append y luego a la cadena f.
Entonces .append, por si no lo recuerdan,
y es posible que no lo recuerden, porque no sé si lo vimos,
es un método o función integrada a una lista que
permite agregar un valor a una lista llamada students.
Así es como crece un arreglo en Python.
Simplemente se agrega y el programa descubrirá
la longitud de esta lista.
Esta cadena f significa que ahí va una cadena formateada, similar
a printf, pero la sintaxis es un poco diferente.
Y la cadena que estoy formando aquí es tal y tal de esta y esta,
así que, {name} from {dorm}
con las llaves dentro de una cadena de formato, o de una cadena f,
significan que debemos conectar estas variables en dicha cadena f.
Y esta es una nueva característica.
Podemos devolver, no solo la plantilla de renderizado,
sino que también podemos devolver la redirección y la ruta
a la cual deseamos redirigir al usuario.
Y adivinen qué.
Si llaman a redirect("/registrants"),
¿qué hace flask?, porque flask nos dio esta función de redirección
dentro del sobre para nosotros.
PÚBLICO: Una nueva dirección.
DAVID: Una nueva dirección, ¿y qué tipo de código de estado?
PÚBLICO: 301.
DAVID: Como 301.
Ya lo vimos un par de veces.
301 significa redirigir al usuario.
Entonces esta función maneja todo eso por nosotros.
No tenemos que saber o preocuparnos por cómo se generan esos
códigos de estado.
Mientras tanto, /registrants es súper simple, pero cuenta con
una nueva y agradable característica.
Así que /register, al que se envía el formulario, hace todas estas cosas
y luego redirige al usuario a /registrants, solo porque sí.
Y queda mejor diseñado si esta ruta
solo se usa para guardar información, y esta ruta
solo se usa para ver información, porque de esta manera
también pueden visitarla a través de get.
Noten que estoy devolviendo "registrants.html",
Pero estoy haciendo algo un poco diferente esta vez.
¿Qué es diferente en la línea 16, con respecto a lo que nuestras otras plantillas
renderizadas llamaban antes?
PÚBLICO: Students igual a...
DAVID: Sí, students = students, lo cual es un poco extraño.
Pero sabemos que uno de esos valores se refiere a esta lista de aquí.
Y es un ejemplo de Python cuando admite parámetros con nombre.
Resulta que si quieren pasar datos a una plantilla,
pueden poner una coma y los nombres de los valores que quieran pasar.
Index no necesita esto.
Failure no necesita esto.
success no necesita esto. porque todo está hardcoded,
pero registrants sí.
Con base en lo que vimos, va a generar una lista con viñetas que diga,
David de Matthews y María de Apley Court,
de modo que necesitamos saber quiénes son esos estudiantes.
OK, entonces, en "registrants.html", los estudiantes serán el parámetro nombrado.
Y el valor de ello será esta lista de arriba.
Entonces, el lado derecho es una variable, o un valor
que debe existir en el programa actual,
y el lado izquierdo es una variable que,
ya lo veremos, va a estar dentro de "registrants.html".
Vamos a abrir registrants.html, porque las otras plantillas, sinceramente,
no son tan interesantes.
Index.html es como el formulario web que tiene los campos de dormitorios y nombres.
Failure solo dice, lo siento, debe proporcionar el nombre y el dormitorio.
Layout es simplemente una estructura web similar a la anterior.
Entonces, el único archivo nuevo, además de los cambios en application.py,
está en registrants.html.
Este archivo, igual que antes, amplía un diseño.
Entonces es el molde que está en uso
y va a llenar el siguiente bloque para el cuerpo.
Esto es solo específico de la técnica de plantillas,
solo limpia el código.
Pero lo que realmente interesa está aquí.
Es como una especie de HTML, pero a la vez no lo parece,
¿qué aspecto tiene entonces?
PÚBLICO: Un código de Python.
DAVID: Sí, parece un código de Python
y técnicamente no lo es.
Y me doy cuenta de que esta es una parte difícil del semestre,
tal vez es la parte del semestre donde presentamos
todas estas malditas cosas al mismo tiempo.
Pero este es un lenguaje llamado Jinja,
J-I-N-J-A, el cual es un lenguaje de plantillas.
Y verán esa palabra en la documentación y demás.
Es un lenguaje muy ligero que sirve para mostrar información.
Nos da algunos bucles.
Nos da algunas condiciones.
Y tiene mucho del código de Python.
Pueden pensarlo de esa manera, pero no es necesariamente idéntico.
Así que ahora veremos con ejemplos lo que podemos hacer con eso.
Aquí, tenemos una plantilla de Jinja que dice: "for student in students".
Eso es muy similar a Python.
"For student in students" significa iterar sobre los estudiantes
y llama a cada student que esté en el camino de student.
Es decir, necesito llamar a students porque lo pasa a mi formulario.
Esto podría ser foo, o bar, o S, o lo que sea.
Es solo un bucle.
Y entonces, quizás, puedan adivinar qué hace esta línea,
a pesar de que es un poco compleja.
En la línea 7 tengo algún tipo de HTML familiar,
y es familiar en el sentido de que por unos segundos, hace un par de semanas,
les mostré una lista con viñetas en HTML que tenía muchos elementos de la lista Li.
Pero traten de adivinar.
¿Qué está haciendo la línea 7, probablemente, si tuvieran que
adivinar según el resultado de este programa?
PÚBLICO: Imprimir [INAUDIBLE].
DAVID: ¿Imprimir qué?
PÚBLICO: Imprimir a los estudiantes.
DAVID: A los estudiantes individuales, entonces,
recuerden que la lista students es solo una lista de cadenas tal y tal
de esta y esta, tal y tal de este y este lugares.
De modo que, si inducimos este bucle, iteramos sobre esa variable
y con cada iteración generaremos un elemento, un nuevo elemento en la lista,
en otras palabras, una nueva viñeta, una nueva viñeta, una nueva viñeta, cada vez
que imprimimos {{ student }} con el nombre de ese valor,
obtendremos una lista de estudiantes con viñetas.
Desde luego, el HTML podría no ser bonito
porque esta vez se generó por un humano,
pero este es el HTML.
Si veo Chrome Source para esta página, observen que
obtuve todas estas cosas de mi diseño,
mientras tanto, aquí abajo tengo y
los cuales codifiqué en ese archivo.
Pero no están codificados en ninguna parte,
se generaron dinámicamente.
Esta es la primera evidencia, no solo de
la lógica dentro de nuestra aplicación web basada en Python,
sino también de la capacidad de generar el contenido para el usuario.
Y si continúo ejecutando el servidor y también
tengo personas lo envíen y se registren continuamente
esa lista se haría cada vez más larga
y el supervisor o la persona que gestione
los deportes de interior, puede mirar en esa lista
al ir a \registrants y así saber a quién
contactar, en caso de que solicitemos más información personal
como los correos electrónicos y demás.
¿Hay alguna pregunta sobre este ejemplo?
Muy bien, en el ejemplo 2, donde creamos de nuevo el sitio web
que más o menos implementé en 1997 o en 1998
y aunque fue en un lenguaje diferente, le permitió a los estudiantes de primer año
registrarse en los deportes en interior
y lo haremos de la siguiente manera,
Si entro en froshims2 y escribo flask run,
ahora volveré a cargar esa aplicación
y después solicitaré otra cosa,
hice el formulario un poco más grande al pedir una dirección de correo electrónico
porque esta vez, intentaré enviar un correo electrónico.
Permítanme regresar aquí, al archivo
y reduciré esto para hacerle espacio a froshims2/ application.py
el cual hará lo siguiente.
Tengo algunas indicaciones de contraseña, pero veremos más sobre eso en un momento,
noten que aquí arriba tengo otro import, sin mencionar el del sistema operativo.
Y aquí arriba observen, veamos,
arriba está import smtplib, el protocolo para transferencia simple de correo o SMTP,
el cual tiene relación con el correo electrónico
y eso es, porque este ejemplo funciona como sigue.
En la diagonal ("/") devolvemos ese formato, index.html.
Si en cambio, vamos a ("/register observemos lo que sucede ahora
y quiero mover esto aquí arriba,
aquí vamos.
Ahora tenemos este archivo aquí.. este método aquí
que funciona de la siguiente manera.
Si el usuario intenta registrarse con "POST" llama esta función def register ( ):
obtenemos name,
obtenemos email,
obtenemos dorm, y luego un poco de revisión de salud,
que por ahora no está completa, porque, al igual que antes, solo
pregunto, if not name or not dorm:
Pero, ¿cómo me aseguro de que el usuario me dio su dirección de correo electrónico?
PÚBLICO: [INAUDIBLE].
DAVID: Sí, de modo que si no es name, email,
o dorm, he mejorado este ejemplo si lo comparamos con el último
al verificar también su dirección de correo electrónico
pero si no nos proporcionan una, diremos que hay un error,
por otro lado, ¿qué hace la línea 23?
PÚBLICO: ¿Envía un mensaje?
DAVID: Establece un mensaje, una variable que se llama
message = "You are registered!"
La siguiente línea es un poco críptica y solo sabrían
lo que significa al leer la documentación,
como lo hice al escribir este ejemplo.
En el lado izquierdo tengo una variable llamada server,
que esta vez no será un servidor web, sino un servidor de correo electrónico
con el cual quiero conectarme.
En particular, quiero usar esta biblioteca llamada smtplib,
que es una función SMTP o Protocolo para Transferencia Simple de Correo,
para conectarme a una dirección que podría no haber visto antes con claridad,
pero probablemente adivinen el servidor al que me conecto en el puerto TCP 587.
En resumen, aun cuando la mayoría de nosotros, si usamos Gmail,
solo vamos a Gmail.com y comenzamos a usarlo,
y al parecer es un puerto 80,
en el fondo, cada vez que redactemos un mensaje
y hagamos clic en Send o enviemos un archivo, lo que se genera
es un código como este en Google
después ellos se conectan a su propio servidor de salida de correo
llamado servidor SMTP, el cual será esta dirección.
Se conectan a él por medio del puerto TCP 587, porque no es una página web,
es un correo y por lo tanto tiene un número único propio,
los humanos decidieron hace años.
En esta línea de aquí, la 25, starttls, se inicia la codificación
para que de esta manera, en teoría, nadie entre nosotros
y Google pueda ver el correo electrónico que enviamos a su servidor.
Después aquí codifiqué algunos valores, lo cual
tal vez no sea lo mejor, pero lo hice
para que me permitiera registrarme los primeros años a froshims.
pero, ¿qué ocurre después?
En la línea 26, esta es la línea
de acuerdo con la documentación de esta biblioteca,
por la cual puedo iniciar sesión con el nombre de usuario jharvard@cs50.net
después de pasar su "PASSWORD"
Hace un par de lecciones, recuerden que
mencioné que existen estas variables de entorno, cuando
hablamos sobre el espacio de la memoria en los programas,
las variables de entorno son valores globales que no están en el código
pero a las que también tenemos acceso,
de modo que esto dice "consigue del entorno",
la contraseña de JHarvard, desde algún lugar en el IDE.
Por lo que no tengo que codificarlo y transmitirlo en Internet.
Mientras tanto, la línea 27 hace lo que dice la función,
esto dice: al utilizar este servidor, Gmail, envía un correo desde jharvard@cs50.net
a esta dirección de correo electrónico, con este mensaje
y este mensaje, como lo habrán notado, es "You are registered!"
Y solo para ser claro, ¿de dónde viene esta variable de correo electrónico?
¿A quién va dirigido este correo electrónico?
PÚBLICO: Al usuario.
PÚBLICO: Al estudiante.
DAVID: Al estudiante que se registró por medio del formulario,
porque tenemos su nombre, correo electrónico y dormitorio,
Suponiendo que escribió una dirección de correo electrónico verdadera,
esto pasa al segundo argumento para enviar un correo y entonces lo envía.
Por último, render_template ("success.html") y voilà.
Ahora estamos por experimentar una de las demostraciones más geniales
que hayamos hecho en el curso, o uno de los fracasos más vergonzosos,
Si desean reproducirlo en casa, vayan a tinyurl.com/fridaycs50
que es bastante fácil de recordar.
Tinyurl.com/fridaycs50, Enter, eso debe redirigirnos con nuestro viejo amigo
el HTTP 301, que debería pasarnos a este formulario
y luego también lo reproduciré en mi casa.
David from Malan y diré que mi dirección es la de John Harvard,
él será de, digamos, Pennypacker,
Register y en verdad estoy registrado, lo que espero también podrán ver pronto.
Y mientras hacíamos eso, recibí una alerta de seguridad en mis cuentas de Google,
porque todos las están usando.
Pero está bien.
Estoy registrado como JHarvard.
Y, ¡oh, mi dios!, todos esos ejemplos,
OK, y los errores que veremos pronto
que explicaré pronto, ¿y qué es lo que obtuve?
Si ustedes, como yo, revisan su correo en algunos segundos, a partir de ahora,
deberían ver un correo electrónico de jharvard@cs50.net, con el mensaje
"You are registered!" que me fue enviado directamente, o con suerte, para ustedes.
Al menos dos de ustedes no recibirán este mensaje,
porque según mi recuperación de correo, tres de ustedes
escribieron mal sus direcciones de correo electrónico en el ejemplo
de modo que me los regresa nuevamente.
así que, si no lo tienen simplemente inténtenlo de nuevo.
Pero, ¿qué ocurrió aquí?
En este caso, escribí un código claramente y por medio de application.py tenía
este route("/register" que esta vez, no solo guardó cosas
en una variable,
sino que las metió en un tipo especial de biblioteca
que sabe cómo enviar los correos.
Literalmente, esto es lo que hice en los viejos tiempos,
no me sucedió eso...
podría haberme sucedido,
pero en 1997, no sabía lo que era una base de datos o dónde podíamos
almacenar la información.
Así que estoy bastante seguro, de que la primera versión de los registros
en línea de Harvard, para froshims, solo se enviaron
al supervisor de un correo electrónico y responsable de ese deporte intramuros,
y esto era bastante bueno,
pues usaban su bandeja de entrada como una base de datos
y así sabían quién estaba registrado.
Sin embargo, esto lo mejoramos con el tiempo
y en la actualidad guardamos las cosas en una base de datos muy ligera.
Todavía no sabía SQL o cómo hacer las cosas de un modo más elegante
y mucho menos sabía lo que era un archivo CSV.
En mi computadora tenía Microsoft Excel y en fechas más recientes Numbers,
de modo que puedo abrir hojas de cálculo.
Pero si en vez de buscarlo acá arriba
decimos froshims3, la cual es nuestra última versión de la serie de ejemplos
de froshims, por cierto, me adelanté e hice esto.
En esta versión del programa,
esto es un poco críptico, pero lo descifré al leer
la documentación de Python sobre cómo usar los CSV
y se me ocurrió lo siguiente.
Al igual que antes en la línea 12, if not "name" or not "dorm"
y regresé a la sintaxis anterior, porque en este momento no estoy
usando la dirección de correo electrónico para este ejemplo
y si vamos más adelante, tenemos a return "failure.html"
Pero este nuevo código, en vez de un correo electrónico, es esta funcionalidad.
Así que aquí tengo file, la cual es una variable, que se almacena ¡ah!
obtiene el valor de retorno open.
De modo que esta es una función en Python, que es similar al fopen en C.
Solo que ellos arreglan el nombre aquí
y esto abre un archivo llamado "registrants.csv".
¿Y qué significan las comillas en "a"?
Probablemente no utilizamos "a",
usamos una letra diferente en p-set 4.
PÚBLICO: [INAUDIBLE].
DAVID: ¿Qué es eso?
PÚBLICO: ¿La r o la w?
DAVID: Usamos r o w para read o write.
Parece que la "a" es un poco diferente, lo cual, en este caso, tiene sentido.
PÚBLICO: Añadir.
DAVID: OK, gracias.
OK, significa "añadir".
Y "añadir" tiene sentido aquí, porque se escribe de manera predeterminada,
prácticamente sobrescribe el archivo
y esto crea un nuevo archivo.
Aunque "añadir" literalmente hace eso,
también le agrega una línea al archivo, una nueva línea al archivo, lo cual
es bueno si queremos tener a más de una persona
en él.
Si queremos recordar a todos los demás añadiendo líneas,
esto dice, oye, Python, abre el archivo en el modo "añadir",
y almacénalo en una variable llamada file.
Esta es una línea de código que usa algo de la sintaxis que no vimos muy bien en C,
pero declara a una variable llamada writer, que usa la biblioteca CSV, la cual
importé en la parte superior del archivo, parecido a la importación de la biblioteca
mail en el otro,
y tiene una función llamada writer, que puedo pasar a un archivo abierto,
también hay una biblioteca especial, que sabe cómo
poner comas entre los valores, cómo guardar
y salir en caso de que haya comas en nuestro archivo,
entre otras cosas.
Y luego esta línea es un poco rara,
pero usa algunos de los componentes básicos anteriores,
writer.writerow, writer.writerow,
por lo tanto, esto hace lo que dice
y dice: usa la biblioteca para escribir una fila, en el archivo abierto.
¿Qué queremos escribir?
Aquí tenemos, a propósito, unos paréntesis adicionales,
por lo que se supone que esta función tome un tuple.
Un tuple son cero o más valores separados por comas,
lo cual es bueno, porque es algo parecido
a una serie de columnas.
Un tuple es algo coma, algo coma, algo
que es exactamente lo que queremos poner en un CSV, algo coma, algo coma
algo,
porque, por si no lo sabemos, un CSV es un archivo donde todos los valores
están separados por comas.
Y si los abrimos en Excel, Numbers o las hojas de cálculo de Google,
cada una de esas comas delimita una barrera entre varias columnas,
esto dice: continúa y escribe una fila en el CSV,
que contenga el nombre y el dormitorio de los estudiantes,
después cierra el archivo y regresa a "success.html"
Aún con el riesgo que implica,
hay un retraso en el Internet como de 30 segundos, lo que
significa que lo podemos mantener limpio durante unos 30 segundos.
Ahora ejecutaré este ejemplo en froshims3 y escribo flask run,
Enter.
En caso de que deseemos ir a la misma URL, tinyurl.com/fridaycs50,
esta nos llevará a una versión algo más antigua del formulario,
sin dirección de correo electrónico, así que, asegurémonos de presionar Reload,
lo que deberíamos ver es esta versión con name y dorm.
Y si escribí el código correctamente, deberían
poder registrarse en un archivo llamado registrants.csv en mi IDE.
No recibirán un correo electrónico esta vez, porque
le quitamos esa funcionalidad.
Pero esta página de registro dice que está funcionando.
Si lo desean, dediquen un momento para hacerlo,
mientras yo regreso al IDE.
Parece que están entrando muchos registros, así que es genial.
Estos son los registros,
así pueden ver a los que visitan el sitio y dan clic en Registro.
De hecho se está registrando mucha gente.
Eso es genial.
Voy a apagar brevemente la pantalla
y ver quién se ha registrado si voy a este directorio.
Esto es... OK, voy a entrar a froshims3, lo cual estoy haciendo.
Veo registrants.csv.
OK, vamos a limpiar esto.
[RISAS]
OK, DAVID 2.0 está registrado, genial.
De acuerdo, voy a descargar este archivo.
Creo que se ve bastante limpio.
Voy a descargar esto.
Y les mostraré lo que estoy haciendo en solo un segundo.
Pero esta es la mejor demo que he visto, por lo que puedo ver.
De acuerdo, y asegurémonos de no me pierda esto aquí.
Ajá, OK, algunos de ustedes solo están pulsando...
Brandon estaba pulsando Enviar bastantes veces, aparentemente.
De acuerdo, no creo que haya algo que lamentar en esto.
OK, vamos bien.
Muy bien, ¿qué acabo de hacer?
Estamos de vuelta.
Ahora que hemos pasado todo por los censores, lo que noté
es que, oh, tengo un archivo registrants.csv en el mismo directorio.
Y eso era lo que se agregaba cada vez.
Por otra parte, si continúo y descargo este archivo
poniendo registrants.csv y luego Descargar,
o podría abrirlo en el IDE para ver las filas y columnas reales.
Creo que haré esto rápidamente,
así verán este archivo,
aunque resulta un poco difícil verlo.
Así que lo cerraré a propósito, porque lo descargué mucho antes,
y de hecho puedo abrirlo en Excel.
Y si en Excel amplío mis columnas, cada una de estas columnas
representa la brecha entre una coma.
Brandon aparentemente trataba de que su nombre fuera muy grande y audaz,
pero eso no funciona en los archivos CSV.
Al parecer Montreal es el mejor,
muchos nombres de pila,
más Brandon... desconocido... OK,
hay uno que mencioné, el padre de alguien.
Tal vez el padre de alguien está aquí hoy, OK.
Tenemos, Wheeee, ¡¡MTL ES LO MEJOR!!, John Harvard, John, Olivia, Batman, Kyle...
[RISAS]
DAVID: OK, hay un Digno de Wiggles,
ahora se está volviendo un poco extraño,
caritas, Cara de..., OK, ese logró colarse,
no me di cuenta.
David, tengo miedo, Ok.
[RISAS]
Así que, gracias a la programación por fin tenemos
la capacidad para mantener cerca algunos de estos datos.
Básicamente, esto nos permitirá comenzar
a crear aplicaciones verdaderamente interactivas,
nos permitirán almacenar la información y finalmente
recuperarla.
Y todo se reduce a algunos de estos simples paradigmas.
Ahora está implicada una gran cantidad de sintaxis compleja.
Y hay algunas ideas nuevas en el camino, cosas como tuples
y cosas como rutas.
Y no usé esa palabra antes, pero técnicamente este signo denota
algo llamado decorador.
Pero al igual que con C en aquellos primeros días, tengan en cuenta
que una vez que empiecen a notar estos patrones,
incluso si no lo aprecian todo o si no entienden nada
al principio, podrán de forma iterativa
sentirse más cómodos con el material.
Si tienen fe en que realmente no recuerdan
cómo funciona esto, pero saben que tienen que hacerlo ya, está bien.
Porque si entienden estas cosas con mayor profundidad,
resolverán el problema y lograrán hacer su trabajo.
Y a medida que se sientan más cómodos, pueden comenzar, con las secciones
y las horas de oficina, y en la serie de problemas 7
comenzar a entender realmente algunos de los matices
y la manera en que se relacionan o no con cosas que vimos antes en C.
¿A dónde vamos con esto?
Bueno, en la serie de problemas 6 vamos a unir varios mundos de la web,
de Python y también de distancia de edición,
y la programación dinámica en nuestra conferencia de Yale de hace unas semanas.
Y si están un poco retrasados en algunos de esos temas,
o si no dominaban bien algo del material que vimos hoy, está bien.
Sin embargo, retrocedan,
porque las últimas tres conferencias culminan en la serie de problemas 6.
Esto los desafiará a regresar y volver a implementar Mario,
ya sea la versión más o la menos cómoda, pero no en C sino en Python.
Lo más probable es que los sorprendan al menos dos razones.
Primero, lo más probable es que si lo solucionaron con éxito la primera vez,
incluso si están un poco oxidados, lo más probable es que
lo resolverán más rápidamente la segunda,
a pesar de que es un lenguaje nuevo.
Y verán que algunas ideas de C se aplican a alguna que otra idea
en Python, tal como hicimos con Scratch para ver ese mismo tipo de transición,
y lo mismo ocurre con Cash or Credit o con Visionaire,
o en Caesar y Crack también.
Pero la cereza del pastel será, no solo escribir código en Python,
sino escribir el código en Python para una aplicación web que haga
algo gráfico con un sitio web.
Por ejemplo, aquí tenemos la versión más cómoda de las soluciones
del equipo para Similitudes, una sección de la serie de problemas 6.
Y lo notarán en este formulario basado en la web,
ahora que estoy en similarities.cs50.net/more.
Su URL, por supuesto, será diferente, ya sea que la hagan
de la forma más cómoda o de la menos cómoda también.
Pero aquí tenemos un formulario web con dos cadenas que vamos a introducir,
dos cuadros de texto.
Y este formulario podría parecer mucho más bonito que los que
he estado haciendo hoy.
¿Qué es lo que no tenían los que estuve haciendo hoy?
PÚBLICO: CSS.
DAVID: No tenían CSS en absoluto,
Así que obtenía cosas bastante viejas y feas
al estilo predeterminado de los 90 que Chrome, IE, Edge, Firefox
y Safari me dan de manera predeterminada. Pero ustedes
pueden usar bibliotecas que les permitan
crear sitios web mucho más bonitos.
Así que, siempre y cuando sepan cómo generar el marcado,
pueden dejar que otra persona lo modele y de ese último paso por ustedes.
Así que la mayor parte de la estética que ven aquí, la linda barra de
navegación en la parte superior, los tamaños de fuentes, el resaltado bonito y gris aquí,
el hecho de que esto llegue hasta el borde o que
esto tenga el mismo margen aquí y acá, o el hecho
de que este botón ya no se vea tan feo como antes, todo eso es CSS.
Y sucede que estamos usando una biblioteca llamada Bootstrap,
la cual es una biblioteca muy popular y que tiene muchas funciones,
como formularios que les ayudarán a diseñar estas cosas.
Y si yo, en esta aplicación, escribo una cadena como Harvard y luego escribo
en una cadena como Yale y hago clic en Score, lo que verán aquí es,
de forma algo compleja, o muy compleja si no están completamente atrapados
por nuestra conferencia de Yale,
¿ven una matriz en la parte superior?
Esto es solo una cuadrícula con filas y columnas.
La fila superior de esta matriz dice H-A-R-V-A-R-D,
así que obviamente es la primera palabra que escribí.
Y en el eje Y, dice Yale, Y-A-L-E, y lo que cada uno de estos números
representan es el costo, paso a paso, de convertir una cadena en otra.
Aunque en sí, es una especie de ejercicio inútil,
pero el número de pasos para convertir una cadena en otra
da una estimación de qué tan similares o diferentes son las cadenas.
Si hay un costo muy bajo para cambiar una cadena a otra,
lo más probable es que sean muy similares.
Si se necesita un paso para convertir una palabra en otra,
lo probable es que sean idénticas, excepto por un carácter.
O si el costo es realmente alto, como seis, entonces se requieren seis pasos
para convertir a Harvard en Yale.
Y eso tiene algo de sentido, porque son palabras realmente diferentes,
excepto por el hecho de que tienen una A en común
que tal vez podamos reutilizar sin tener que cambiarla por completo.
Así que la edición de distancia es una técnica que se resuelve de modo muy lento
y costoso a la manera ingenua, usando esencialmente un par de bucles for,
donde se itera sobre una cadena, se itera sobre la otra cadena
y solo iterativamente, o más bien con un poco de recursión,
se intenta cada cambio posible en la cadena.
Bueno, ¿y qué pasa si borro esto y luego agrego esto?
¿Y qué sucede si agrego esto y elimino esto?
¿Qué pasa si cambio esto y agrego esto y luego borro esto?
Hay tantas permutaciones que se pueden agregar y eliminar,
y caracteres que se pueden editar, que se vuelve un problema demasiado lento,
especialmente cuando las cadenas son más largas que estas.
Y entonces, lo qué harían si eligen
la versión más cómoda de la serie de problemas,
es implementarlo mediante una programación dinámica.
Y esta matriz de aquí solo recuerda,
solo almacena todos los valores temporales que hemos memorizado en el camino,
si recuerdan la conferencia de Benedict,
simplemente trabajen de la parte superior izquierda a la inferior derecha
para obtener su respuesta final.
Y el hecho de que ese número sea relativamente grande, 6,
significa que Harvard no es muy similar a Yale, al menos en términos
de comparación de cadenas.
No me di cuenta de la semántica de eso hasta que dije esa oración.
Mientras tanto... oh, y como nota aparte, por si no se han dado cuenta,
aquí en la parte inferior hay una especie de registro.
Este muestra, una vez que hayan implementado la parte superior,
lo que le tiene que pasar a Harvard para convertirse en Yale.
Tenemos que eliminar una h, borrar esta a, quitar esta r.
Luego tenemos que cambiar una letra a "y", cambiar otra letra a "l"
y una letra más a "e", y voilà, Yale.
Pero observen si hacemos algo más similar, como... digamos...
supongan que usamos a Mario, de la serie uno, y a María la jefe del equipo.
Esta es una cadena mucho más similar porque solo se necesita
un paso para convertir una en la otra
y entonces el registro también es mucho más pequeño.
Y entonces se obtiene una estimación de la similitud,
pero podemos avanzar un paso con el uso de diferentes algoritmos
que pueden funcionar o no también.
Entonces aquí está la versión menos cómoda del mismo problema, por lo cual ahora
nos piden dos archivos y no solo dos cadenas.
Podemos hacer archivos aún más grandes de la siguiente manera,
porque no es tan costoso y es mucho más sencillo
mostrarlos en la pantalla.
Así que descargué o inventé un par de ejemplos por adelantado.
Tengo un archivo llamado hello.c, que se ve así...
es una pequeña retrospectiva de la semana 1.
Y luego tengo otro archivo llamado hey.c,
el cual es idéntico, excepto por una palabra, a hey, world.
Ahora haré lo siguiente.
Voy a subir hello.c y hey.c.
O podría hacer clic aquí y navegar por mi disco duro
como ustedes lo harían en su Mac o PC.
Pero solo voy a arrastrarlos y soltarlos.
Y luego tengo tres opciones de algoritmos.
Porque si pensamos en lo que es un archivo de texto,
realmente no sé muy bien cómo compararlos.
Probablemente pueda decirles si son idénticos.
Puedo usar un bucle while o un bucle for en C,
iterar cada carácter en el archivo y decir True o False,
estos archivos son idénticos.
Pero si hay una pequeña diferencia, como hey y hello, o tal vez algún espacio,
entonces tengo diferentes opciones.
¿Y qué pasa si comparamos estos archivos línea por línea?
¿Creen que la mayoría de las líneas en hello.c y hey.c
serán similares o diferentes?
PÚBLICO: Similares
DAVID: Similares, excepto por esa línea de printf.
Veamos lo que sucede.
Si elijo comparar las líneas de mi algoritmo y hago clic en Comparar,
veo resaltados en amarillo, en la interfaz de usuario, los dos programas restantes
y a la derecha, hello y hey, con todas las líneas idénticas resaltadas.
El hecho de que se vea tanto amarillo significa que son bastante similares.
No le estoy dando un valor en este caso particular.
Pero podría decir que todas las líneas, excepto una, son comunes
y se les atribuye ese tipo de puntaje.
Por otra parte, las frases no necesariamente tienen sentido,
pero si esto fuera un ensayo, o si están familiarizados con sitios como Turnitin
y cosas así, como un ensayo en inglés, podría subir dos ensayos diferentes
y ver cuántas frases tienen en común.
Incluso ver si una frase está arriba y otra está aquí abajo
porque los estudiantes utilizaron las mismas citas o lo que sea,
al menos puedo encontrarlos al dividir el texto
según la puntuación de una frase en inglés, la cual no
existe de la misma manera en código.
Pero, ¿qué pasa con las subcadenas?
La subcadena es un término más sofisticado que solo se refiere
a una porción de una cadena de longitud uno, dos, tres o cuatro.
Y aquí tengo un cuadro de texto donde puedo configurarlo.
Entonces, si quiero buscar subcadenas comunes de longitud 10,
sería una cadena de texto bastante larga que está en ambos
Compare, y de hecho hay una gran cantidad de tramos de 10
porque todos son muy similares.
Pero si lo cambio a uno, para buscar todos los caracteres comunes,
verán que casi todo está en común, ¿excepto por cuál letra faltante?
PÚBLICO: Y.
DAVID: Y... entonces habrá un par de formas diferentes
para implementarlo, de hecho, hay muchas maneras diferentes
en las que se pueden implementar todos estos algoritmos.
Pero el punto clave es que, al usar Python,
van a tener muchas más herramientas a su disposición.
Tendrán diferentes tipos de datos, como listas, conjuntos,
y diccionarios, si quieren utilizarlos.
Y lo que no tendrán que hacer, como podría ocurrir en C,
es analizar estos caracteres individualmente.
Por el contrario, si desean dividir un archivo de acuerdo con sus líneas,
solo llamen a una función para eso.
Si desean capturar todos los espacios en blanco,
solo llamen a una función para eso.
Si quieren tomar una subcadena de cierta longitud,
solo usen la sintaxis correcta de Python para eso.
Y una vez que hayan utilizado esta especie de enfoque de andamiaje
para importar algunos de sus problemas de C a Python,
terminarán por implementar cualquiera de ellos.
Hoy terminaremos un poco más temprano.
Me quedaré un rato para responder preguntas.
Les deseo la mejor de las suertes, y nos vemos a la próxima.