Subtitles section Play video Print subtitles [MUSIC PLAYING] DAVID MALAN: All right, this is CS50, and this is lecture 9. And so we've been diving into bunches of languages recently among them have been HTML, and CSS, and Python most recently. And soon we're going to see JavaScript soon. We're going to see SQL and more. So let's see just a moment if we can kind of wrap our minds around what's going on with these various languages. So HTML, which we looked at a couple of weeks back, is used for what? AUDIENCE: Websites. DAVID MALAN: Websites. OK, but be more specific. What about websites? AUDIENCE: Markup. DAVID MALAN: Markup. OK, be more specific than markup. What does that mean? AUDIENCE: The way they look. DAVID MALAN: The way they look. OK, good, so marking up a website, the structure of the website, and the contents of the website are what you would annotate using HTML-- Hypertext Markup Language. It's not a programming language, so it doesn't have functions, and loops, and conditions, and the kind of logical control that we've used for some time. It really is about presenting information. Make something bold. Make something italics. Put something centered and so forth. CSS, meanwhile, allows you to really take things the final mile and really get the aesthetics just right. And so, in fact, what I just described, boldfacing, and italics, and centering, early on in version 1 say of HTML was actually how you did it. There was no CSS. But these days, the better approach is to factor out those kinds of aesthetics from your HTML and instead put them in this other language, CSS, Cascading Style Sheets. So your HTML now becomes put this text in a column. Put this other text in another column. And structure your data in a certain way. And then stylize it with colors, and fonts, and placement using CSS. Now meanwhile, most recently, we introduced Python. And what was noteworthy about Python? What do you got? Some-- back here? Python-- AUDIENCE: More straightforward syntax. DAVID MALAN: More straightforward syntax, yeah, in some ways, and we'll see some syntax where you take that back, I think. But in general, that is kind of the case, because you don't need parentheses if they're not strictly necessary. You don't need curly braces just because. Instead, things like indentation become more important, which on the one hand is a little annoying, but on the other hand, really does reinforce good habits. So that's probably a good thing. And then at the very end of the last lecture, we did something that was hopefully wonderfully inspiring, which was to implement what in Python? AUDIENCE: Dictionary? DAVID MALAN: The dictionary. And so we've really, we pretty much re-implemented all of problem set 5 speller using like I don't know, 15, 20, 25 lines of code, not to mention I was able to type it out within 30 seconds. And that's not just because I knew what I wanted to type, but really because you have to write so few lines of code. With Python, and soon with JavaScript, and even other languages out there, you just get so much more functionality for free. If you want to know the length of the string, you call a function. If you want to get a linked list, you create a data structure called a List. If you want a hash table, you create a data structure called a Dictionary. You don't implement it yourself. Underneath the hood, someone else out there in the world has implemented all of that functionality for us. But now we're standing on their shoulders. And so today, what we begin to do is to transition to this last portion of the class, where our domain is not just a command line and dot slash something, but web programming, where the ideas are pretty much going to be the same so long as we now understand, as hopefully you do or are beginning to, what HTTP is and how the web and the internet itself work. So recall that we looked a little bit ago at a URL like this. And so if you were to visit https://www.facebook.com and hit Enter in your browser, you're going to send some kind of message in an envelope that might physically in our world look like this. But of course, it's digital instead. And what is inside of that envelope, if you simply do type that URL before trying to get to Facebook? AUDIENCE: An error message that redirects to-- I guess [INAUDIBLE] that one. DAVID MALAN: Yeah, probably no error message here, because that URL did have the HTTPS. And it wouldn't so much be an error message, but like a preference to go to a different location. AUDIENCE: Moved? DAVID MALAN: Sorry? AUDIENCE: Moved. Moved, like permanently moved. DAVID MALAN: Oh moved. Not moved, only if we had gone to a shorter URL. Recall that all of those 301 one redirects were the result of, for instance, leaving off the dub dub dub or leaving off the S. so this is actually the good. This was the end of the story, where everything just worked and we got back a 200 OK. So if I did hit Enter though on my laptop and tried to visit that URL, what did I put, or my laptop put inside of this envelope? AUDIENCE: Request. DAVID MALAN: The request to get an address, so it was like the get verb, like getme, probably slash, because the last thing in this URL is the slash. It probably had a Host header. Recall, we saw host colon and then the domain name of the website again. And there were bunches of other headers, so to speak, that we kind of turned a blind eye to. But in essence, atop the piece of paper, virtually, that's inside of this envelope, or at least these two lines, a reminder as well as to what protocol, sort of what handshake convention, we are trying to use with the server. And now when the server responds with an envelope of its own, how do these headers change? What's inside of Facebook's HTTP headers in its envelope back to me? Kind of spoiled it a moment ago. What? AUDIENCE: The IP address? DAVID MALAN: Somewhere-- let's kind of consider that on the outside of the envelope, though. That's how it gets to me. What's on the inside? What's the status code going to be when I visit Facebook's Home page? AUDIENCE: 200 OK DAVID MALAN: 200 OK-- and so we saw 200 OK only when we actually looked underneath the hood, so to speak, to see what was inside of these envelopes using Chrome's Inspector toolbar, the developer tools, or using cURL, that command line program. Odds are, there are other headers in there, like content type is text slash html. And I think that's the only one we saw. But moving forward, as you make your own web-based applications, you will actually see and Chrome and other tools a whole bunch of different content types. You'll see like image slash ping or image slash jpeg. So indeed, anytime you download a picture of a cat or something from the internet, included in the headers in that envelope are two lines like this. But a cat is not a web page. It's not HTML. So this would be like image slash jpeg, if it's a photograph of a cat. And then below that though, the dot dot dot, is where things started to get interesting in the last half of our lecture on HTTP, because what came below all of the HTTP headers inside of this envelope from Facebook? What's inside of the envelope? AUDIENCE: Nothing? DAVID MALAN: Nothing-- yes, it's technically an answer. But-- AUDIENCE: Isn't it like pieces of the file? DAVID MALAN: Yeah, it's the pieces in the file. I mean, it really is the file itself. So essentially, when you write a letter in the human world, you usually put like the date. And you might put the person's address. And you might put like dear so-and-so. You can kind of think of all of that like metadata, the stuff that's not really the crux of your message to the human, as being the HTTP headers. But then once you start writing your first paragraph and the actual substantive part of your letter, that's going to be down here, so to speak. And that's going to be the HTML inside of this envelope. So if I'm downloading Facebook's Home page via my browser to my computer, and I am seeing Facebook's Home page or my news feed, or if I'm logged in, all of that HTML is actually inside of this envelope. Now technically, it's all zeros and ones at the end of the day. But now that we're not sort of at week zero anymore, we're thinking in terms of language, there's just a whole bunch of HTML. And what did that HTML look like? Well in the simplest case, it might have looked like this. This is a simpler web page certainly than Facebook's own. But this would be an example of the first paragraph, so to speak, of Facebook's Home page coming from server to browser. And so that's the relationship among HTTP and HTML and, in turn, CSS, though there's none pictured here. HTTP is that protocol, that set of conventions, ala the human handshake that ensures that the data is formatted in a certain way and gets to me from server to browser, or from browser to server. Below that is a very specific language called HTML, which is the actual content. And what does my browser do upon receiving this? Well, just like we humans would read the first paragraph of the letter, a browser is going to read this top to bottom, left to right, and do what it says. Hey, browser, here is a web page. Hey, browser, here is the head of the page. Hey, browser, here is the title. Put it in the tab bar. Hey, browser, here's the body. Put it in the big rectangular region of the window. Hey, browser, that's it for the web page. So you can think of these open tags and close tags or start tags and end tags as really being these directives. Do something; stop doing something. And that's literally what the browser is doing underneath the hood. So the last time we introduced Python, which is unrelated fundamentally to all of this. It is just another programming language. So technically we could have started talking about Python in like week 1, right after we looked at Scratch instead of looking at C. But instead, we started sort of with Scratch, the graphical program. Then we kind of went super low level with C, and built, and built, and built on top of it, until now we're kind of at Python, where we can solve all of those same problems with Python. And in fact, one of the challenges of problem set 6 is going to be to rewind a few weeks and re-implement Mario, and Cash or Credit, or Caesar, or Vigenere in Python, so that you effectively have your own solutions handy, or the staff solutions in C. And it'll be really kind of a warm-up exercise and a comforting exercise to just translate something that you know works or should work to a new language and see the mapping from one to another, just like we did with Speller, but more powerfully. We're also going to start to build applications using Python that we've not built before. And so among them, for instance, today will be a handful of examples that actually use Python to generate HTML from a server to me. Because you could write this on your Mac or PC. You could save it. You could upload it to a server in the cloud, so to speak. And people can visit it. But if I visit this page today, or tomorrow, or the next day, it's always going to be the same. It's going to say hello title, hello body every day. Facebook, and Gmail, and any website out there these days is much more dynamic. The content changes based on you or other humans, typically, or even the time of day, if it's a new site. So today we're going to explore, how do you use programming, in Python in particular, to generate dynamic content, ultimately based on data in your database interactions from the user or any number of other things. So how do we go about doing this? Well, let me go ahead and open up the IDE for just a moment and open up an example from today's source code called serve.py. This is an example, a few of whose features might look a little familiar, but not all of them. So let me scroll to the bottom first. This is a program written in Python that implements a web server. So remember, a server-- even though most of us, at least I certainly grew up thinking of it as a physical machine-- it's technically a piece of software running on a physical machine. So just to be clear, what does a web server do? What's its purpose in life? AUDIENCE: Like connects to the internet. DAVID MALAN: Connects-- a little too grand-- its functionality is actually much more narrowly defined, I would say. What's a web server? That's kind of like a router interconnects things. AUDIENCE: Door? DAVID MALAN: What's that? AUDIENCE: Your door to the internet. DAVID MALAN: Door to the-- even too fancy a description-- let's really home in on what it does functionally. AUDIENCE: It listens for requests and then responds to them? DAVID MALAN: Right, so a much less interesting answer, but much more concrete and factual as to what the server does. Exactly, it is a piece of software that just listens for HTTP requests on the internet coming in what? --via wired or wireless connections. As soon as it hears an HTTP request, like get slash, it responds to those requests. So that is what the web server does. So Facebook.com, and Google.com, and all of these companies have web server software running on physical machines that are just constantly listening for those requests. And the photo I showed last time of that old rack at Google's headquarters is an example of a whole bunch of servers that were running the same software, all of which had internet connections that were just listening for HTTP connections, specifically, if we want to get really precise from a few weeks back, on TCP port 80, on a certain IP address. But again, we can kind of abstract away from that. And as you say, it's listening for connections on the internet. So how does this piece of software work? Just to demonstrate how relatively easy it is to write a web server, irrespective of the content it serves up, line 24, if you could translate it into English for me, based only on last week's material, what is line 24 doing? And it's not configure server. More technically, what does line 24 do in Python? AUDIENCE: It's just assigning port the number 8080. DAVID MALAN: To? Oh, yes, OK, to port. So, OK, so what is port exactly? AUDIENCE: Just a variable. DAVID MALAN: Just a variable-- what is its data type? AUDIENCE: It's an int. DAVID MALAN: How do you know that? I don't see int. AUDIENCE: Or the input is given as an int. And Python just dynamically figures is out somehow. AUDIENCE: Exactly, so we-- unlike C, you don't specify the types anymore, but they do exist-- ints, and strings, and floats, and so forth. But honestly, why do we really need to specify int if it's obvious to the human, let alone should be to the computer, that the thing on the right is an int. Just make the thing on the left an int. And this is one of the features you get of Python, and in general, more modern languages. Meanwhile, line 25 is similar in spirit. Give me a variable called server address. But this we didn't talk about too much last time. I mentioned the word only in passing. This is a little funky. We never saw this syntax in C in this context-- parenthesis something comma something close parenthesis. We absolutely saw that syntax when we were calling functions and so forth, or when we had if conditions or the like, or loops, and while loops, and for loops. But we've never seen, to my recollection, a pair of parentheses open and close that have nothing next to them other than, in this case, the equal sign. But what does this kind of look like maybe from other classes you've taken? [INTERPOSING VOICES] DAVID MALAN: Yeah, sorry, say again. You want to go with ordered pair? Yeah, so if you think to any math class or graphing class, anytime you dealt with x and y, it's kind of common in certain worlds to have pairs of numbers, or triples of numbers, or quads of numbers. And so Python actually supports that idea. If you have two related values that you want to kind of cluster together in your mind, you can simply do open parenthesis one value comma the other. And the general term for this is a tuple-- T-U-P-L-E. So it's kind of like a double or a triple. But a tuple is any number of things, one or more things in parentheses. So why are these related? Well, in TCP/IP, the protocol spoken on the internet, the first thing is the IP address. The second thing is the TCP port. So we have both IP and TCP, ergo, TCP/IP. And so we're just storing both of those variables in this-- both of those values in this address called server address. Meanwhile, this kind of code we wouldn't really be familiar with yet. But this is declaring another variable on the left called httpd, d meaning daemon, which is a synonym for server, so HTTP server, aka web server. Give me some kind of HTTP server object. This is like a special struct, like a student struct. But this struct actually implements a web server, passing in the server address and whatever this thing here is. And let me wave my hand at that for just a moment. But then the last line of code here on 29, says inside of that variable is a function, otherwise known as a method, called serve forever that literally does that. When you run this program, and it gets to line 29, the program never, ever ends. It doesn't exit. It just keeps staying there. Never again do you see a prompt. It literally is serving forever by listening for HTTP requests. Now let me just show you what this does now. Let me go ahead in my terminal window. And how do I run a Python program? AUDIENCE: Python [INAUDIBLE]. DAVID MALAN: Exactly-- so it's this. Unlike C, you literally say Python, which is not only the name of the language but it's the name of the program, the interpreter that can understand this file. And if I go ahead and run that, I can't open file serve.py. Up No such file in directory. So technically, I didn't mean to do that. But teachable moment, what's going wrong? AUDIENCE: You're not in the right folder. DAVID MALAN: Yeah, I'm not in the right folder. So before I mentioned it's in Today's Source Code, Source 9, so let me just cd into the right directory, and now do it again. And now nothing seems to be happening forever. And so it seems like the server is actually running. So I'm actually going to go ahead and do this. Let me go ahead and go up to Web Server under the Menu here. I just have a little warning from Cloud9. I'm going go ahead and click App. And now notice what's happening. My new URL is going to look different than your URL might. But in my case here, I just went to ide50 dash malan dash Harvard dot edu-- because that's my username on Cloud9-- dot cs50 dot io colon 8080. Because this program, this server, it is listening for TCP connections on port 8080, not the default, but 1880. And as soon as it hears a connection, it literally spits out apparently "hello, world." So where is that coming from? Well, if I zoom out and go back to my program here and look at the top, we'll see what this thing actually is. And we won't have to get into the particulars of why this works. But this is how a web server functions at the end of the day. When a web server receives an envelope from a user's browser, like this one here, it looks inside and it realizes, oh, this is a GET request. Because literally the verb GET is inside of the envelope. So here is a function called doget, just because. And then what do we do? This line here, 13, is telling the server to send 200, OK. It's telling it to send this header, content type text HTML. And it's telling it to write the following string, "hello, world," in what's called Unicode or UTF-8 out on the internet. And that's it. So this is a very specific example. This web server is not all that useful, because no matter who or how often you connect to this web server on port 8080 of your domain name, what is it going to show? AUDIENCE: Hello, world. DAVID MALAN: Hello, world-- so not interesting-- you might as well have just save the whole darn thing as like index.html and be done with it, and not use Python at all. But what if, what if instead of doing this, you have code in your web server that says something like this-- figure out what file was requested from HTTP headers, because remember it might be slash. It might be slash zuck, for Mark Zuckerberg's Home page, or some other request. Check if that file exists. If so, send it back to browser. In other words, suppose we remove this hard-coded stuff about "hello, world," and just start to write some code, or at least for now pseudocode, that makes the web server dynamic. Upon getting a request on port 8080, it checks what the request is for, per this first line 12. If it finds it on the hard drive locally, it's going to send it back to the user. And so ultimately, that is what a web server does. I hard-coded a simple one to just forever say, "hello, world." but that's what a web server does. And moving forward, we are not going to implement the web server itself in Python. We're instead going to use a tool, a pretty popular one called Flask. So there's bunches and bunches of different web server software out there in the world. Flask happens to be one of them. It's technically called a micro framework, because it's like a small amount of code that other people wrote just to make it easier to serve up websites. And so rather than write the web server ourselves, we're going to use a web server that someone else wrote, Flask, and actually start writing our own applications on the web with it. So now what does this mean? Let me go ahead and do the following back here in the IDE. Let me ahead and kill this server here, close that file here, and let me go ahead and let's say do this. I'm going to go ahead and create a new file. And if I Google this, Python-- Python Flask, the only way I would know what I'm about to do is if I had looked up the documentation for Flask and I followed the instructions, literally read the documentation. And at one point, I kind of read through the user guide here. I looked at some examples. I played around with my IDE, saved some things and tried them out. And thus was born this kind of example. So if you want to use Flask, it turns out you essentially have to do this. You first define an application. And you say, Flask name. Why? Why? It's not all that useful for now for us to dive into the weeds here. But this just says, hey, Flask, give me a web app. I don't care how it's implemented. You take care of that, so I don't have to write code like the previous serve.py file. And then after that, I need to tell flask what to do and when. And so the way you do this in a lot of modern web software is you define what are called routes. You say to Flask, or your web server more generally, hey, server, if you get a request for slash, do this. If you get a request for slash zuck, do this. If you get a slash for slash login, do this other thing. And so the pseudocode in a server might be something like this-- if request is for slash, then send back home page. Else if request is for slash zuck, which again was just one of the sample URLs two times ago, then send Mark's Home page. Else if the request is for login, then prompt user to log in, and so forth. So this is a web-based application, albeit in pseudocode. It has nothing to do with TCP/IP per se. That is going to be the job of the web server to deal with. I don't want to even know there are envelopes virtually on the internet. I just want to start writing code in my logic. Just like in C, I want to write my main function and my helper functions. Here is what my web application is going to do. So how do you do this? Well, suppose that you want to do the following. Let me go into-- save this as application.py, which is just a convention, application.py. And let me create momentarily another file called index.html. So I need a really quick web page here. And this will come with practice, but let me go ahead and just quickly whip up a little web page-- head here, title, hello, title, and then down here body, and hello body. OK, so super simple web page, same as we did a couple of weeks back. That's all. It's in a file called index.html. How do I now connect these two files? If I have a program written in Python, or technically pseudocode, and one of the things I want this program to do is this pseudocode here-- if request is for slash, then send back the Home page. We've branch into, I think, briefly a couple times ago that the default Home page for a website is often, just by human convention, called index.html. So this pseudocode now is kind of this. If the request is for slash, specifically send back index.html. But instead, if the request is for slash zuck, then send Mark's Home page. So what might that look like? Let me actually go and copy this, make a new file. And just for kicks, I'm going to save it as a zuck.html and then hello, world, I am Mark. So suppose this is Mark's Profile page. It's super simple. It's obviously not what Facebook looks like. But it is a valid HTML page. So now I have two files and one web application. So technically, I should really send back zuck.html. And if I continue this sort of imaginary example, then prompt user to log in, that probably means then show user login.html, which is yet another page that has like a form on it. It's just like the form we made for our simple Google example. So in short, all a web application is, it's a program written in some language that respond to requests based on some logic. And this is the logic that we did not have in HTML alone. This is why we need Python, or Java, or Ruby, or PHP, or any number of other languages can do the same thing. C can also do this, but it would be an awful, awful nightmare to implement this in C. Because just think of how annoying it is to like compare substrings or extract something like the HTTP headers from a longer-- it's just a lot of work. A fun fact-- two years ago we had problem set, where we did exactly that, but now it's a little different. So here's how we transition to making this an actual web app. Let me go ahead and translate this to actual code. Let me delete this. And it turns out, in Flask, if you want to find a route, so to speak, for slash, you do this. My app shall have a route for slash. And when that route is visited by a user, by making a request in one of these envelopes, go ahead and call a function in Python called index-- though I could call it anything I want-- that simply returns the result of rendering a template called index.html. And we'll see why that is called a template in just a bit. But know that Flask gives me this special function called Render Template that will spit out a file. But it does more than that, which is why it has a fancier name. The file I want it to spit out is index.html. Meanwhile, if I want to support Mark Zuckerberg's Home page, I'm going to do what then, if you just kind of infer? AUDIENCE: Def zuck. DAVID MALAN: Def, OK, zuck. AUDIENCE: And then return his-- the rendered template. DAVID MALAN: Yeah, so return render template of zuck.html. And one more thing-- AUDIENCE: [INAUDIBLE] backslash zuck. DAVID MALAN: Backslash-- backslash where? No need for backslash or escape characters, but there's one-- one of these things is not like the other at the moment. AUDIENCE: [INAUDIBLE]. DAVID MALAN: Yeah, so we need to define this function as being, quite simply, the function that Flask should call when the user visits slash zuck. Now again, it seems a little stupid that we've written zuck in three places, index in two places. That's just kind of the way it is in Flask. Like this could just be Foo. This could be bar. The function names don't matter. But you might as well keep yourself sane and use the same names as relate to the routes themselves. So now we've replaced two of my conditions in my pseudocode with actual code. And if we take this one step further, to do the Login screen. I bet I just need to do something like app dot route slash login and then maybe something like def login return render template login dot html, which I didn't bother making, but I certainly could with some copy/paste and some edits. So now we have a web application that supports three routes. When it gets a request in an envelope from someone on the internet, it will look inside that envelope and check, what are you requesting? Well, if you're requesting slash, I'm going to this function. If you're requesting slash zuck, I'm going to call this function. Or slash login, I'm going to call that function. And that's it. The web app is not complete because notice, we seem to have no code that actually checks usernames, and passwords, and sort of fancy features that you would hope actually exist. But that's more code to come. For now, all we're doing is spitting out, conditionally, different files. So how do I now make this work? Well turns out, I need to make a directory called templates, so make dir templates-- or I could do it with the file browser, with the GUI-- Enter. I'm going to move both index.html in there with mv. And I'm going to move mark into there with mv. And now I need to do one other thing. In my program up here, I've deliberately-- whoops, oh, let's close the tabs, because I moved the files. That's OK. It's just because I moved the files into a subdirectory. So let me re-open those. So I left the room appear deliberately for a couple of reasons. One, Flask-- rather Python-- has no idea what Flask is. When Python was invented years ago, there was no such thing as Flask. That was written more recently by a community of people, who have been making better web server software since. So if I want to use a package that someone else wrote, aka a library, recall that I can do something like this from Flask import FLASK, which is a little stupid looking. But this just means somewhere on the IDE, we have pre-installed a package called Flask. Inside of there is a feature called FLASK-- capital letters-- which happens to be what I'm using here. And for today's purposes, you can think of this as a structure. It's not a student struct, which is the go to example thus far. But it's a special web app structure that I'm somehow using. But you can just take on faith for now that that's what that does. But render template is also not a function that I implemented. And indeed, nowhere in the file is it actually defined or implemented. Turns out that comes with Flask, so I can also import a second function. Just like I imported get int or get string or get float, I can import this function called render template. And that's all I actually need here. So now I'm going to go ahead, and if I didn't make any typos, I'm going to go ahead and now do this-- Flask run. So Flask, in addition to being like a framework, a way of writing web applications, it is also a little program called Flask that takes some command line arguments, one of which is Run, which just says run the web app in my current directory. And that file, by convention, has to be called application.py. So when I hit Enter, I see a whole bunch of debugging output. Debugger is active. We'll see what that means some time. And now here is the URL. It's really ugly looking, because I have a pretty long user name here on Cloud9, but notice it's the port 8080 that's important. Let me go ahead and open that. And now I see "hello, body." But up here-- and remember that the slash is inferred. Chrome is just being used friendly and hiding it. If I change this to zuck-- Enter-- "I am Mark." And if I change it to login, what's going to happen? AUDIENCE: Nothing, because it-- DAVID MALAN: Not found-- so something deliberately at this time it's going to go wrong because I didn't-- whoa-- OK, so I didn't bother making that template yet. And so you'll soon be familiar, not with segfaults any more, but probably with something called an exception. And we'll see more of these over time. But Python, unlike C, supports something called exceptions, which is a type of error that can happen. And essentially, one of the features, if a little cryptic, of Flask, is that anytime something really goes wrong like a segfault, but in this case called an exception, you'll see a somewhat pretty web page that I did not write. I didn't make any of this HTML. Flask generates that for me just to show me all of the darn errors that somehow ensued, so I can try to wrap my mind around what's going on. Fortunately, the most important one is usually at the top. And it kind of says what I need to know-- "template not found," even though I'm not sure what this means yet, "login.html." So I can infer from that what's actually gone wrong. So that might be my very first example. And the key takeaways here are that I have written Python code with logic to decide, if the request comes in for this, do this. If the request comes in for some other thing, do this, else do this other thing, so kind of a three-way fork in the road, even though the results are just some text files. OK, any questions or confusions at this point? OK, so now that we have a programming language, we can do much more powerful things, kind of sort of like I tried to do back in my day when I first learned how to write web applications. And one of the first things I did-- let me go ahead and close all of this up. One of the first things I did was to make a website for the Freshmen Intramural Sports Program. And let me go ahead in here to Frosh IM0, open up some templates, and we're about to see is this. Here's a little web application that I made in advance. It's in a folder called Frosh IM0, which has a template subdirectory, inside of which are a whole bunch of web pages. And you can probably infer what they are used for. Index is probably the default. Success has something to do with things going right. Failure is probably the opposite. And we don't know yet what layout.html is, and an application.py. That's it. So let's actually see what index.html looks like. And that's the following. In index.html, it looks like we have a whole bunch of HTML. And I've cut off deliberately the first couple of lines. But what's an H1 tag? AUDIENCE: Header. DAVID MALAN: Header, so it's like a big bold piece of text. So "Register for Frosh IMs" looks like the main text atop this page. Form, action, register, method, post, we saw this briefly when we re-implemented Google a few weeks ago. So here, "action" means that when you click Submit, this is going to be submitted to the current domain slash register. And it's going to use a method called Post. So we didn't talk about this in detail last time, but it turns out there's at least two verbs to know in the web world-- Get, which puts everything you type in into the URL, and Post, which, in short, does not. It hides it sort of deeper in the envelope. So based only on that definition, whereby recall that Google uses Get. If I go to Google dot com slash search question mark q equals cats-- and hopefully they're doing better today than last time. OK, so notice the URL here-- I have to stop pulling up Daily News. So notice the URL here has my search query. Why might it not always be a good thing to put into the URL what the user typed in? AUDIENCE: Cause it's like a password. DAVID MALAN: Yeah, if it's your password, you probably don't want it showing up in the URL. Because maybe someone nosey walks by and can just read your password off the URL. But more compellingly, a lot of browsers have autocomplete these days, and they remember your history. So it would be a little lame if your little sibling, for instance, could just click the little arrow at the end of this window and see every password you've typed into websites. You could imagine this not being good for uploading content like photos. Like, how do you put a photo in a URL? That doesn't feel like it would really work, though technically you can encode it as text. Credit card information or anything else, I mean anything resembling something private or secure to you, probably don't want cluttering the URL bar because it's going to get saved somehow. When you use incognito mode though, for instance, that kind of stuff is thrown away. But this is just bad practice to force your users to use a mode like that. So Post does not put it in there. And so if Google used Post, which they don't for their search page instead, we would appear to be at this URL, just slash search, no question mark, no q, and no cats, but the query can still be passed in. It's just kind of, again, deeper inside of the envelope. So long story short, I chose to do exactly that just because with Frosh IMs, because we don't really need to be storing all of the freshmen's names, and email addresses, and dorms in people's URL bars unnecessarily. So input name equals name, type equals text. This is going to give me a text box, just like q for Google, for someone to type in their name. Select-- it's kind of a weird name, but what does a select element give you visually on a screen, if you recall? Yeah? AUDIENCE: It's like a dropdown bar. DAVID MALAN: Yeah, it's a dropdown menu. So all of the items in that menu are going to be drawn from these Harvard freshman dorms here. And then down at the bottom of this file, if I keep scrolling, notice there's one other input whose type is Submit. And what does a input whose type is Submit look like on the screen, if you recall? AUDIENCE: It's a button. DAVID MALAN: Yeah, it's just a button. That's it. And you can style it to look differently, but it's just a button by default. So long story short, this web application gives me a form via which frosh can register for intramural sports. And I can see this as follows-- if I go into Frosh IM0, and I simply do Flask run, I'm going to see my same URL as before, but now a different application is running on the same port. Here's what it looks like. It's super simple, super ugly, but it does, indeed, have a text box. It's got a dropdown. And it's got a Register button. And now with the world suddenly got more interesting, because now I have not just static content, like "hello, world" or "I am Mark." I actually have something interactive for the user to do. And if he or she fills out this form now, clicks Submit, two or three weeks ago, we just punted completely, and we let Google handle the user submission. But now we have Python in a programming language that can receive, inside of the same envelope, the user's query for cats or the user's name and dorm. And we can actually do something with it. So this program doesn't do all that much with it yet. If I go in here and zoom in, and I register David from Matthews and click Register, notice what happens. I do end up, as promised, at slash register. And I'm told "You are registered," well, not really. And that's because this is version 0. It actually doesn't do all that much. What does it do? Well, let's go back and try to be less cooperative. So I just reloaded the page. It's still asking for my name and dorm. You don't need to know that information. I want to keep it private. I just want to anonymously register for a sport, whatever that would mean. Register-- OK, I caught it. Notice that the URL is still slash register. But I'm being yelled at for not providing my name and dorm. All right, so fine, I'll give you my name. But I don't want you to know where I live, so I'm just going to say David-- Register. And it's still catching that somehow. So only when I actually give it a dorm and a name, like David from Matthews, and click Register, does it actually pretend to register me. So what does the logic look like? In just English pseudocode, even if you've never written Python, what kind of pseudocode would be in application.py for this application? AUDIENCE: If there is no text, provide error message. DAVID MALAN: Perfect, if there is no text provided, provide this error message instead. And so let's take a look at how that's implemented. In Frosh IM0, in addition to my template, I again had this application.py. And let's see what's new and what's different. So first, this is mostly the same as before. I just added one other thing in here, Request, for reasons we'll see in a moment. Here is the line of code that says, hey, Python, give me a web application called app. Hey, Python, when the user visits slash, render the template index.html. That's how I got the form. But this is the interesting part. Let me zoom out slightly. These lines of code are a little more involved, but let's do the one at a time. This first line, nine, is saying, hey, Python-- or specifically Flask-- when the user visits slash register using the post method, what do I want to call? Just to be clear, what function? AUDIENCE: Register? DAVID MALAN: Register-- so again, the only relationship here, even though the syntax looks a little cryptic, is this says, hey, server, when the user visits slash register, call the function immediately below it called Register. And then what does that function do? Well, here is the logic that you proposed verbally a moment ago. If not request dot form dot get or not request dot form dot get dorm, name and dorm, then return failure.html, else implicitly return success.html. So the only part that's a little new and different here is 11, line 11. Because in C, you would have to use the exclamation points. You would have to use vertical bars for Or So some of that syntax is a little different. But this works as follows-- there exists a function called Get that is inside a special variable called Form that is inside a special variable called Request that I have access to, because I imported it up here. And that function, Get, checks inside of the virtual envelope for a field called Name that would have been populated in the envelope if a user typed his or her name. And if it exists, it returns it, quote-unquote, "David," quote-unquote, "Maria," or whoever it is that's registering, but if not, inverts it. So if not a name, or if not a dorm, go ahead and spit out failure.html. So what does failure.html look like? Well, failure.html just has this hard-coded message, "You must provide your name and dorm." And now at the risk of introducing one too many languages at a time here, there is another one in here. These funky curly braces and percent signs are what's called a templating language. But before we explain what that is, notice at the top of this file is mention of another file, layout.html. That We've not seen this before. In the past, we've just had full and complete index.html files or zuck.html files. But what was true a moment ago about index.html and zuck.html from our last example? Let me go ahead and quickly open those again. Index.html, recall looked like this. And zuck.html looked like that. What do you notice in layman's terms about the two? AUDIENCE: [INAUDIBLE] is mostly the same. DAVID MALAN: Yeah, they're almost identical, right? They seem to differ only in their titles, obviously, and in the body's content. But all the other structure is identical. And to be fair, there's not that much in red there. There's not too many tags. But I mean, I literally, in front of you, copied and pasted this. And generally, that is already a step in the wrong direction. And so there's an opportunity here. There's a problem to be solved. And we've done this in the past, right? In C, if you were to just blindly copy and paste code you need in multiple places, that's kind of dumb. It's kind of messy. It's hard to maintain. Rather, you should probably be defining it as a function that you call in multiple places. Now this is not a programming language, so there's no comparable notion of a function. But because it's a markup language that just has hard-coded values, you can think of this as kind of being a template or a mold, like put something here, and then maybe here, put something else here. So again, if you think of the physical world as having templates, or again, like a mold into which you pour specific values, this is kind of what we're talking about. And that is what layout.html is in this Frosh IMs example. I've not opened it until now, but here is, somewhat cryptically, an example of layout.html. And notice, it's got the doc type. It's got HTML head, title, some other stuff up there body. But then it has this placeholder. And I'll admit it, the syntax is sort of annoyingly cryptic, but this is just saying put something here. And that's all. What are you putting there? Well, if I go back to failure.html, notice that it works as follows. Failure.html conceptually extends this template. It borrows that mold, called layout.html. And then notice the same keywords here, block body and block. This just means plug this into that file. And this allowed me to break my habit quickly of just copying and pasting everything, even though the format of these files is almost identical. So if I go back now to application.py, notice that this program does spit out either index.html or failure.html, or success.html. So it would have been pretty lame to copy and paste my code three times. That's why I took the time to create a fourth file, layout.html, just to factor out everything that's common. And the upside of this, too, means that all of these pages structurally look the same. And if I had like a fancy logo on my website and a nice brand to the web site, all of my pages would look the same except for a message that changes in the middle, say, of the page. And so this, then, is Frosh IM0. Any questions on how this now looks? All right, so we have a couple of other opportunities here. I would propose that it would be kind of interesting to actually remember that the user has registered, instead of just pretending by spitting out a hard-coded value, like "You are registered." Well, not really, because I'm not doing anything with their name or dorm. So maybe we could start storing that in memory and see who is registered for the site. It would be even cooler if, like in my day way back when I implemented the actual Frosh IMs website, you could email someone when he or she registers to confirm that they're registered. Or better still, why don't we actually save it to a mini database, like a CSV file, that I, like the person running Frosh IMs, can actually open in Excel, or Numbers, or Google Spreadsheets, or the like. So before we to get to that, let's take our five-minute break here. And we'll come back and solve exactly those problems. So we are back. And so I thought today would be opportune, since you might have been wondering who Stelios is who has been our example in quite a few of our memory examples. But visiting from Yale University today, one of our head TAs there, Stelios. STELIOS: Hi, everyone. AUDIENCE: We love you! [APPLAUSE] STELIOS: Yale is on break, so I said, why not come by? Yeah, it's glad to see you. I've been in here before many times. It's a beautiful space. And, yeah, come by and hi after lecture. DAVID MALAN: So glad to have you. Thank you, Stelios. So, it was brought to my attention, since I wasn't focusing so much on my logs in the terminal window, which record all of the HTTP requests that you get during a server running. And this is a screenshot of my terminal window from just a little bit ago. And you'll recall that I visited slash, and then I tried to register. But in between there, someone in the audience, apparently, or on the internet, tried to visit slash was up, using Get in their browser. I scrolled past a few other inputs from the internet. But the more shareable ones were these here-- bro slash David and slash nice. So that was the last one before I killed the actual server. And this is because, even though I'm listening on a nonstandard port, 8080, that domain name, I did share my workspace publicly so that anyone could access it while the server is running. And if you happened to be here physically or tuning into a live stream, it's obvious that I'm advertising now publicly that port 8080 is where we've been spending our time. But if we turn back now to Flask and maybe minimize our logs moving forward, let's consider how we can actually now remember that users are logged in. So in fact, let me go ahead and demonstrate among today's examples, Frosh IMs1, by running Flask run. And then I'm going to go to the same URL as before up here. And we'll see this time, that if I go ahead and register as David from Matthews-- Register, notice now that instead of just going to slash register, I changed things a little bit. And I'm going to slash registrants, because there I seem to have some HTML that generates a bulleted list of whoever has registered. And so now let me go ahead here and go back, perhaps, and register let's say Maria from Apley Court-- Register. And now we have two. Moreover, if I just reload the page, notice that this information persists. So how is this actually working? Well, let's go ahead and take a look inside of application.py for Frosh IMs1 dot-- for Frosh IMs1. So what do we have inside here? So as before, I'm configuring my app with a line like this, like, hey, Flask, give me an app. And then this, I claim, is my registrants. So this is just a comment in Python, the hashtag registrants. Students equals open bracket close bracket represents what, though? AUDIENCE: List. DAVID MALAN: A list, yeah, it's an empty list. It's like an empty array. But unlike in C, where arrays can't grow or shrink, in Python lists, which are similar in spirit to an array, can actually grow and shrink dynamically. So if you want an empty one, you literally just say, give me an empty one. And then we'll figure out the ultimate length later. And so what's compelling about this on line 7, is that I have a variable now called Students, that's initialized to an empty list. But it's now in the web application's memory. Because recall that when we run Flask, I don't immediately get back to my prompt. The program doesn't just run and then stop. It just keeps listening, and listening, listening, waiting for more of these envelopes to come in. As such, as these various functions get called-- index, or registrants, as we'll see, or others-- they all have access to this global variable, in this example, Students. And so any of them can just put more, and more, and more data inside of Students. And so here, if I go ahead and do this-- let me go ahead and show that in the user visits slash, we just return index.html. Otherwise, if they visit slash register, notice that I've actually got some interesting logic going on this time. So if the user visits slash register via Post-- and the only way thus far we've seen that this could happen is if the user does what? How do you do something via Post? AUDIENCE: You submit. DAVID MALAN: You submit a form. So Get, we humans can simulate really easily. If you just go to a URL, by typing it into your browser, you are by default using Get. You can't do the same nearly as easily for Post. You only have access to the URL bar. But if you have a web form, like the one in index.html with the Dorm dropdown and the Name textbox, you can submit via Post, which is how this route can apply just to that particular route. So here on line 21, I'm saying, hey, give me a variable called Name, and put in it whatever the user typed into the Name field. Give me the same for the Dorm. And so we notice, even if it was a big dropdown of items, the user is only selecting one of those. And so we're getting back just this one value. And then here is a little sort of Pythonic-type logic. If not Name or not Dorm, which is kind of nice. It's a little terse, and it would have looked strange a few weeks ago, but now it looks better, perhaps, than it would have in week one in C. Then go ahead and return failure.html. If we're missing the name or the dorm. Meanwhile, if that's not the case, and we've not returned a failure, go to do this, students dot append and then this F-string. So dot append, if you don't recall-- and you might not recall, because I don't remember if we showed you-- is a method or function built into a list that allows you to literally append a value to a list called Students. So this is how, in Python, you grow an array. You just append to it and the program will figure out the length of this list. This F-string just means here comes a formatted string, similar in spirit to print F, but the syntax is a little different. And the string I'm forming here is so-and-so from such-and-such, so Name from Dorm. And the curly braces inside of a format string or an F-string means that we should plug those variables into that F-string. And then lastly, this is a new feature. You can return not just render template, you can literally return redirect and the path to which you want to redirect the user. And take a guess. If you call redirect slash registrants, what does Flask, because Flask gave us this redirect function, put inside the envelope for us? AUDIENCE: A new address. DAVID MALAN: A new address-- and what kind of status code? AUDIENCE: 301. DAVID MALAN: Like a 301-- we saw that a couple of times ago. 301 means redirect the user. So this function handles all of that for us. We don't have to know or worry about how those status codes are actually generated. Meanwhile, slash registrants is super simple, but it does have one nice new feature. So slash register, to which the form submit, ultimately does all this stuff and then redirects the user to slash registrants, just because. And it's kind of better designed if this route is only used for saving information, and this route is only used for seeing information, because this way you can visit it via Get as well. Notice that I'm returning registrants.html. But I'm doing a little something different this time. What is different about line 16, vis-a-vis all of our other render template calls before? AUDIENCE: Students equals. DAVID MALAN: Yeah, students equal students, which is a little strange. But we know that one of those values is referring to this list here. And so this is an example of Python supporting named parameters. It turns out that if you want to pass data into a template, you can put a comma and then the names of the values you want to pass in. Index didn't need this. Failure didn't need this. Success didn't need this, because it's all hard-coded. But Registrants does. Based on what we saw, it's going to generate a bulleted list of like David from Matthews and Maria from Apley Court. So we kind of need to know who those students are. So, OK, registrants.html comma, students shall be the named parameter. And the value of it shall be the list up here. So the right-hand side is a variable, or a value that must exist in the current program. And the left-hand side is a variable that's going to be inside of, we'll see, registrants.html. So let's open registrants.html, because the other templates, honestly, aren't that interesting. Index.html is just like the web form with the dorms and the name field. Failure just says, sorry, you must provide name and dorm. Layout is just the similar web structure as before. So the only new file here, besides the changes to application.py, are in registrants.html. This file, as before, extends a layout. So that's the mold that it's using. And it's going to fill in the following block for the body. So again, this is just specific to the templating technique, just to clean up the code. But the real interesting stuff is here. This is kind of sort of HTML, but kind of sort of not. So what does this look like? AUDIENCE: Python code. DAVID MALAN: Yeah, it kind of looks like Python code. And it's technically not. And I realize this is this awkward part in the semester, maybe like most of the semester, where we introduce all these darned things at once. But this is a language called Jinja-- J-I-N-J-A-- that is a templating language. And you'll see that word in documentation and so forth. It's a very lightweight language for just displaying information. It gives you some loops. It gives you some conditions. And it pretty much is Python code. You can think of it that way, but it's not necessarily identical. So for now, you'll see by example what we can do with it. So here, we have a Jinja template that says, "For student in students." This is very Python-like. So "For student in students" means iterate over students, and call each student along the way "student." So with this, I needed to call students, because it's passed into my form. This could be foo, or bar, or S, or whatever. It's just a loop. And then you can perhaps guess what this line does, even though it's a little cryptic. On line 7, I have some kind of familiar HTML, familiar only insofar as for a few seconds a couple of weeks ago, we showed you a bulleted list in HTML, which had a bunch of Li-- list items. But take a guess. What is line 7 probably doing, if you had to guess, based on what the output of this program was? AUDIENCE: Print [INAUDIBLE]. DAVID MALAN: Printing what? AUDIENCE: Printing the students. DAVID MALAN: The individual students-- so remember that the Students list is just a list of strings, so-and-so from such-and-such, so-and-so from such-and-such a place. So, if we induce this kind of loop, iterating over that variable. And on each iteration, we spit out a new link list item, a new list item, like in other words, a new bullet, a new bullet, a new bullet, each time printing out just the name of that value, we're going to get a bulleted list of students. And sure enough, the HTML might not be pretty because it's being generated this time by a human. But this is the HTML. If I view Chrome Source for that page, notice that I've got all this stuff from my layout. Down here, meanwhile, I've got ul and ul, which I did hard-code into that file. But these are not hard-coded anywhere. They were dynamically generated. And this is now really the first evidence of, not just the logic within our Python-based web application, but also the ability to generate content back to the user. And if I kept running the server and kept having people submit, and register, and register, that list would just get longer, and longer, and longer. And the proctor or whoever is actually managing the intramural sports can actually look at that list by going to slash registrants and know whom to contact, at least if we asked for more personal information like emails and the like. So any questions then on this example? All right, so it's in example 2, where now we recreate the website that pretty much I implemented back in 1997 or 1998, albeit in a different language, that actually allowed freshmen to register for intramurals. And we can do that as follows. If I go into Frosh IMs2, and I do Flask run-- I'm going to now reload that app. And now I'm asking for one other thing. So I made the form a little bigger by asking for an email address. Because this time, I'm actually going to try sending an email. Let me go back over here to the file. And let me minimize this to make room for Frosh IMs2 application.py, which does the following. So I have some mention of password here, but more on that in just a bit. And notice that up here I have a new import, not to mention OS. Notice up here-- let's see. Notice up here, we have import smtplib, so SMTP, Simple Mail Transfer Protocol, which happens to do with email. And that's because this example works as follows. In slash, we just return that template, index.html. If instead you do register, notice what actually happens this time. And I want to move this up here. There we go. So now we have this file here-- this method here-- that operates as follows. If the user tries to register via Post, call this function. Get their name. Get their email. Get their dorm, and then just a little bit of a sanity check that's not complete now, because I'm just asking, like before, if not name or not dorm. But how do I also make sure that this user has given me their email address? AUDIENCE: [INAUDIBLE]. DAVID MALAN: Yeah, so if not name, or not email, or not dorm-- now I've improved upon this example versus the last by also checking for their email address. And if they don't provide one of those, we say failure. Otherwise, what is this line 23 do? AUDIENCE: Sends its message? DAVID MALAN: It sets a message, a variable called Message, equal to quote-unquote, "You are registered." The next line here is a little cryptic, and you'd only know this from reading the documentation, like I did when writing this example. On the left-hand side I have a variable called Server. This time it's not a web server, it's an email server, to which I want to connect. Specifically, I want to use this library, called smtplib. It's SMTP functionality, Simple Mail Transfer Protocol, to connect to an address that you might not have explicitly seen before, but you can probably guess whose server I'm connecting to on TCP port 587. Long story short, even though most of us, if you use Gmail, just go to Gmail.com, and you start using it, and it appears to be a port 80. Underneath the hood, anytime you compose a message and click Send or send an archive, what is happening is code like this at Google. They're connecting to their own outgoing mail server, called an SMTP server, which happens to be this address. They're connecting to it using TCP port 587, because it's not a web page. It's mail, so it has its own unique number that humans decided on years ago. This line here, 25, start tls, this turns on encryption so that this way, theoretically, no one between you and Google can see the email that you're sending out to their server. And then I hard-coded a few values, here which wouldn't be best practice in general, but this is just for me to register some first years for Frosh IMs. So what happens next? On line 26, this is the line. According to this library's documentation, via which I can log in as username jharvard@cs50.net, passing in his password. So recall a couple of times ago, I think I mentioned that there are these environment variables, when we talked about programs memory space. Environment variables are like these global values that aren't in your code but you do have access to. So this just says get from the environment, from somewhere in the IDE, JHarvard's password. So I don't have to hard-code it and broadcast it on the internet. Meanwhile, line 27 does kind of what the function says. This says, using this server, Gmail, send mail from jharvard@cs50.net to this email address with this message. And this message, as you've noted, is just, "You are registered." And where does this email variable come from, just to be clear? To whom is this email going? AUDIENCE: To the user. AUDIENCE: The student. DAVID MALAN: The student who registered via the form, because we got their name, email, and dorm. Assuming he or she typed in a legitimate email address, it's being passed to the second argument to send mail, and then it's being sent. And then lastly, render template success.html, and voila. So now you are about to experience either one of the cooler demos we've done in class or one of the more embarrassing failures. If you would like to play along at home, go to tinyurl.com/fridaycs50. That's a lot easier to remember. Tinyurl.com/fridaycs50-- Enter, that should redirect you via our old friend HTTP 301, should put you at this form. And then I will play along at home, too. David from Malan, actually, I'm going to tell it my address is John Harvard's. He will be from, let's say, Pennypacker-- Register, and registered really, which hopefully you shall soon see, too. And meanwhile, I get a security alert in my Google accounts, because everyone's using it. But that's OK. I am registered at JHarvard. And, oh, my goodness, all of these examples, OK, and the errors that we'll soon see-- we'll soon explain-- so what did I just get? If you, like me, check your mail in some number of seconds from now, you should see an email from jharvard@cs50.net with the message, "You are registered" that was sent directly to me, or hopefully to you. Now, at least two of you will not get this message, because according to my bounced mail, three of you have mistyped your email addresses into the example. And so they're bouncing back to me. So if you don't get it, simply try again. So what actually happened here? So I actually wrote code clearly, in this case, that via application.py had this route slash register that didn't just save things in a variable this time. It actually tucked them up into a special type of library that actually knows how to send mail. And this is literally what I did back in the day. It didn't occur to me-- actually, it might have occurred to me, but I didn't know in 1997 what a database was or where we could actually store the information. So I'm pretty sure, the very first version of registrations online at Harvard for Frosh IMs were to literally just send the proctor an email, who was responsible for that intramural sport. And it was good enough. They could just use their inbox as essentially their database, and know who had registered. Eventually though, we were able to improve upon this and actually save things in a lightweight database. I still didn't know SQL, and I didn't know how to do things more fancily. But I didn't know what a CSV file was. I had Microsoft Excel, or Numbers more recently, on my computer, so I can open up spreadsheets. And so it turns out, that if we instead look up say Frosh IMs3, which is our final version of the Frosh IMs suite of examples, I actually went ahead and did this. In this version of the program-- it's a little cryptic, but I figured this out just by reading on Python's documentation and how to use CSVs. And I came up with the following. So as before, on line 12, if not name or not dorm-- so I've reverted to the old syntax, because I'm not using email address for this example-- then I go ahead and return failure.htlm. But the new code here, instead of email, is this functionality. So here I have file, which is a variable, gets stored-- gets the return value of Open. So this is a function in Python that's similar to fopen in C. They just kind of clean up the name here. It open a file called registrants.csv. And what do you think the quote-unquote "a" means? We probably-- you didn't use "a." You used a different letter in p-set 4. AUDIENCE: [INAUDIBLE]. DAVID MALAN: What's that? AUDIENCE: R or W? DAVID MALAN: We used R or W for read or write. Turns out a is a little different, which makes sense in this case. AUDIENCE: Append. DAVID MALAN: OK, thank you. OK, it's append. And append make sense here because write, by default, literally overwrites the file. It creates a new file. Whereas, append literally does that. It adds a line to the file, a new line to the file, which is good if you want to have more than one person ultimately saved in the file. You want to remember everyone else by appending. So this says, hey, Python, open the file in append mode, and store it in a variable called File. This is a line of code that uses some syntax we didn't quite see in C, but we're declaring a variable called Writer using the CSV library, which I've imported at the top of this file, similar to importing the mail library in the last one. And it has a function called Writer that I can pass in an open file. And this is just a special library that knows how to put commas in between values, knows how to save things, knows how to escape things if there's actually commas in your file, and so forth. And then this line is a little funky. But it does use some building blocks from earlier-- writer dot write row-- writer write row. So this kind of does what it says. This says, use the library to write a row to the open file. What you want to write? Now if there's deliberately these additional parentheses here, turns out this function is supposed to take a tuple. A tuple is zero or more values separated by commas, which is kind of nice because it's kind of similar in spirit to a set of columns. Like a tuple is something comma something comma something. That is exactly what we want to put in a CSV, something comma something comma something. Because if you're unfamiliar, a CSV is just a file where all of the values are separated with commas. And if you open it in Excel, or Numbers, or Google Spreadsheets, each of those commas demarcates a barrier between various columns. So this says, go ahead and write a row to the CSV, containing the student's name and the students dorm. And then close the file and return Success. So at the risk-- there's like a 30-second internet delay, which means we can keep this clean for about 30 seconds. Let me go ahead and run this example here in Frosh IMs3 and do Flask run-- Enter. And if you'd like to go ahead to my same URL, tinyurl.com/fridaycs50, that will take you back to a slightly older version of the form, no email address, so make sure you hit reload. And you should see just this version, name and dorm. And if I wrote the code right, we should all be able to register in a file called registrants.csv in my IDE. You're not going to get an email this time, because we ripped that functionality out. But this Register page claims that it's working. So if you'd like, take a moment to do that. I'll go back to the IDE here. Looks like a lot of registrations coming in, so that's pretty cool. These are the logs here. And so you can see everyone visiting the site and hitting Register. That's actually a lot of people registering. That's pretty cool. I'm going to briefly turn off the screen this time and see who has registered by going into this directory. This is-- OK, I'm going to go into Frosh IMs3 is what I'm doing here. I see registrants.csv. OK, let's just scrub this. [LAUGHTER] OK, David Malan 2.0 registered, great. All right, I'm going to download this file. I think it looks pretty clean. Let me download this. And I'll show you what I'm doing in just a second. But this is the best demo ever, from what I can see. All right, and let's make sure I didn't miss this here. Uh huh, OK, some of you are just hitting-- Brandon was just hitting Submit a lot, apparently. All right, I don't think I'm going to regret any of this. OK, we're good. All right, so what did I just do? We're back. So now that we've run everything through the censors, what I've noticed is that, oh, I have a registrants.csv file in the same directory. And that was what was getting appended to each time. Meanwhile, if I go ahead and download this file by doing registrants.csv and then Download. Or I could just open it in the IDE to see the actual rows and columns. Let me actually do that real quick. So you'll see this file here. But it's a little hard to see. So I'm going to deliberately close it, because I downloaded it earlier. And I can actually open it in Excel. And if in Excel I just expand my columns, each of these columns represents the gap between a comma. Brandon was apparently trying to make his name very big and bold, but that doesn't work in CSV files. Montreal is apparently the best. A lot of first names-- more Brandon-- unknown, OK-- there is that one I mentioned, someone's dad. Maybe someone's dad is here today, OK. All right, we, MTL is the Best, John Harvard, John, Olivia, Batman, Kyle-- [LAUGHTER] DAVID MALAN: OK, there's Worthy of Wiggles-- now it's getting a little strange-- faces, buttface, OK, that made it through. I didn't notice. David, I'm scared, OK. [LAUGHTER] So we finally have, thanks to programming, the ability to actually keep some of this data around. And so this ultimately allows us to now start making applications that are truly interactive. And they actually allow us to store information and retrieve that information, ultimately. And it all reduces to some of these simple paradigms. And now, absolutely, there's a whole bunch of cryptic syntax involved. And there's some new ideas along the way, things like tuples and things like routes. And I didn't use the word before, technically this at sign denotes something called a decorator. But as with C, back in those early days, keep in mind that once you start noticing these patterns, even if you don't appreciate everything or understand everything from the get-go, you can kind of iteratively get more comfortable with the material. If you kind of take on faith that I don't really remember how this works, but I know that I have to do it now, that's fine. Because if you understand more of the stuff below it, that'll solve the problem for you and get the work done. And as you get more at ease with this, then can you start, through section, and office hours, in the p-set itself, start to really understand some of the nuances here and how it relates or doesn't relate to things we've seen in the past with C. So where are we going with this? Well, with problem set 6, we're going to bridge these several worlds of the web, and of Python, and also of edit distance, and dynamic programming from our Yale lecture a couple of weeks back. And if you're a little behind on some of those topics, or some of today's material wasn't quite on the tip of your tongue, that's fine. Do go back, though. Because realize the past three lectures really now culminate in problem set 6. You will be challenged to go back and re-implement Mario, either the less or the more comfy version, not in C, but in Python. And odds are, you'll be struck for at least two reasons. One, odds are if you did solve it successfully the first time around, even if you're a little rusty, odds are you will solve it much more quickly this time around, even though it's a new language. And you'll see what some idea from C maps to some other idea in Python, just like we did from Scratch to see that same kind of transition. Same thing for Cash or Credit, same thing for Visionaire, or Caesar, or Crack as well. But the icing on the cake is then going to be to not just write code in Python, but write code in Python for a web application that actually does something graphical with a website. So for instance, here we have the more comfortable version of the staff solution to Similarities, one piece of problem set 6. And you'll notice on this web-based form, I'm currently at similarities.cs50.net/more. Your URL, of course, will be different, whether you do the less comfy or more comfy as well. But here we have a web form with two strings waiting to be typed in, two textboxes. And now this form arguably looks a lot prettier than the ones I've been doing today. And because the ones I've been doing today had no what in them? AUDIENCE: CSS. DAVID MALAN: There was no CSS whatsoever. So what I was getting were the pretty old, ugly, 1990s styles defaults that Chrome, and IE, and Edge, and Firefox, and Safari all give me by default. But you can use libraries out there that allow you to make your websites much prettier. So long as you just understand how to generate the markup, you can let someone else style it and take it that last mile for you. So most of the aesthetics of what you see here, the nice navigation bar at the top, the font sizes, the nice gray highlighting here, the fact that this goes all the way to the edge, the fact that there's the same margin over here as there is over here, the fact that the button doesn't look as ugly as it did before, all of that is CSS. And we happen to be using a library called Bootstrap, which is a very popular library that's got a lot of functionality, like forms, to help you style these things. And if I, in this application, type in a string like Harvard and then type in a string like Yale and click Score, what you will see here, a little cryptically-- very cryptically if you're not fully caught up on our lecture from Yale-- is you see a matrix at the top here. This is just a grid of rows and columns. The top row of this matrix says H-A-R-V-A-R-D, so obviously the first word I typed in. And on the y-axis it says Yale, Y-A-L-E And what each of these numbers represents is the cost, step-by-step, of converting one string into another. Now that in and of itself is kind of a useless exercise, but the number of steps to convert one string into another rather gives you an estimation of how similar or how different strings are. If there's very low cost to change one string to another, odds are they're really similar. If it takes one step to convert one word into another, odds are they're identical except for one character. Or if the cost is really high, like six, then it takes six steps to convert Harvard into Yale. And that kind of makes sense, because they are really different words, except for maybe the fact that they have an A in common that maybe we can reuse without having to change that completely. So edit distance is a technique that can be solved very slowly and very expensively in the naive way, using essentially a couple of for loops, where you iterate over one string, you iterate over the other string. And you just iteratively, or rather by a bit of recursion, try every possible change to the string. Well, what if I delete this and then add this? What if I add this and delete this? What if I just change this, and then add this, and then delete this? There are so many permutations of adding, and deleting, and editing characters, that it's just a really slow problem, especially when the strings get longer than these. And so what you'll do, if you choose to do the more comfy version of the problem set, is you'll implement this by a dynamic programming. And this matrix up here just remembers, just stores, all of the temporary values that I've so-called memoized along the way, such that if you recall from Benedict's lecture, you just kind of work your way from top left to bottom right to get your final answer. And the fact that that number is relatively big, 6, means that Harvard is not very similar to Yale, at least in terms of its string comparison here. I didn't realize the semantics of that until I said that sentence. So meanwhile-- oh, and then as an aside, if you didn't notice already, at the bottom here is kind of a log. This just shows you, once you've implemented the top here, what it is that has to happen to Harvard in order to turn it into Yale. We have to delete an h, delete this a, delete this r. Then we have to change a letter to y, change another letter to l, and another letter to e, and voila, Yale. But notice, if we do something more similar, like let's say, let's say, suppose we do Mario from p-set one and Maria from the heads team. This is a much more similar string, because it only takes one step to convert one into the other. And so the log is much smaller as well. And so you get an estimation of similarity. But we can take this one step further using different algorithms that may or may not perform as well. So here's the less comfy version of the same problem, whereby now I'm being asked for two files, so not just two strings. You can you do even bigger files in this way, because it's not quite as expensive, and it's a lot easier to show on the screen. So I downloaded, or I whipped up a couple of examples in advance here. I have a file called hello.c, which looks like this-- a little flashback from week 1. And then I have another file called hey.c, which is identical except for some word, like, hey comma world. So I'm going to go ahead and do this. I'm going to go ahead and upload hello.c and hey.c. Or I could just click these, and then I could navigate through my hard drive like you might on your Mac or PC. But I'm just going to drag and drop them. And then I have three choices of algorithms. Because if you can think about what a text file is, I don't really know off the top of my head how best to compare them. I can probably tell you if they're identical. I can just use like a while loop or a for loop in C and iterate over every character in the file and tell you True or False, these files are identical. But if there's a little difference, like hey and hello, or maybe some spacing, then I have different options. So what if we compare these files line by line? Should most of the lines in hello.c and hey.c be similar or different, do you think? AUDIENCE: Similar. DAVID MALAN: Similar, except for that one printf line. So let's see what happens. If I go ahead and choose compare lines as my algorithm and click Compare, I see highlighted in yellow, in the user interface, the two programs left and right, hello and hey, with all of the identical lines highlighted. So the fact that there is so much yellow means, OK, these are pretty similar. I'm not slapping a value on it, in this particular case. But I certainly could say that it's all but one of the lines are in common and ascribe it that kind of score. Meanwhile, sentences doesn't necessarily make sense. But if this were an essay, or if you're familiar with sites like Turnitin and so forth, like an English essay, I could upload two different essays and see how many sentences do they have in common. So that even if one sentence is up here and another is down here, because the students used the same quotes or whatnot, I can at least find those by breaking the text up based on periods in an English sentence, which don't exist in quite the same way in code. But what about substrings? Substrings is a more fancy term just to say a portion of a string of length one, or two, or three, or four. And here I have a textbox where I can configure this. So if I want to look for common substrings of length 10, that would be a pretty long string of text that's in both. Compare, and indeed, there's a lot of stretches of 10 because they're all so similar. If I instead change this to one, looking for all the common characters, you'll see that almost everything is in common, except for what missing letter? AUDIENCE: Y. DAVID MALAN: Y-- so there's going to be a couple of different ways you can implement this, actually many different ways that you can implement each of these algorithms. But what's key is that by using Python, you're going to have a lot more tools at your disposal. You're going to have different data types like Lists, and Sets, and Dictionaries, if you want to use them. And what you're not going to have to do, as you might have in C, is actually parse out these characters individually. Rather, if you want to split up a file based on its lines, just call a function for that. If you want to actually grab all of the whitespace, just call a function for that. If you want to take a substring of a certain length, just use the right Python syntax for that. And so once you've taken this sort of scaffolding approach of porting some of your C problems to Python, you'll culminate in implementing either of these. We'll wrap a bit earlier today. I'll stick around for questions. Best of luck, and see you next time.
B1 US html malan david malan server slash david CS50 2017 - Lecture 9 - Python, continued 59 8 小克 posted on 2017/11/14 More Share Save Report Video vocabulary