Transcript #160: Your JSON shall be streamedReturn to episode page
00:00 KENNEDY: Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds. This is Episode 160, recorded December 4th, 2019. I'm Michael Kennedy.
00:11 OKKEN: And I'm Brian Okken.
00:12 KENNEDY: And this episode is brought to you by DigitalOcean. Check them out at pythonbytes.fm/digitalocean. $50 credit for new users. Let's start with a topic that we've covered quite a bit, Brian, type hints. Or do you call them type annotations?
00:25 OKKEN: I usually call 'em type hints.
00:27 KENNEDY: Yeah, I go back and forth, and the article you're going to mention actually says you can call them both. But yeah, it's kind of funky that they don't have a definitive name. Maybe they do and I just don't have certainty around it.
00:37 OKKEN: Yeah, one of 'em's wrong, and whatever one I'm using is probably the wrong one. So we have covered it a lot, and there's a lot of tools that we've talked about, like Mypy and others. So hopefully we've convinced everybody that they should at least do a little bit of type hinting? If you're in that boat, then this article's perfect for you. Al Swaggart wrote an article called "Type Hints for Busy Python Programmers" and that's everybody, right? I mean...
01:01 KENNEDY: We're all busy.
01:01 OKKEN: We're all busy. I really like the article. It's kind of a, when I first went to it, I was a little shocked because there's a lot of words there, but it reads like a conversation. It's a conversational thing, as if it's a programmer talking to an expert. So that sort of tone of, I think I should do this, but what do I do? And so he just sort of walks through a whole bunch of questions with it. He covers using Mypy and typing as the two modules you need and how to use those, and there are other tools, but really, most people are using Mypy, and that's what, Al's saying that. I don't know if most people are using Mypy or some of the other tools. I don't think there's any way to gain statistics on that. But I think Mypy's a good way to start. And a reminder that using types doesn't affect runtime. It's, you have to run a tool like Mypy to get it to work. And so I don't think he covers this, but I think that people should hook a running Mypy into their tox system or into their continuous integration pipeline to make sure that these are met.
02:09 KENNEDY: Yeah, everything's hanging together, yeah.
02:10 OKKEN: Yeah, there isn't any compiler to catch you. So one of the things I liked about it is that it gets you started and it covers some of the basics, but there's, as I've started running it, started using type hints, the exact things that I've run into, Al covers. For instance, you got a function that takes an integer, but it also could be None, or the default is None or it's optional or something. How do you deal with that? There is stuff built in the type hint system for union, so you can say it's either an int or None, and there's optional parameters. And then a shout-out to stuff that, if you kind of get into it and you might, like, if you're passing callables or sequences around, yes, there are ways to type that. And so I think this is actually just a really great quick read and it'll get you started pretty fast.
02:59 KENNEDY: Yeah, I really like it. I love the conversational style. It seems super approachable and it's kind of from the skeptic's perspective. It seems a little bit like, oh, I want to do this, but what about, I don't know if I'm sure about this. Why can I do this? And yeah, it seems like a lot of fun. I'm definitely a fan of type hints these days not for the Mypy reasons. I understand that makes sense for very large projects. But for me, like, the editors are just so much better if you can just give them these little hints here and there. I'll give you an example. Like, for the database for Python Bytes, we're talking to MongoDB with Mongo Engine, and the way you specify it is much like SQLAlchemy, or even maybe more so like Django ORM where you say this column is a Mongo Engine column of type such-and-such. Well, the type editor, the editors think the type is a column, but it's not a column. It's probably a datetime, or it's a string, or it's a list, or it's anything but what they think it is. And so you can use type hints to say this column is an integer and it's equal to one of these column things.
04:01 OKKEN: Oh, okay.
04:02 KENNEDY: And that'll tell all the editors when I hit dot on this, don't tell me it's one of these column things. I don't want to know that. I want to know what its value is, 'cause that's what I program against when I run it. So there's just all these different angles that make it super valuable.
04:12 OKKEN: Oh, I'll have to take a look at how you're using that. That's pretty cool.
04:15 KENNEDY: Yeah, for sure. Speaking of cool, another thing that we have beaten to death but is very tough and leathery and has not died is the ability to create an application out of Python code, right?
04:24 OKKEN: Yes.
04:26 KENNEDY: Well, I stumbled across this thing. I don't believe it is new, but it actually is interesting on layers of interest here called auto-py-to-exe. auto-py-to-exe. Okay, so this is a GUI, and it's built with Eel. First of all, what? It's a GUI Python thing built with Eel. Remember Eel?
04:48 OKKEN: Kind of, remind me.
04:58 OKKEN: Oh, okay, it says electric snake, got it.
05:02 KENNEDY: Yeah, Electron, elec, yeah, exactly. So it's very much like that. I think it's for kind of simplistic ones, but it certainly works for this app, which is pretty cool. So here's a Python app built in Eel. That's cool. And it's kind of meta in the sense that its job is to make other Python applications out of native Python code.
05:20 OKKEN: Okay, interesting.
05:20 KENNEDY: Okay, yeah? So what it does is basically, this is automation over top PyInstaller. And you might think, okay, well, I could just pass the command line arguments and just do that. But there's something really nice about having a GUI say here's the icon. I just put the icon into the app. And now here's the name I want for the title and such-and-such, and here are the additional binary files or additional resource files I want bundled and shipped with my application. We're using this JSON file and we're using this, I don't know, this image that we're going to embed somewhere. Just include those. And so there's all sorts of settings in this auto-py-to-exe where you can just pick all that stuff out and you don't really have to be an expert at all with PyInstaller, but you can build pretty nice stuff. Like, there's a checkbox. Do you want just a loose set of files or do you want it bundled into a single .exe that I can just give and it'll contain Python and the dependencies and all that.
06:11 OKKEN: Okay, this does sound neat, yeah.
06:13 KENNEDY: It's pretty neat, right? Yeah, and so really, people want to, if this sounds interesting to you and you want to find out, hey, is this cool, is this interesting, there's a three-minute YouTube video. You can just check that out.
06:24 OKKEN: Okay, cool.
06:25 KENNEDY: So I put the link to the three-minute video at the end. People can click on that and watch it, and then within three minutes, you'll decide whether or not this is useful for you. But some of the conversation I saw people say, yeah, I know it just automates PyInstaller, and that's cool, but there were things I couldn't get to work with PyInstaller, but doing it here, it worked fine. So I feel like there's a lot of value in this.
06:42 OKKEN: Yeah, nice.
06:42 KENNEDY: Yeah. Speaking of value, DigitalOcean, they are adding a lot of value to all of the hosted things of the world, including our stuff that's hosted there across all the different sites and whatever. I believe we're doing 15 terabytes of traffic a month through DigitalOcean.
06:55 OKKEN: Wow.
06:56 KENNEDY: That is not messing around. That's a lot. So been rock solid. The other thing that they have that they're just launching is the Kubernetes container, their own container registry for things like their Kubernetes service. So we've got Docker Hub and places that you can put your containers, but that's on the public internet and things like that. It'd be nice to have a private little one for your private code that you want to make sure doesn't somehow leak with a, you know, making it public or private on accident or whatever. So you can use their DigitalOcean Container Registry and have nice, private container definitions. It's pretty cool, among other things. So check them out at pythonbytes.fm/digitalocean. Like I said, $50 credit for new users to get started playing around with this. Speaking of playing around, I have never played with Sphinx.
07:41 OKKEN: Oh, you never have?
07:42 KENNEDY: I haven't, I've had no reason to do it, but it seems like something that's useful. Maybe I should learn about it.
07:46 OKKEN: Yeah, so one of the things, like, so what I've wanted to use Sphinx for, so Sphinx can be used for building up documentation. It makes a documentation website based on either rst or markdown. Or not, rst and...
07:59 KENNEDY: Restructured text.
08:00 OKKEN: Restructured text, yeah. Thanks a lot, programming world, for having two things that could be abbreviated rst. In the C++ land, there was some auto-documentation tools to where you could take, and I know other programming languages have this, too. Where you can take information about the structure of the program and automatically generate some web documentation about how to use it and what the parameters are for different functions and stuff like that. So you can do that with Sphinx, and that's the thing I've been wanting to do, and I've tried several times and failed, and it's usually because, probably on my part, but the tutorials get me part of the way and then they reference a bunch of documentation and stuff, and I don't want to become a Sphinx expert. I want, that's kind of the point of this. I want to be able to just point it at my code and go, "Go do it." And, like, for instance, pulling out, so what does a function do, what do the different tests do. I'd like that to be embedded in the docstring so that when I'm coding, I can make sure that that's correct and then that's just automatically generated. So what I'm highlighting today is an article called "How to Document Python Code with Sphinx." It's a short tutorial by Moshe Zadka? That's a cool name. And so walks through, it has a little example of a little module with a docstring and then the small example of how to set up your index.rst. And I like markdown better, but this is so short, I'd probably just use the restructured text version. Points out that you need a few extensions. You need autodoc, napoleon, and viewcode. And then it just gives you the conf.py file you need to make this work. And then how do you generate this stuff? Well, there's this long, weird command. It's not that weird, but I don't want to memorize it. So this tutorial also shows you how to set up a tox.ini file with this Sphinx built in, so you can just say tox and your docs get rebuilt. So I like this tutorial and I'm going to give it a shot.
09:59 KENNEDY: Yeah, it's a really cool thing, and automatically generating your documentation, not terrible at all.
10:04 OKKEN: Of course, it doesn't cover, like, okay, well, now that you've generated it, it's a bunch of web pages and stuff. Where do you put that? But for internal documentation within a team, you got your own way to do it, whether you're pushing it into a small web server or just leaving it with your code or whatever. So leave that to the user.
10:22 KENNEDY: Yeah, or put it on DigitalOcean. Or not, GitHub pages, right? That's one thing you can do. You can put it on Netlify. A lot of options for just hosting HTML.
10:30 OKKEN: Yeah, or throw it into a GitHub cluster, or a Kubernetes cluster. I don't know, maybe not.
10:37 KENNEDY: That's right. So something that's always amused me is the association of Python ecosystem and language with snakes. Because that's not what the origin, right? That's not what Python is named after. It's named after Monty Python. All these apps and stuff should have, like, medieval knight type of names, but they don't. So I'm going to tell you about one that is called Snek. Snick? Snake? S-N-E-K, Snek. I don't quite know the right accent to put on it to pull that off, but Shnek. It's pretty awesome. So it's a PowerShell module for integrating standard CPython, just Python code, and various packages with PowerShell. So if you're doing anything on Windows, any sort of automation or advanced shell stuff, you're probably using PowerShell, although the regular terminal's getting better, as well. And, you know, the story of Python on Windows has always had a little caveat, or maybe a little star, like, yeah, you always do this, except for on Windows, you type this other thing. And it's slowly getting better, right? Steve Dower's done a lot of work to improve that with the Python installer that comes off the Windows 10 store. It has python3 as a command and not just python, and so on. But here's one more thing that you can do to make working on Windows with Python better. If you do anything with PowerShell, you can write scripts now that have sections of those scripts or libraries for PowerShell written in Python, and it uses this library called Python for .NET, which is a new, modern way to share the entire vast library of .NET and all the objects you might put there with Python code. And similarly say, this Python thing returns some funky .NET type that could be converted so it looks normal to the rest of the PowerShell land, which is generally .NET stuff. So if you're doing stuff with PowerShell, check this out. It's pretty cool. The syntax is funky, but, you know, it's PowerShell syntax, so there you have it.
12:36 OKKEN: Yeah, well, okay. So I think that people can't be blamed for doing the snake thing because our logo is two snakes.
12:43 KENNEDY: I know. I think that that is absolutely true.
12:46 OKKEN: I think it should be maybe some cheese.
12:48 KENNEDY: Yeah, exactly. Or maybe a shield. I don't know, whatever. I don't mind having it be a snake. The snake is cool and there's the python snake. It's just funny that that's not actually the name.
12:57 OKKEN: No, a killer rabbit would be nice.
12:58 KENNEDY: Yes, a killer rabbit would be fantastic. If you just got an exception and that appeared as an emoji, that would be beautiful, yeah. Or maybe a failed test in PyTest, right? You could write a plugin that unleashes the killer rabbit and all that. Alright, we're going down a bit of a hole, so maybe get us out and talk, get us back to the databases.
13:17 OKKEN: Okay, so databases. Since in Python world, one of the things we like to do is use pandas because pandas makes dealing with data so much easier with dataframes and stuff. And also one of the things with databases that we can use is SQLAlchemy if it's a SQL-based database, and most of them are. So you can just take pandas and put it together with SQLAlchemy and put it together with your database and just slurp your entire data tables into pandas dataframes and then manipulate 'em there. So you're good to go, right?
13:50 KENNEDY: Right, unless you have, like, five gigs of data. Then you're good to swap and be very slow.
13:55 OKKEN: Yeah, or terabytes of data. That'd be bad.
13:56 KENNEDY: Yeah, very bad.
13:59 OKKEN: So all hope is not lost, because, I'm going to guess, Irina Truong wrote this article called "How to Use Pandas to Access Databases" and it's really great. One of the recommendations she uses is don't be afraid of the command line for SQL because you can play around with queries and look to see how big the shape of your data is to start with, which is a good thing. But then goes on to tips on how to put this together correctly, like, and I'm just going to read out the highlights, but there's examples of all these, so I think it's great to have a look. Don't grab a whole table. Limit to just the fields that you care about that you're going to actually use. Tables often have a lot of columns that you don't need, so don't grab everything. Limit the number of records. You can either use the limit field to say I only want to grab, like, a thousand elements or something. You can also combine that with just the number of fields. But also, you can also pick out, say, I know I'm going to already throw away all the rows that don't have a particular value in this one fied, so you can limit that in your query. One of the things you'll often run into with SQL databases, of course, is the need to use joins, and the quick recommendation there is let the database do that. Put it in your query. Don't do the join within pandas, because you can do it with pandas and SQLAlchemy together, but don't. It's going to be slower.
15:23 KENNEDY: Right, load it all in memory and have the datatable merge it. That seems probably not like the best way to do it.
15:29 OKKEN: Right.
15:30 KENNEDY: Databases are pretty good at joining stuff.
15:32 OKKEN: Yeah, and, I mean, if you find, of course, it didn't talk about this, but if you find you're doing that a lot, you can kind of restructure some of your queries within, I think you can build that in, make a join be faster? I don't know. I'm not a database person, so.
15:46 KENNEDY: You could put indexes. You could write a store procedure and call that. There's a couple options.
15:50 OKKEN: Okay, you ask Michael how to do it. Anyway, maybe not. So a lot of this is we're caring about memory, so how do you figure it out how much memory you're going to use? And I didn't know you could do this, but there's, she has a tip of using a query called memory_usage and then summing it. It says, I don't know what the field comes back, but you can do a query and grab the memory. But you do a small query, just 100 rows or something, and then take that, and then you can use that to estimate the total size when you're going to read out 1000 or 2000 or something. And then the last one I actually didn't quite follow, but I think I kind of followed. The tip is that the types get converted, integer types get converted to 64-bit types, I think, and you don't really need that for a lot of stuff, so there's a, I'm calling this out because it's definitely for the user, read this if you need it. But there's a little bit on using chunking and then combining that with specifying what pandas types to use so that you get smaller data footprints.
17:01 KENNEDY: Yeah, yeah. So, for example, maybe one of the columns in the dataframe, just the way it came back from the database is a 64-bit type integer, and you know everything would actually fit into an unsigned 16-bit integer. Well, that'll save you, it'll be a quarter of the size of the data if you make that conversion, right? So, got a million of 'em, a quarter of the size of a million is possibly meaningful.
17:24 OKKEN: Yeah, I mean, a lot of stuff that, like, for instance, a lot of stuff I'm, one of the tables I deal with has a number, numbers for the different, specifying which kind of result we're looking at, for instance, and they each have a number code. There's only six, so the number can be one through six. I don't need 64 bits to store that, so, yeah.
17:46 KENNEDY: For sure.
17:46 OKKEN: So that's good. Do you use pandas with SQLAlchemy in any of our, when you're doing it?
17:50 KENNEDY: Nah, not really. There's a few times I've been thinking I should probably try to do some BI, like graphing-type stuff, maybe about popularity of episodes or things like that. Figure out what they actually release our podcast on. But I haven't done anything like that, no.
18:06 OKKEN: Okay, but you do use SQLAlchemy, though, right?
18:08 KENNEDY: Some, but not for the main site, because that's MongoDB.
18:11 OKKEN: Oh, right, yeah.
18:14 KENNEDY: But I'm using something, I'm using Mongo Engine, which is super equivalent. Yeah, yeah, yeah.
18:17 OKKEN: Nice.
18:17 KENNEDY: Cool. Yeah, I suspect there's probably some interesting MongoDB integration with pandas that I just don't know about, but I don't know any equivalent there. Well, this next one I'm going to cover is very similar to what you talked about. It talks about how do I basically efficiently work with data from this one source, databases, and how do I not just select star from all the tables into pandas and work on it. Another problem you might have is you might have JSON data. JSON is sweet, but one thing JSON is not very obviously good at is streaming data, right? Because how do you know where the closing curly brace is? Maybe you've got some key and then it's got an array of stuff, and the closing bit of that array is not until maybe 500 megabytes down the file. That's a problem potentially, right? So if you load it with, if you just load up a, you know, import json and do a json.load, give it a file pointer, it's just going to hoover that all up and jam it into one giant dictionary and spit it out. But if it's huge, obviously what you want to do is iterate over it and process it item by item, yeah? I mean, that's what you would do for a regular file if you could take it line by line, but because it's this formatted thing, it's much harder. And something I ran across the last time, time before, we were talking about some other project, and it said, oh, this project uses ijson. I'm like, wait a minute, what is ijson? That's interesting. So ijson is an iterative JSON parser with the standard Python iterator interface. So what you can do is basically point it at a file stream, some search expression, kind of, in the JSON document, and then it will stream those back to you generator-style, one at a time.
20:02 OKKEN: That's so cool.
20:03 KENNEDY: Yeah, so there's a little example I put in the show notes. It says imagine we've got some object called earth in our JSON document, and it has a bunch of continents, and within each continent, it lists out, say, cities and states and so on. If that was huge, probably it's not, but if it were, you would want to iterate over it. So you just go to the ijson and go, give me the items from this file for earth.europe.item, and item is just a way to say stop there. And then what you do is you just say for thing in whatever came back from that load that you did, and you just iterate over it in a for in loop.
20:39 OKKEN: That's really neat. And it's doing, like, I was looking at the website. There's an example with grabbing it from a URL, because that's, you might be getting it from an API endpoint. So I'm guessing that it's not grabbing everything from the endpoint at first.
20:55 KENNEDY: It probably depends on how the endpoint is set up, or even maybe how the object that's querying it back. So I think they're using urllib or something like that there. If you would set that up to do streaming, then you pass the stream over to ijson, then it would probably stream it from the server and never keep it all in memory at once, anyway. That'd be cool.
21:13 OKKEN: Yeah, that'd be cool.
21:15 KENNEDY: Yeah, but there's probably several layers you got to set that up as.
21:17 OKKEN: I'm using generators and iterators more and more because this lazy, doing lazy work is awesome, and it speeds things up quite a bit sometimes.
21:26 KENNEDY: It's so awesome, and you basically no longer have a memory issue no matter data you have. You might still have a time issue, but you're not going to run out of memory, right? You're just going to blast through it one at a time instead of blasting through them all and then working on it.
21:38 OKKEN: Oh, nice, I got to check this out. Cool.
21:39 KENNEDY: Yeah, so people, if you have large JSON, bring out the ijson. Alright, well, that's it for all of our main items, Brian. I have, for some reason, it's like a crazy news week, and I actually decided to not throw a bunch of stuff in here, but to save it till next time, because I just don't want to overwhelm everyone. But yeah, I've got a bunch of stuff to talk about. How about you?
22:01 OKKEN: I am just kind of in a lull after Thanksgiving.
22:07 KENNEDY: Still in the turkey coma?
22:08 OKKEN: Turkey coma, yeah. My head's spinning. There's a lot of stuff coming up in the next couple months, and I'm pretty excited about.
22:15 KENNEDY: That's awesome. Yeah, I'm trying to juggle between getting over that holiday break, doing all the Black Friday stuff at Talk Python Training, and then getting ready for vacation. It's a lot. But in that little gap where I'm really still paying attention, there's a bunch of stuff that I ran across this week. So first of all, let's start with this. Django 3 was released.
22:32 OKKEN: Oh, sweet.
22:35 KENNEDY: Yeah, so that's pretty cool. And Django 3, there's a couple things that are important about it. One is it has official support for MariaDB, which is pretty cool. The other one is that it begins the journey to the async world.
22:49 OKKEN: Dun dun dun.
22:50 KENNEDY: Oh, we'll cross over to the ASGI world. Yeah, so things like async and await are now making their way to Django. I saw some messages from some of the developers there saying that this is not like the full story. This is the first steps. So we got a long ways to go, but it's first steps, right? It's great to see them moving that way. So, but you get super high scalability if you need it. Most people actually don't need it, but if you do, it's cool to say the answer is not, well, now you move to Go or Node. It's you put the async keyword in front of your view method and you're good again.
23:23 OKKEN: Yeah, I'm excited to watch this. And actually, the Django 3 release, I had dipped my toes in Django before, and I wanted to sort of wait until, I knew that 3 was coming, so I was sort of waiting for this to be official before I started up again, so now I got no excuse. I can get started.
23:38 KENNEDY: Yeah, that's awesome. Speaking of excuses running out, the death clock does toll, doesn't it? Pretty soon, the death clock is going to toll for Python 2.7, or 2 in general, and in particular 2.7. And as part of that, Python 2 will be removed from Homebrew.
23:56 OKKEN: Wow, that's big.
23:56 KENNEDY: Yeah, that's pretty, it's just another sign that, you know, you probably shouldn't be using this. It used to be installable. Homebrew install python@2, or two, or whatever the keyword was. Yeah, that doesn't work. Not yet, very soon that's going to stop working. So, that's cool. Big news, although I'm not really sure what spin to put on it, so I'll just give you the news, is Guido is stepping down from the steering council. And this came to us from Vincent POULAILLEAU.
24:21 OKKEN: Right, it's a thing. I don't really know how to spin it other than that.
24:25 KENNEDY: Well, yeah, I mean, basically, from what I got out of doing a little bit of reading is there were new elections to reelect people to the steering council, and Guido didn't put his name in the hat. And people said, "He didn't put his name in the hat. Here, let me put it in there for him." And then there was the conversation that followed that, you know, a lot of people are enjoying being part of the steering council. I've been on that part of Python for a long time, and it's just not fun for me right now, and I've earned some fun in the programming world. So I want to work on projects and not politics and all that kind of stuff, so I'm going to let someone else take it. And he also said, "The reason I'm comfortable doing this is it's in good hands. The people already, the other council members there are great, so you all don't need me. I'm still going to be around and working on stuff, "but I just don't want to be on the steering council." So anyway, thanks, Vincent, for sending that over. That's big news, but that's about all I got to say. There wasn't a whole lot written about it, really. GitHub is freezing open source for hundreds of thousands of years to preserve it for humanity. That's pretty awesome.
25:25 OKKEN: Yeah, so the GitHub archive program, I watched this video.
25:29 KENNEDY: It's well done, right? It's like a polished little video.
25:31 OKKEN: Yeah, so I don't know what to make of it other than it's a thing. They're going to put a whole bunch, all the, as of, like, they've already put a bunch of stuff in there, but I guess next spring, they're going to, or when, next summer or something, they're going to go up and take all open source code on GitHub and digitize it into these films, these weird...
25:54 KENNEDY: Microfiche code. Digital microfiche or something that'll last for very long.
25:58 OKKEN: Yeah, it's supposed to last 1000 years or something like that. And they're going to put it in, like, some cave in, on an island somewhere.
26:05 KENNEDY: Greenland? Iceland? One of those two, I can't remember.
26:07 OKKEN: Right, so why?
26:09 KENNEDY: To preserve it, I don't know. I'm pretty excited. I have over 100 public repos that are going to be up there, though. That's going to be awesome. I'm excited for them to get pulled and...
26:16 OKKEN: Yeah, if all of civilization collapses, we're counting on future civilizations to be able to find this cave and figure out some technology to read these microfiche things.
26:30 KENNEDY: Wow, those ancient creatures wrote in a very weird symbol form.
26:33 OKKEN: Yeah, okay, well, good luck, future selves.
26:37 KENNEDY: Yeah, yeah, good luck, future selves. Hopefully they got some hints. But anyway, that's pretty cool. And the last thing, I had talked about this Python for Decision Makers course that I'm working on, and basically, it's the high-level of why Python, when to use it, what it's good for, what it's not good for. I'm also going to do a live webcast that people can check out after the winter break. So mid-January, I'm doing just a free webcast. People can sign up and come ask questions and we can just share our thoughts on whether Python makes sense for whatever they're doing.
27:07 OKKEN: Awesome.
27:08 KENNEDY: So people can check that out.
27:09 OKKEN: Nice.
27:10 KENNEDY: Click the link and register for free.
27:11 OKKEN: Cool. That's a lot of stuff, man.
27:11 KENNEDY: It is. I think we should wrap it up with a joke, though.
27:14 OKKEN: Yeah, let's do that.
27:15 KENNEDY: As is our tradition now. Alright, you go first.
27:18 OKKEN: Okay, so. Okay, a web developer walks into a restaurant. He immediately leaves in disgust, as the restaurant is laid out in tables.
27:27 KENNEDY: Oh. Must've been a NoSQL web developer. Doesn't want that relational stuff in there. Yeah, that's pretty funny. That comes from a joke API that Ninjutsu sent over, so appreciate that. And this next one is, well, also from there, but I kind of like it so I'm going to cover it. So last time when we were talking about pint, you talked about using prefixes and suffixes for variable names, like, if I'm going to have something in meters, I'd use an _m potentially, or centimeters, _cm, whatever convention you use. So what is the best prefix for global variables?
27:59 OKKEN: I'm not sure, what? Maybe g?
28:00 KENNEDY: That would be, yeah, g. g_, something like that, if it's global. Or hash. Like, you shouldn't have global variables, so let's just comment those babies out.
28:11 OKKEN: Comment those out.
28:12 KENNEDY: Pretty sweet, yeah. Thanks, Ninjutsu, for sending those in. Those were funny. Alright, Brian, well, thanks, as always.
28:17 OKKEN: Thank you. Bye.
28:18 KENNEDY: Yeah, bye. Thank you for listening to Python Bytes. Follow the show on Twitter via @pythonbytes. That's Python Bytes as in B-Y-T-E-S. And get the full show notes at pythonbytes.fm. If you have a news item you want featured, just visit pythonbytes.fm and send it our way. We're always on the lookout for sharing something cool. On behalf of myself and Brian Okken, this is Michael Kennedy. Thank you for listening and sharing this podcast with your friends and colleagues.