WEBVTT 00:00:00.001 --> 00:00:04.880 Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to 00:00:04.880 --> 00:00:11.660 your earbuds. This is episode 132, recorded May 22nd, 2019. I'm Michael Kennedy. And I'm Brian 00:00:11.660 --> 00:00:15.820 Aitken. And this episode is brought to you by DigitalOcean. Check them out at pythonbytes.fm 00:00:15.820 --> 00:00:20.660 slash DigitalOcean. More about that later. Brian, how you been? I'm good, but I'm giggling right now 00:00:20.660 --> 00:00:24.460 because I've been looking up jokes, but we'll get to those later. Yeah, I always look forward to the 00:00:24.460 --> 00:00:28.420 jokes. And I think a lot of people out there seem to appreciate them. So yeah, we won't disappoint 00:00:28.420 --> 00:00:33.680 this time. We got more lined up, as always. Yeah, okay. I mean, like in the past, you maybe used to 00:00:33.680 --> 00:00:38.720 have to come up with these, but we have the internet. Yeah, I know. It's beautiful. It's easy to be a dad 00:00:38.720 --> 00:00:43.420 now. That's right. All right, you want to kick us off with a little embedded Python? Yeah, I was 00:00:43.420 --> 00:00:48.420 really excited to watch this. So I did meet, so this, the first one I've got up is the history of 00:00:48.420 --> 00:00:56.780 CircuitPython. And this was actually on the PSF blog. And I think that a Jesse Jerry Davis put it up. 00:00:56.840 --> 00:01:02.740 But anyway, it's about the history of CircuitPython and Adafruit and Scott Showcroft, 00:01:02.740 --> 00:01:08.300 which I met Scott at PyCon and I knew he was involved with CircuitPython, but I guess I didn't 00:01:08.300 --> 00:01:14.000 realize he was, he's the CircuitPython guy. So what happened was, and I always kind of wondered 00:01:14.000 --> 00:01:17.360 about this, like the relationship between MicroPython and CircuitPython. 00:01:17.360 --> 00:01:22.360 Right. I knew about MicroPython being for embedded devices. And I'm like, oh, there's now CircuitPython. 00:01:22.360 --> 00:01:27.440 Like, are they friends? Are they frenemies? Like, are they, one is a specialization of the other? What 00:01:27.440 --> 00:01:33.820 are they? So what happened was Adafruit thought MicroPython was a pretty cool thing and hired Scott 00:01:33.820 --> 00:01:40.880 to port it to their, I guess their SAMD21 chip that's used on many of the boards. So he did it, 00:01:40.880 --> 00:01:47.580 he's working on it. And it's a, at first it was just a fork, but now it's a fairly big changed fork. 00:01:47.780 --> 00:01:54.740 There's a lot of differences, but Scott said it's a friendly fork. So they, he works closely with the 00:01:54.740 --> 00:01:59.520 MicroPython people too, and they share code back and forth. So there's no, no hard feelings there, 00:01:59.520 --> 00:02:06.080 but it's focused on the Adafruit boards, but it's also, MicroPython is also focused really just on 00:02:06.080 --> 00:02:14.060 embedded stuff. Whereas CircuitPython is focused on beginners. And one of Scott's quotes is, 00:02:14.060 --> 00:02:19.980 our goal is to focus on the first five minutes someone has ever coded. That's a strong lofty 00:02:19.980 --> 00:02:25.660 goal. But watching some of their demos with the CircuitPython, it isn't surprising to me, you know, 00:02:25.660 --> 00:02:30.500 doing, they just hook it up and a few minutes later, they've got stuff running. It's kind of incredible. 00:02:30.500 --> 00:02:34.880 Yeah, that's really awesome. And that is a very, I don't know, impressive goal to say we're 00:02:34.880 --> 00:02:39.300 focused on the first five to 10 minutes of somebody programming, because yeah, that's, 00:02:39.900 --> 00:02:44.040 that's an early point in the life cycle, but I guess you got, you know, it's, it's got to start 00:02:44.040 --> 00:02:49.280 somewhere. And I do think these embedded devices really do bring like some realism to programming 00:02:49.280 --> 00:02:54.620 for people who may be programming just in the more theoretical way, didn't necessarily connect. 00:02:54.620 --> 00:02:56.160 So it's, it's great. 00:02:56.160 --> 00:03:00.760 One of the things I didn't know about was with, one of the things that CircuitPython does is 00:03:00.760 --> 00:03:06.500 it outputs, like all the print statements go automatically to the serial output. So if you could, 00:03:06.600 --> 00:03:11.180 if you hook up your serial output to a connected display, you don't even have to have any other 00:03:11.180 --> 00:03:14.900 device. You can just see your prints and stuff. So that's kind of neat. 00:03:14.900 --> 00:03:20.800 That's awesome. And Nina Zakarenko actually said, showed how to use this. And like, I think it was 00:03:20.800 --> 00:03:26.340 Visual Studio Code. She had that serial output connected. So just within Visual Studio Code, 00:03:26.340 --> 00:03:29.260 like the devices output would just like stream at the bottom. 00:03:29.400 --> 00:03:37.400 That's so cool. And then, we're also including a link to the release notes for, CircuitPython 4.0.0. 00:03:37.400 --> 00:03:43.080 So it's a new major number. So there's some breaking, a couple of breaking things, but it looks kind of neat. 00:03:43.080 --> 00:03:47.000 Yeah, that's super. And apparently they're not on the zero ver, philosophy. 00:03:47.000 --> 00:03:49.820 Yeah, no, that's good. 00:03:50.320 --> 00:03:59.400 Maybe you read it reverse for zero ver, like zero, zero, four. I don't know. Anyway, if you must, but no, that's cool. It's, it's great that there's a new version of that out. 00:03:59.400 --> 00:04:08.880 And it's, I really think they're doing a lot of cool stuff. The Adafruit folks are doing a lot of cool things. And some of those devices, I think were given out at PyCon this year as well, which is pretty neat. 00:04:09.000 --> 00:04:12.140 So, we've talked about Python being popular, right? 00:04:12.140 --> 00:04:12.620 Yes. 00:04:12.620 --> 00:04:21.700 Yeah, absolutely. So this next article that I want to cover is by dice.com doing a little bit of analysis of the TOB index. 00:04:21.700 --> 00:04:27.620 So we've talked about TOB before. This is a programming index talks about how popular languages are. 00:04:27.620 --> 00:04:37.000 And one of the areas of major growth in Python has to do with the data science space and just the scientific computing in general. 00:04:37.000 --> 00:04:45.820 So this article that I want to highlight, the title is R risks Python, R risks Python swallowing it whole, according to TOB. 00:04:45.820 --> 00:04:50.940 So that's pretty interesting. There used to be like kind of a debate. Do I use R? Do I use Python? 00:04:50.940 --> 00:04:58.240 Well, it looks like there's a lot of consolidation and all this growth in Python is somewhat a zero sum game for the other languages. 00:04:58.240 --> 00:05:03.960 So it might be, might be interesting to check out if you're thinking, should I learn R? Should I learn Python? 00:05:03.960 --> 00:05:10.820 R has a lot of interesting advantages over Python, but it seems like Python is kind of, kind of winning the day. 00:05:10.820 --> 00:05:16.300 And so R has tumbled out of the top 20 languages and now is somewhere below that. 00:05:16.300 --> 00:05:20.880 It's a very popular with a lot of people, but I didn't even hear about it until like maybe a year ago. 00:05:20.880 --> 00:05:24.460 For sure. Yeah. It's definitely focused on a, on a more of a niche space. 00:05:24.600 --> 00:05:37.420 So the article speculates sort of not super effectively why they think that is like the acid question, like, well, it seems that Python is winning in data science, but why? 00:05:37.540 --> 00:05:39.980 And so I thought maybe I'd throw my own commentary in here. 00:05:39.980 --> 00:05:47.440 And there's this idea, like, I really like to talk about with Python being a full spectrum programming language. 00:05:48.180 --> 00:05:53.880 And what I mean by that is like, you can get started with the absolute minimum amount of effort. 00:05:53.880 --> 00:05:56.680 There's no compilers, no linkers, there's no header files. 00:05:56.680 --> 00:06:01.720 There's a single file and you can say print, parentheses, quote, hello world. 00:06:01.720 --> 00:06:02.500 Right. And that's it. 00:06:03.380 --> 00:06:10.680 You don't need to think about generators or all the other stuff that like rich programming languages have. 00:06:10.680 --> 00:06:12.700 Like think C#, Java, C++, right? 00:06:12.700 --> 00:06:16.080 You've got to like do all this ceremony to get going. 00:06:16.080 --> 00:06:24.800 But the value of those other languages is like you can go build, you know, video games or operating systems or, you know, whatever. 00:06:24.800 --> 00:06:28.520 Right. And you can do much of that kind of stuff, not operating systems necessarily, 00:06:28.520 --> 00:06:31.620 but like you can build real apps, professional apps in Python. 00:06:31.620 --> 00:06:43.740 And it kind of scales from this ultra beginner part where you can partially understand the language and be effective all the way up to using meta classes and decorators and generators to build, I don't know, Instagram or whatever. 00:06:43.740 --> 00:06:52.180 And I think that that's actually why Python is winning in the space because the data scientists and scientific computing folks are coming in and they're like, I don't want to be like a programmer. 00:06:52.180 --> 00:06:54.600 I want to use programming to solve my problem. 00:06:54.600 --> 00:07:00.200 And Python lets them start that super easy path, but grow into where they eventually find themselves. 00:07:00.200 --> 00:07:10.120 One of the things also is that people that have to reach towards R or some other programming language, that's not their only software issue that they may have. 00:07:10.120 --> 00:07:16.920 And if you can solve it with Python, you learn Python and then you can solve other automation things within your workflow as well. 00:07:16.920 --> 00:07:18.960 Whereas R has very focused. 00:07:18.960 --> 00:07:22.680 I don't know how much you can do with it outside of data science. 00:07:22.680 --> 00:07:23.300 That's for sure. 00:07:23.300 --> 00:07:24.440 That's definitely part of the story. 00:07:24.440 --> 00:07:27.840 Speaking of stories, you got a little history lesson for us, right? 00:07:27.840 --> 00:07:32.440 I've had this on the list for a while, but it took me, I just went back and read it yesterday. 00:07:32.440 --> 00:07:39.900 It's an article by, I think it's Eamon L. Emery called The Missing Introduction to Containerization. 00:07:39.900 --> 00:07:45.400 And so container systems like Docker and stuff like that, lots of people use them. 00:07:45.400 --> 00:07:50.800 And I do want to ramp up learning how to use them more. 00:07:50.800 --> 00:07:54.520 I'm kind of one of those people that need a mental model of how all this stuff works. 00:07:54.520 --> 00:07:56.020 And this is it. 00:07:56.180 --> 00:08:02.540 So it starts with a 1979 release of something called, I don't even know how to pronounce this. 00:08:02.540 --> 00:08:03.140 Chroot? 00:08:03.140 --> 00:08:05.080 T-H-R-O-O-T? 00:08:05.080 --> 00:08:05.620 Chroot? 00:08:05.620 --> 00:08:06.440 Chroot? 00:08:06.440 --> 00:08:06.940 Chroot? 00:08:06.940 --> 00:08:07.740 Anyway. 00:08:07.740 --> 00:08:14.560 Chroot jail, which was a way to isolate a root process and its children from the rest of the OS. 00:08:14.700 --> 00:08:19.160 But there was a bunch of problems with, there wasn't really meant for security. 00:08:19.160 --> 00:08:22.260 And I'm not going to read the whole thing, but it, you know, builds up. 00:08:22.260 --> 00:08:32.000 Because of this is open source, FreeBSD improved on it, then Linux vServer, and then Oracle Solaris had some stuff, OpenVZ. 00:08:32.000 --> 00:08:35.480 And then Google chimed in with something called C Groups. 00:08:35.480 --> 00:08:39.680 And then a group called Linux Containers did LXC. 00:08:39.680 --> 00:08:42.100 And then, you know, it kind of built up. 00:08:42.100 --> 00:08:43.360 Cloud Foundry got involved. 00:08:43.520 --> 00:08:45.080 And then in 2013, Docker. 00:08:45.080 --> 00:08:49.140 And then Google's still doing more stuff with making things easier. 00:08:49.140 --> 00:08:51.340 But all of this stuff builds up on itself. 00:08:51.340 --> 00:08:55.100 And I really like that bit of a history lesson of how things built on itself. 00:08:55.100 --> 00:09:05.100 And then it jumps into talking about the differences, all the different terms you'll find, like a system virtual machine, a process virtual machine, and VPS. 00:09:05.100 --> 00:09:06.540 And what all those things mean. 00:09:06.540 --> 00:09:12.160 Also, kind of the difference between an operating system container system and an app container. 00:09:12.340 --> 00:09:16.280 And Docker is a little bit of a mix of both. 00:09:16.960 --> 00:09:19.580 So, it's kind of containers and platforms. 00:09:19.580 --> 00:09:23.940 Just why there's so many things around is kind of described in this. 00:09:23.940 --> 00:09:26.400 And then that's only like halfway through the article. 00:09:26.400 --> 00:09:33.860 The rest of the article jumps into, I think it's creating a container system from scratch based on some of these lib container things. 00:09:34.360 --> 00:09:35.880 And yeah, I don't want to do that. 00:09:35.880 --> 00:09:38.860 So, but the first half of it, definitely recommend. 00:09:38.860 --> 00:09:40.040 It's a good article. 00:09:40.240 --> 00:09:42.020 Yeah, the history here is really interesting. 00:09:42.020 --> 00:09:47.260 Like, I guess when I first learned about Docker, I thought like, oh, Docker invented containers. 00:09:47.260 --> 00:09:47.960 Right? 00:09:47.960 --> 00:09:49.120 But absolutely not. 00:09:49.120 --> 00:09:49.780 Right? 00:09:49.780 --> 00:09:52.720 They were building on LXC and all these other things. 00:09:52.720 --> 00:09:55.360 And eventually they sort of moved off that. 00:09:55.440 --> 00:10:01.960 But yeah, they were just, you know, making containers more accessible and easier for folks and popularizing it. 00:10:01.960 --> 00:10:05.000 I think these containers are super powerful and super interesting. 00:10:05.000 --> 00:10:06.420 To me, I don't know. 00:10:06.420 --> 00:10:07.380 Do you feel like they're complicated? 00:10:07.740 --> 00:10:14.520 It seems like the system is made to not be, but I know there's a lot of stuff behind the scenes going on. 00:10:14.520 --> 00:10:17.280 And I, you know, to be honest, I haven't played with them much or used them. 00:10:17.280 --> 00:10:21.460 I don't need them for my normal job, but I would like to learn more. 00:10:21.460 --> 00:10:22.160 How about you? 00:10:22.160 --> 00:10:23.100 I definitely like them. 00:10:23.100 --> 00:10:25.960 I'm not doing anything with them right now. 00:10:25.960 --> 00:10:29.100 And I've thought about how using containers might make sense. 00:10:29.100 --> 00:10:35.560 But at the same time, you'll have like lightweight VMs I just fire up and like they're dedicated to a single purpose. 00:10:35.560 --> 00:10:37.140 So I don't know. 00:10:37.280 --> 00:10:42.160 It's always a bit of a trade-off of like adding more complexity in one place. 00:10:42.160 --> 00:10:44.500 I feel like it's a little bit of a whack-a-mole problem. 00:10:44.500 --> 00:10:49.220 I can have more simplicity in some places, but I've like pushed it to another. 00:10:49.220 --> 00:10:57.940 So for example, right, people talk about containers often being a great way to simplify development environments for junior developers. 00:10:57.940 --> 00:10:58.360 Okay? 00:10:58.360 --> 00:10:58.660 Yeah. 00:10:58.660 --> 00:10:58.960 Right? 00:10:58.960 --> 00:11:00.620 So like I'm going to work in a new company. 00:11:00.620 --> 00:11:02.900 Our app infrastructure is super complicated. 00:11:03.640 --> 00:11:07.220 So what they do is they say, well, here's like three containers. 00:11:07.220 --> 00:11:08.320 One runs a database. 00:11:08.320 --> 00:11:09.640 One runs the web front end. 00:11:09.640 --> 00:11:11.800 One runs the caching tier or whatever the heck it is. 00:11:12.140 --> 00:11:13.680 And I'm going to just run those. 00:11:13.680 --> 00:11:17.020 And I'll just develop in that regardless of what my machine setup like. 00:11:17.020 --> 00:11:19.400 Well, that's on one hand like simpler. 00:11:19.400 --> 00:11:23.120 I say maybe Docker Compose up and boom, my little environment's working. 00:11:23.120 --> 00:11:29.420 But now I've got to figure out how does my editor do like remote debugging of Docker containers? 00:11:29.420 --> 00:11:35.140 And how do I like step across calls between containers in my debugger and all this other stuff? 00:11:35.140 --> 00:11:41.480 It's like, okay, so I've moved like setup complexity to like editor complexity or other stuff, right? 00:11:41.480 --> 00:11:42.020 So I don't know. 00:11:42.020 --> 00:11:43.160 It's super interesting. 00:11:43.160 --> 00:11:47.960 I'd certainly see them being really valuable for like zero downtime deployments and other kinds of stuff. 00:11:47.960 --> 00:11:49.340 But yeah, it's interesting. 00:11:49.340 --> 00:11:57.580 In my wacky corner of the universe, the place where I probably would use them is we often want to spin up a new build server or something like that. 00:11:57.580 --> 00:12:00.920 And we have it written down about how to build a build server. 00:12:00.920 --> 00:12:04.860 Even though it's on a virtual machine, we got to install a bunch of stuff. 00:12:04.860 --> 00:12:07.820 And it's a half a day to get it up and running. 00:12:07.820 --> 00:12:10.140 And having that just saved off. 00:12:10.140 --> 00:12:12.340 Yeah, that's a perfect example of Docker, right? 00:12:12.340 --> 00:12:15.460 Because you can build the container images to just do that setup. 00:12:15.460 --> 00:12:18.780 And you just say, you know, Docker build and boom, you're ready. 00:12:18.780 --> 00:12:19.740 Yeah, I like that. 00:12:19.740 --> 00:12:25.920 Speaking of containers and all those good things, let's talk really quick about DigitalOcean, some of the stuff they have to offer. 00:12:25.920 --> 00:12:33.580 So DigitalOcean just this week put their Kubernetes cluster into general availability and added some cool new features. 00:12:33.580 --> 00:12:36.640 So if you're using Docker, you've got to run it somewhere. 00:12:36.640 --> 00:12:39.040 And usually just running it directly is not what you want. 00:12:39.040 --> 00:12:45.220 You want to run it somewhere where you can upgrade versions and do zero downtime deployments and multi-container stuff. 00:12:45.220 --> 00:12:47.420 So Kubernetes is a great place for that. 00:12:47.540 --> 00:12:49.200 So check that out over at DigitalOcean. 00:12:49.200 --> 00:12:55.320 Just visit pythonbytes.fm/DigitalOcean and get $50 credit for new users. 00:12:55.320 --> 00:12:58.020 Yeah, so all sorts of cool stuff over there. 00:12:58.020 --> 00:13:01.760 You can provision your servers and optimize it and get it going. 00:13:01.760 --> 00:13:02.140 Right? 00:13:02.200 --> 00:13:03.080 Really, really nice. 00:13:03.080 --> 00:13:10.180 And one of the things they just added is free integrated monitoring that'll provide like insight across your clusters and your containers and stuff. 00:13:10.180 --> 00:13:11.160 So yeah, check them out. 00:13:11.160 --> 00:13:12.840 Pythonbytes.fm slash DigitalOcean. 00:13:12.840 --> 00:13:14.120 Super, super cool. 00:13:14.120 --> 00:13:18.380 So this next thing I want to cover, Brian, touches on something I've been a fan of for a long time. 00:13:18.380 --> 00:13:19.720 And that's design patterns. 00:13:19.720 --> 00:13:20.060 Okay. 00:13:20.160 --> 00:13:26.360 So design patterns, we talked a little bit about that previously, one of the shows just recently. 00:13:26.360 --> 00:13:32.800 But this time I want to focus on maybe a topic that is reversed from a lot of the advice that you hear. 00:13:32.800 --> 00:13:38.640 A lot of times you hear people say, hey, Python developers, stop using classes and stop using objects. 00:13:38.820 --> 00:13:41.120 Just write modules and functions, right? 00:13:41.120 --> 00:13:42.100 Yeah, sometimes. 00:13:42.100 --> 00:13:42.720 Yeah, sometimes. 00:13:42.720 --> 00:13:43.800 And that's totally reasonable. 00:13:43.800 --> 00:13:48.540 A lot of times people come from C# or Java where it's everything is an object. 00:13:48.540 --> 00:13:49.960 Everything has to be in a class. 00:13:49.960 --> 00:13:52.400 And so they think, well, I have to do that in Python. 00:13:52.400 --> 00:13:58.880 And if you've got a static variable in a class, that's, you know, just kind of like a module level variable in a function. 00:13:58.880 --> 00:14:00.660 Like there's no real value to breaking that apart. 00:14:00.660 --> 00:14:03.060 However, a lot of times there are. 00:14:03.060 --> 00:14:14.560 So there's a cool article that walks you through in super in-depth focused on sort of data science side of this object, no object debate called algorithms as objects. 00:14:14.560 --> 00:14:18.680 So it's usually we think of like algorithms as a single function with an input and an output. 00:14:18.680 --> 00:14:21.760 And algorithm textbooks reinforce this notion, right? 00:14:21.760 --> 00:14:24.460 Like everything fits nice onto a single page. 00:14:24.600 --> 00:14:35.060 But in reality, what you end up with are these like giant monolithic functions that are like full of details with lots of cyclomatic complexity and passing lots of data around and all sorts of stuff. 00:14:35.060 --> 00:14:36.600 And it's not nearly as nice. 00:14:36.600 --> 00:14:39.740 You end up with these functions that like lack readability. 00:14:39.740 --> 00:14:42.260 And because of that, they lack maintainability. 00:14:42.260 --> 00:14:45.920 Nobody wants to touch it because it's probably important. 00:14:45.920 --> 00:14:47.400 It's an algorithm, right? 00:14:47.400 --> 00:14:49.820 And if it's wrong, it's probably hard to tell if it's wrong. 00:14:49.820 --> 00:14:51.580 So you don't want to break it. 00:14:51.580 --> 00:14:53.960 It's just kind of scary, right? 00:14:54.240 --> 00:14:59.420 So they talk about taking these algorithms and turning them into functions. 00:14:59.420 --> 00:15:04.760 And one of the ideas I really like that they're starting with is like, well, should I do this or not? 00:15:04.760 --> 00:15:05.500 How do I know? 00:15:05.500 --> 00:15:08.060 So they talk about this idea of code smells. 00:15:08.060 --> 00:15:15.040 And the idea of code smells comes from Martin Fowler way back in the day, like 1999 or something like that when he wrote his refactoring book. 00:15:15.040 --> 00:15:21.700 And these are aspects of code that are not necessarily broken, but they're just like a little bit off. 00:15:21.700 --> 00:15:22.940 Have you heard of this idea, Brian? 00:15:22.940 --> 00:15:23.660 Yeah, definitely. 00:15:23.880 --> 00:15:25.140 It kind of makes you wrinkle up your nose. 00:15:25.140 --> 00:15:27.460 You're like, ew, something's not good here. 00:15:27.460 --> 00:15:29.060 But, you know, the code works, right? 00:15:29.060 --> 00:15:29.960 Like it would pass a test. 00:15:29.960 --> 00:15:30.740 So it's fine. 00:15:30.740 --> 00:15:39.440 So the code smells, they say, that you should be on the lookout for here are, number one, the function, the algorithm, the one giant function. 00:15:39.440 --> 00:15:41.680 It's too long or it's too deeply nested. 00:15:41.680 --> 00:15:43.740 Like we spoke about guarding clauses last time. 00:15:44.120 --> 00:15:45.380 Does it have banner comments? 00:15:45.380 --> 00:15:51.840 Like a huge comment at the top that describes what it does, how it works, the special cases, right? 00:15:51.840 --> 00:15:55.340 I often say that code comments are deodorant for bad code. 00:15:55.340 --> 00:15:57.440 So you should just write good code and not do that. 00:15:57.500 --> 00:15:58.460 So like that's an example. 00:15:58.460 --> 00:16:10.520 Helper functions that are maybe nested closures inside there, some weird thing like that, or maybe actual helper functions, but they're only used within this larger function. 00:16:10.880 --> 00:16:18.680 Passing a lot of states, all these things are sort of indicators that maybe an object would be much better for wrapping up your algorithm. 00:16:18.680 --> 00:16:22.300 So it's really, I think, got a lot of concrete advice here. 00:16:22.300 --> 00:16:23.900 This actually looks pretty interesting. 00:16:23.900 --> 00:16:24.760 It's super interesting. 00:16:24.760 --> 00:16:26.680 And it's full of examples. 00:16:26.680 --> 00:16:30.660 Like it's a really long article with lots of concrete examples of here's an algorithm. 00:16:30.660 --> 00:16:31.460 We did it this way. 00:16:31.460 --> 00:16:36.000 We refactor that to an object and look how much more understandable it is and how much simpler it is. 00:16:36.000 --> 00:16:40.140 So if this idea resonates with you, definitely check it out. 00:16:40.180 --> 00:16:49.380 And the guy who wrote it said, hey, when I present this idea to my colleagues or other folks, at first they're like, no, we shouldn't be using classes. 00:16:49.380 --> 00:16:50.480 Just functions will do. 00:16:50.480 --> 00:16:57.860 This is, you know, he encounters some pushback, but rarely does he encounter like prolonged pushback after people see the results. 00:16:57.860 --> 00:16:59.660 They're like, no, actually, this is pretty cool. 00:16:59.660 --> 00:17:00.580 I'm just chuckling. 00:17:00.580 --> 00:17:04.920 And one of the topics he has here is, I've got 99 problems. 00:17:04.920 --> 00:17:05.700 Give me two more. 00:17:05.700 --> 00:17:08.020 Yeah, it's a good article. 00:17:08.020 --> 00:17:08.960 Definitely check it out. 00:17:09.020 --> 00:17:11.200 If people are interested, it's very concrete and helpful. 00:17:11.200 --> 00:17:14.880 So, Brian, I know you're into testing and I know you're a fan of pytest. 00:17:14.880 --> 00:17:17.680 What are you into, like really small versions of pytest? 00:17:17.680 --> 00:17:18.280 Or what is this? 00:17:18.280 --> 00:17:27.320 I got into this because I've been using Python for testing purposes for since like a little out of like 2002 or something like that. 00:17:27.820 --> 00:17:32.940 There were often custom made Python frameworks or testing frameworks within our company. 00:17:32.940 --> 00:17:37.180 And then around 2010, I did the same thing and wrote my own. 00:17:37.180 --> 00:17:39.240 But it took me a while to get it down. 00:17:39.240 --> 00:17:45.480 I was arrogant and thought, oh, this would be trivial to because it's the basic algorithm isn't really doing much. 00:17:45.620 --> 00:17:55.260 But Oliver Best Balter, there was a comment somewhere on Twitter that the core of pytest could be written in like a couple dozen lines of code. 00:17:55.260 --> 00:17:57.600 And people were like, what, really? 00:17:57.600 --> 00:18:00.480 And so, of course, he's a brilliant person. 00:18:00.480 --> 00:18:01.560 He went out and just did it. 00:18:01.680 --> 00:18:04.060 So, he released a thing called Picopytest. 00:18:04.060 --> 00:18:09.220 It doesn't have a cert rewriting and it doesn't have like fixtures or any of the fun stuff. 00:18:09.220 --> 00:18:16.080 But it's a generally usable test framework that you could run some tests with written in 25 lines of code. 00:18:16.080 --> 00:18:16.480 Dang. 00:18:16.480 --> 00:18:20.320 And, you know, like the first five are just import statements or space. 00:18:20.320 --> 00:18:21.920 And one of them is a method. 00:18:21.920 --> 00:18:27.140 So, I think you could probably get it down to 19 if you were willing to go a little crazy on it. 00:18:27.140 --> 00:18:27.940 That's wild. 00:18:27.940 --> 00:18:31.040 So, some of the things that it uses are like import lib. 00:18:31.260 --> 00:18:41.900 Some of these things are clearly put in the language for tools like pytest and stuff like import libs, spec from file location, and module from spec. 00:18:41.900 --> 00:18:43.600 I don't know what those things do. 00:18:43.600 --> 00:18:50.820 But it looks like it's a way to sort of gradually load a module and then run parts of it because that's what this code does. 00:18:50.820 --> 00:18:57.900 One of the things I like about this and one of the reasons why I'm highlighting it is a lot of people think of test frameworks as this thing. 00:18:57.900 --> 00:18:58.640 They don't really know. 00:18:58.640 --> 00:19:00.240 It's a black box that does stuff. 00:19:00.840 --> 00:19:02.980 And I think this is a good way to highlight. 00:19:02.980 --> 00:19:09.040 It's not that this Python is very flexible and the heart of a test framework isn't that complicated. 00:19:09.040 --> 00:19:17.100 It's going out and finding files that match like a certain pattern, test underscore, and finding some functions inside those to call. 00:19:17.320 --> 00:19:20.700 And then just catching exceptions and logging failures. 00:19:20.700 --> 00:19:21.940 It's not that complicated. 00:19:21.940 --> 00:19:22.980 So, it's pretty cool. 00:19:22.980 --> 00:19:23.660 That's super cool. 00:19:23.660 --> 00:19:29.980 And I think anybody who cares about testing or maybe is being introduced to testing should read those 25 lines. 00:19:30.020 --> 00:19:36.380 Not necessarily for understanding, but just to get the sense of like, this is what happens when you run tests against your code. 00:19:36.380 --> 00:19:37.380 It finds your model. 00:19:37.380 --> 00:19:38.660 It loads up the functions. 00:19:38.660 --> 00:19:39.260 It calls it. 00:19:39.260 --> 00:19:40.800 It does this basic thing. 00:19:40.800 --> 00:19:41.800 And that's it. 00:19:41.800 --> 00:19:42.520 It's really nice. 00:19:42.520 --> 00:19:42.740 Yeah. 00:19:42.740 --> 00:19:43.280 Very, very cool. 00:19:43.280 --> 00:19:44.160 That is definitely... 00:19:44.160 --> 00:19:48.140 I don't know what the atomic unit of a test framework is, but that's nearly it. 00:19:48.140 --> 00:19:49.940 He popped this out in like two days. 00:19:49.940 --> 00:19:54.580 And it took me like two months to write my first version of my test framework. 00:19:54.580 --> 00:19:55.520 So, awesome. 00:19:55.680 --> 00:19:56.340 Yeah, super cool. 00:19:56.340 --> 00:19:56.820 Super cool. 00:19:56.820 --> 00:19:57.060 All right. 00:19:57.060 --> 00:19:59.440 Last one I want to cover has to do with Cython. 00:19:59.440 --> 00:20:01.240 Not CPython, but Cython. 00:20:01.240 --> 00:20:07.360 It's an article called An Introduction to Cython, the Secret Python Extension with Superpowers. 00:20:07.360 --> 00:20:09.660 And who wouldn't want an extension with superpowers? 00:20:09.660 --> 00:20:10.620 Yeah, exactly. 00:20:10.620 --> 00:20:14.800 They make the statement that they think Cython is one of the best kept secrets of Python. 00:20:14.800 --> 00:20:15.720 And I agree. 00:20:15.720 --> 00:20:22.080 Like, Cython will take almost arbitrary Python code and turn it into C. 00:20:22.080 --> 00:20:24.060 That right there is pretty impressive. 00:20:24.460 --> 00:20:29.540 If you have a, like, you've got some program and you find out like, oh, this part of, I 00:20:29.540 --> 00:20:33.940 don't know, some inner loop within an inner loop, you know, within another nested loop or 00:20:33.940 --> 00:20:35.580 something like that's a little bit too slow. 00:20:35.580 --> 00:20:41.980 You could probably write like a function in Cython that does that inner loop and make it 00:20:41.980 --> 00:20:43.180 way, way faster. 00:20:43.180 --> 00:20:44.680 Super cool. 00:20:44.680 --> 00:20:49.500 That's what we hear a lot about Python is you can take some slow parts in and then rewrite 00:20:49.500 --> 00:20:51.540 it and see if you need to. 00:20:51.540 --> 00:20:53.860 But you don't have to with Cython, right? 00:20:53.860 --> 00:20:54.300 Exactly. 00:20:54.300 --> 00:20:55.400 You don't have, that's the thing. 00:20:55.400 --> 00:20:56.760 You don't have to rewrite. 00:20:56.760 --> 00:21:02.460 You could rewrite it in C or in Rust or whatever, or you could just call Cython against it and 00:21:02.460 --> 00:21:08.140 make it, you know, it basically transpiles the Python into C and then compiles the C over 00:21:08.140 --> 00:21:09.420 to machine instructions. 00:21:09.420 --> 00:21:14.840 Now, depending on how you write your code, it may still interact with the Python interpreter 00:21:14.840 --> 00:21:16.460 and the Python gil or it might not. 00:21:17.100 --> 00:21:21.180 And that could actually significantly determine the performance benefits you get, right? 00:21:21.180 --> 00:21:25.700 So you can, it'll work with like an untyped item, but then it does it as a, I think, as a 00:21:25.700 --> 00:21:26.600 py object pointer. 00:21:26.600 --> 00:21:32.900 Whereas if you tell it this is an actual integer, it'll work with it as like a cint type of thing 00:21:32.900 --> 00:21:34.200 or something to that effect, right? 00:21:34.840 --> 00:21:39.240 So you get all sorts of benefits that'll, or, you know, ways to overcome shortcomings of 00:21:39.240 --> 00:21:39.500 Python. 00:21:39.500 --> 00:21:46.000 Say, for example, we talked about execution speed, but there's also a keyword in Cython that says, 00:21:46.000 --> 00:21:47.060 that's called no gil. 00:21:47.060 --> 00:21:52.420 So you can just create a context block in Python effectively say with no gil colon. 00:21:52.780 --> 00:21:56.320 And then that stuff works without the gil in threads. 00:21:56.320 --> 00:21:57.160 And that's it. 00:21:57.160 --> 00:22:02.440 You're just guaranteeing that that stuff isn't going outside of it or anything. 00:22:02.440 --> 00:22:08.000 What the requirement for using that keyword is, and if it doesn't match these requirements, 00:22:08.000 --> 00:22:14.020 it's like a compiler error for Cython, the Cython compiler, is that you don't interact with 00:22:14.020 --> 00:22:15.280 any Python objects. 00:22:15.280 --> 00:22:15.660 Okay. 00:22:15.660 --> 00:22:21.440 So you basically got to cast them into Cython native objects that can be represented in C. 00:22:21.640 --> 00:22:25.620 And then there's no reason for the gil because the gil's point, the purpose of the gil is 00:22:25.620 --> 00:22:30.040 to interact with the reference counting to make sure that that works in Python's object 00:22:30.040 --> 00:22:30.920 garbage collector. 00:22:30.920 --> 00:22:33.960 But if you're not working with Python objects, you don't need the gil. 00:22:33.960 --> 00:22:37.200 So it's a really great way to free up speed and whatnot. 00:22:37.200 --> 00:22:41.260 They talk about some of the projects written in Cython. 00:22:41.260 --> 00:22:47.480 So spaCy, the natural language processing, uv loop, which is a really fast asyncio event loop, 00:22:47.480 --> 00:22:51.600 significant parts of scikit-learn, numpy, pandas, all that kind of stuff. 00:22:51.600 --> 00:22:56.420 So I think the big value, like you said, is like you could go rewrite it in C, or you 00:22:56.420 --> 00:23:00.980 could just use Cython and make your Python run somewhat like C. Pretty cool. 00:23:00.980 --> 00:23:04.880 I actually want to play with this a little bit because I'm glad you found this article. 00:23:04.880 --> 00:23:06.100 Yeah, the article is super interesting. 00:23:06.100 --> 00:23:08.960 One thing that I've noticed, I mean, I didn't read it. 00:23:08.960 --> 00:23:13.800 I didn't like super inspect every code example, but I didn't see them using Python's type 00:23:13.800 --> 00:23:14.360 annotations. 00:23:14.360 --> 00:23:14.780 Right. 00:23:14.780 --> 00:23:20.300 So they're using like the C def to define types and like special Cython ways to define 00:23:20.300 --> 00:23:20.960 types. 00:23:20.960 --> 00:23:27.400 But the more modern versions of Cython, you can just say like value colon int equals something, 00:23:27.400 --> 00:23:31.300 you know, like the standard Python way of saying what a type is for type checking. 00:23:31.620 --> 00:23:36.200 And that'll actually also be understood and used by Cython for like native types. 00:23:36.200 --> 00:23:36.520 Okay. 00:23:36.520 --> 00:23:40.720 That's the question I had was, can you use native Python types? 00:23:40.720 --> 00:23:43.640 The answer used to be no, but now the answer is yes. 00:23:43.640 --> 00:23:44.380 Right. 00:23:44.380 --> 00:23:45.280 So, yeah. 00:23:45.280 --> 00:23:46.000 So it's super cool. 00:23:46.000 --> 00:23:46.980 All right. 00:23:46.980 --> 00:23:50.520 Well, if you think you need your Python code to go a little faster, check out this article, 00:23:50.520 --> 00:23:51.200 check out Cython. 00:23:51.200 --> 00:23:52.100 And it's pretty awesome. 00:23:52.100 --> 00:23:53.460 Just a good reminder, I guess. 00:23:53.460 --> 00:23:55.200 We both have a few extras. 00:23:55.200 --> 00:23:56.420 How about you kick off that section? 00:23:56.420 --> 00:23:57.020 Sure. 00:23:57.020 --> 00:24:01.340 I didn't really want to highlight this for too long, but he, Nick, wrote an article called 00:24:01.340 --> 00:24:02.600 The Price of the Hallway Track. 00:24:02.600 --> 00:24:04.440 It's just a reminder to everybody. 00:24:04.440 --> 00:24:10.500 I mean, we do hear about using, going to things like PyCon and other conferences and not actually 00:24:10.500 --> 00:24:13.060 going to the talks, but doing hallway stuff. 00:24:13.340 --> 00:24:17.000 He's pointing out that that's kind of lame for all the speakers that work really hard 00:24:17.000 --> 00:24:17.720 to do that. 00:24:17.720 --> 00:24:24.280 It's also, even if you intend to watch it later, it's disheartening for people to speak to an 00:24:24.280 --> 00:24:26.280 empty room or even a mostly empty room. 00:24:26.280 --> 00:24:32.280 And he's just asking, you know, don't fill up your day with talks, but pick some, especially 00:24:32.280 --> 00:24:37.520 ones that from people that are lesser known people and that sound interesting to you and 00:24:37.520 --> 00:24:38.520 at least go to a few talks. 00:24:38.520 --> 00:24:39.800 And I think that's a good advice. 00:24:39.800 --> 00:24:40.940 I'm going to try to do that next year. 00:24:40.940 --> 00:24:41.380 Yeah, cool. 00:24:41.380 --> 00:24:41.980 And what else? 00:24:41.980 --> 00:24:47.880 The second one is, who put Python in my Windows 10, May 19 update by Steve Dower. 00:24:47.880 --> 00:24:55.280 We did talk about this in the previous episode, but it is officially out and people are noticing 00:24:55.280 --> 00:24:55.480 it. 00:24:55.480 --> 00:24:55.680 Yeah. 00:24:55.680 --> 00:24:59.500 And Steve gave us a shout out to the Python Bytes episode we did together right there in 00:24:59.500 --> 00:25:00.360 the first paragraph. 00:25:00.360 --> 00:25:01.260 So thanks for that, Steve. 00:25:01.260 --> 00:25:02.260 This is massive. 00:25:02.260 --> 00:25:08.660 This is Windows 10 is shipping with Python 3 and that version of Python 3 is auto updating. 00:25:08.660 --> 00:25:09.820 Like, how cool is that? 00:25:09.820 --> 00:25:10.160 Okay. 00:25:10.160 --> 00:25:11.480 Within a major version. 00:25:11.480 --> 00:25:13.160 Yeah, but it ships within a little stub. 00:25:13.160 --> 00:25:15.000 So you don't get Python right away. 00:25:15.000 --> 00:25:16.700 You get a little thing that pops open. 00:25:16.700 --> 00:25:20.260 If you type Python, it pops open on the app store to download it. 00:25:20.260 --> 00:25:22.560 It doesn't ship with it because it doesn't need to. 00:25:22.560 --> 00:25:27.300 And still a lot of people, like, you know, a lot of people don't need Python, but that makes 00:25:27.300 --> 00:25:27.700 it easier. 00:25:27.700 --> 00:25:30.780 I guess when I say ships with, I mean from a user's perspective. 00:25:30.980 --> 00:25:35.720 Like, if you tell a user to go through a tutorial and you tell them to type Python 3 and they 00:25:35.720 --> 00:25:39.820 sit down and they type it, rather than getting error, it says, oh, you have to click this button 00:25:39.820 --> 00:25:40.720 for this line to work. 00:25:40.720 --> 00:25:42.200 They click the button and then it works. 00:25:42.200 --> 00:25:42.640 Like that. 00:25:42.640 --> 00:25:43.580 Yeah, exactly. 00:25:43.760 --> 00:25:44.880 I wouldn't ask for more, right? 00:25:44.880 --> 00:25:45.680 That's really cool. 00:25:45.680 --> 00:25:45.940 Yeah. 00:25:45.940 --> 00:25:46.440 How about you? 00:25:46.440 --> 00:25:47.040 Got any extras? 00:25:47.320 --> 00:25:47.600 Yeah. 00:25:47.600 --> 00:25:50.760 I got also something super small, a Pico thing. 00:25:50.760 --> 00:26:02.640 So Matt Trentini sent over a cool project called the Tiny Pico, which is an ESP32-based board. 00:26:02.640 --> 00:26:07.520 So a tiny little board that has first-class support for MicroPython. 00:26:07.520 --> 00:26:12.400 So Brian, if you click on that link, if you check this thing out, it's pretty wild. 00:26:12.400 --> 00:26:14.280 It's a project you can order. 00:26:14.280 --> 00:26:16.120 It's pretty cheap, like $26. 00:26:16.960 --> 00:26:18.080 It's so small. 00:26:18.080 --> 00:26:19.000 It's incredible. 00:26:19.000 --> 00:26:21.060 It's like two-thirds the size. 00:26:21.060 --> 00:26:24.340 So 60% of a AA battery. 00:26:24.340 --> 00:26:30.600 I mean, like maybe, you know, like the middle part of your pinky or something. 00:26:30.600 --> 00:26:34.660 I mean, it's a really small board, like both the width and the height. 00:26:34.660 --> 00:26:35.620 That is crazy. 00:26:35.620 --> 00:26:37.200 But listen to its specs. 00:26:37.200 --> 00:26:39.620 32-bit dual-core processor. 00:26:39.620 --> 00:26:45.740 Full-on Wi-Fi, 8211BGNN, Bluetooth. 00:26:46.600 --> 00:26:47.380 All sorts of stuff. 00:26:47.380 --> 00:26:49.480 Like for $26 at that size. 00:26:49.480 --> 00:26:50.360 It's so cool. 00:26:50.360 --> 00:26:52.900 So I want to give a shout out. 00:26:52.900 --> 00:26:54.340 MicroPython's pre-installed. 00:26:54.340 --> 00:26:55.200 That's cool. 00:26:55.200 --> 00:26:56.100 Isn't that super? 00:26:56.100 --> 00:27:01.060 So if people are looking at embedded stuff and little devices, things, this is really, really cool. 00:27:01.060 --> 00:27:01.380 Yeah. 00:27:01.760 --> 00:27:03.720 Good for your next spy cam project. 00:27:03.720 --> 00:27:04.340 Exactly. 00:27:04.340 --> 00:27:08.900 I got another one from Automation Panda, who we met at PyCon. 00:27:08.900 --> 00:27:10.340 And this is Andy. 00:27:10.340 --> 00:27:17.700 And he wrote a cool PyCon 2019 reflections, which I thought if you haven't been to PyCon, check out this article. 00:27:17.700 --> 00:27:21.120 It's like kind of his diary of like what he did and his experiences. 00:27:21.120 --> 00:27:23.460 It's like his second PyCon he ever went to. 00:27:23.460 --> 00:27:26.120 So it was kind of a fresh take on PyCon, which is great. 00:27:26.120 --> 00:27:27.000 That's cool. 00:27:27.000 --> 00:27:27.280 Yeah. 00:27:27.280 --> 00:27:27.520 Yeah. 00:27:27.520 --> 00:27:28.300 It was fun to meet him there. 00:27:28.760 --> 00:27:31.900 I just want to give a quick shout out to our Patreon page, which we don't do that enough. 00:27:31.900 --> 00:27:35.560 So if people want to support the show, obviously visiting the sponsors helps a lot. 00:27:35.560 --> 00:27:40.700 But you can help support with editing fees and other stuff by doing small contributions. 00:27:40.700 --> 00:27:44.620 So there's a link at the bottom of this episode to say here's the Patreon page. 00:27:44.620 --> 00:27:45.640 So people can check that out. 00:27:45.640 --> 00:27:48.160 And Brian, thanks to you for putting that together. 00:27:48.160 --> 00:27:53.120 And one of the things people get is the show notes emailed directly to their inbox if they do that. 00:27:53.120 --> 00:27:53.680 That is awesome. 00:27:54.100 --> 00:27:59.640 And then I just wanted to let people know I'm doing a free one hour webcast in a couple of weeks. 00:27:59.640 --> 00:28:03.180 And the title of the webcast probably more or less sums it up. 00:28:03.180 --> 00:28:07.220 But it's 10 tools and techniques Python web developers should explore. 00:28:07.220 --> 00:28:08.140 That looks interesting. 00:28:08.140 --> 00:28:08.540 Yeah. 00:28:08.540 --> 00:28:10.180 So it's all sorts of fun stuff. 00:28:10.180 --> 00:28:11.420 Like Docker is one of them. 00:28:11.420 --> 00:28:12.420 Vue.js is another. 00:28:12.420 --> 00:28:16.280 You know, Vue models and other sort of design patterns as well. 00:28:16.280 --> 00:28:19.340 A lot of fun things that people haven't maybe seen there. 00:28:19.340 --> 00:28:19.660 Yeah. 00:28:19.660 --> 00:28:21.740 Let's let you kick it off with our joke section. 00:28:21.740 --> 00:28:22.660 What do you got for us? 00:28:22.820 --> 00:28:24.500 Oh, you're going to give it to me. 00:28:24.500 --> 00:28:26.060 I'll steal one of your jokes. 00:28:26.060 --> 00:28:26.880 Yeah, steal it. 00:28:26.880 --> 00:28:27.060 Okay. 00:28:27.060 --> 00:28:27.700 Okay. 00:28:27.700 --> 00:28:29.240 What do you call eight hobbits? 00:28:29.240 --> 00:28:31.560 A hobbite. 00:28:31.560 --> 00:28:33.120 Oh, that's terrible. 00:28:33.120 --> 00:28:34.400 It's so bad. 00:28:34.400 --> 00:28:35.240 It's so bad. 00:28:35.240 --> 00:28:36.200 It wrapped around to good. 00:28:36.200 --> 00:28:38.820 It's like badness overflowed into the good level. 00:28:38.820 --> 00:28:40.500 What do you call eight hobbits? 00:28:40.500 --> 00:28:41.080 All right. 00:28:41.080 --> 00:28:43.060 So I got another one for you. 00:28:43.060 --> 00:28:44.600 This one may also be bad. 00:28:44.600 --> 00:28:46.600 This is a little more on the science-y, math-y side. 00:28:46.600 --> 00:28:49.860 Not quite programming, but it definitely has a computational bit to it. 00:28:50.460 --> 00:28:54.280 So you know Mandelbrot, Benoit B. Mandelbrot is his full name. 00:28:54.280 --> 00:28:58.160 The guy who came up with the Mandelbrot set and fractals and all that kind of stuff, right? 00:28:58.160 --> 00:28:58.480 Yeah. 00:28:58.480 --> 00:29:03.500 And one of the core principles of fractals is no matter how much you zoom into them, there's 00:29:03.500 --> 00:29:09.120 like always more details and often times there's like super weird reasons that it like repeats. 00:29:09.120 --> 00:29:13.280 Like you zoom way into the little branch of the Mandelbrot set, there's like a baby Mandelbrot set. 00:29:13.280 --> 00:29:13.740 Yeah. 00:29:13.740 --> 00:29:14.200 Okay? 00:29:14.200 --> 00:29:15.140 Yeah. 00:29:15.140 --> 00:29:21.540 So the question is for Benoit B. Mandelbrot, what is his middle name? 00:29:21.540 --> 00:29:22.500 What does the B stand for? 00:29:22.500 --> 00:29:25.360 Well, it stands for Benoit B. Mandelbrot. 00:29:25.580 --> 00:29:26.740 Of course it does. 00:29:26.740 --> 00:29:29.640 Yes. 00:29:29.640 --> 00:29:30.480 Oh, I love it. 00:29:30.480 --> 00:29:30.880 All right. 00:29:30.880 --> 00:29:32.320 Well, I guess we're going to leave it. 00:29:32.320 --> 00:29:33.360 We got to do the other one. 00:29:33.360 --> 00:29:33.980 It's so great. 00:29:33.980 --> 00:29:34.400 All right. 00:29:34.400 --> 00:29:34.680 Go for it. 00:29:34.680 --> 00:29:34.880 Okay. 00:29:34.880 --> 00:29:36.320 So two bites meet. 00:29:36.320 --> 00:29:38.700 The first bite asks, are you ill? 00:29:38.700 --> 00:29:42.600 And the second bite replies, no, just feeling a bit off. 00:29:42.600 --> 00:29:46.920 Totally left shift on that one. 00:29:46.920 --> 00:29:47.820 Yeah, absolutely. 00:29:47.820 --> 00:29:49.560 Beautiful. 00:29:49.560 --> 00:29:49.880 All right. 00:29:49.880 --> 00:29:52.260 Well, thanks as always for being here, Brian. 00:29:52.260 --> 00:29:54.220 It's a lot of fun to talk about these and share them with everyone. 00:29:54.220 --> 00:29:54.540 Yep. 00:29:54.540 --> 00:29:54.940 Bye. 00:29:54.940 --> 00:29:55.200 Yep. 00:29:55.200 --> 00:29:55.360 Bye. 00:29:55.360 --> 00:29:57.160 Thank you for listening to Python Bytes. 00:29:57.160 --> 00:29:59.700 Follow the show on Twitter via at Python Bytes. 00:29:59.700 --> 00:30:02.560 That's Python Bytes as in B-Y-T-E-S. 00:30:02.560 --> 00:30:05.800 And get the full show notes at pythonbytes.fm. 00:30:05.800 --> 00:30:10.000 If you have a news item you want featured, just visit pythonbytes.fm and send it our way. 00:30:10.000 --> 00:30:12.700 We're always on the lookout for sharing something cool. 00:30:12.700 --> 00:30:15.800 On behalf of myself and Brian Okken, this is Michael Kennedy. 00:30:15.800 --> 00:30:19.240 Thank you for listening and sharing this podcast with your friends and colleagues.