« Return to show page
Transcript for Episode #180:
Transactional file IO with Python and safer
00:00 Hello, and welcome to Python bytes where we deliver news and headlines directly to your earbuds. This is Episode 188 believe it recorded April 29 2020. It's almost made a I am Brian Aachen and Michael Kennedy in this episode is brought to you by Digital Ocean. And we'll talk more about them later. Well, I have some very timely news, because not very long ago, a couple days ago, a boon to 2004 is out. Work. All right, yeah, the new Ubuntu. And it's why is this big news? Well, there, there's a lot of releases of Ubuntu and whatnot. But this is the first new LTS long term support version in two years. So basically, this is the first like real production grade version of Ubuntu that's been out in two years. So that's a big deal, I think, Oh, yeah, really big deal. And it's got something special in it does. It hates legacy Python, but it loves modern Python. So one of the things is bugged me about 1804, which is what I've been using for production is it was stuck on three, six, I mean, imagine, April 2018. It's using Python three, six, it didn't change. Well, what's the current version now? Well, that's Python three, eight. Sadly, three, nine is gonna be out really soon. And this is three, eight. But nonetheless, hey, three, eight is awesome. It has a bunch of cool new features that we can use. And yeah, it comes included. I don't even think you have to pip install Python. I think three, eight. It's already there. That's really cool. Yeah. And to get legacy Python, you can get it. But you have to go like apt install it explicitly to say, No, I want the old one. But then three, eight, automatic is now everywhere. That's right. Like, it's time to hit all your code with Flint, and auto f string, all the things. So upgraded. All of the servers for Python by servers are pretty small and simple. But if you look at all the stuff that I'm running, there's actually a ton of servers. And I actually talked about that with Dan Bader, on talk Python, Episode 215. So people really want to look in what we're doing what I'm doing here, what we're doing for Python bytes. In terms of infrastructure, they could do that, but upgraded a bunch of servers to 2004. There's a bunch of stuff that kind of built up cruft. And I'm like, Oh, we could do this way better. Read it, all that stuff over the weekend. And so now everything's on the shiny new versions of Python three, eight, and a boon to 2004. And it went really well for me. So that's great. Yeah, in the kernel has been upgraded to five four, which add support for wireguard VPNs. better support for like Raspberry Pi's and Intel and AMD hardware, new version of gnome, you can install the desktop on top of the ZFS filesystem. If you care about that. And you talked about digitalocean the top, you can go to digitalocean right now and just check off. I want a new 2004 droplet. Boom, off it goes. That's how I got ours. Oh, that's great. Nice. Yeah. And actually, we've already had the kernel upgraded. The five four Colonel upgraded to like a new version. I just had to like apply the patches. So I guess it's pretty active. But here you go. Is it so yeah, different topic. But for our servers, you have to, like pay attention to kernel upgrades and stuff. Yeah, apparently. Yeah. They're not like on a platform as a service type of thing. It's not a big deal. It's, it's pretty regularly, like once a month or whatever. I'm usually logged in to one of them every couple days doing something and it'll say, oh, like either it's already applied. It says you got to reboot it. It'll be like, obvious that there's an update when you log in. And they're like, Oh, I should just run that thing that upgrades all of them. Okay, once I notice it, yeah. So pretty much Yeah. Okay. Neat. Yeah. Okay. Well, I'm gonna switch hats. So
03:42 I want to talk about warnings. So warning, I'm going to switch a hat. And so Rubin learner is a friend of the show and great guy teaches Python. And we wrote an article called working with warnings in Python. And I, I like this, because I don't think we've talked about warnings much, no, not much at all. Actually, it's a good introduction. But he talks about exceptions, and the class hierarchy and print outs and stuff. But if you want to like if something goes wrong, you kind of want you've got options of like printing out to the user or throwing an exception, but you also have warnings, and how should you treat those. And I love what he wrote. He said, most of the time, warnings are aimed at developers rather than users. Warnings in Python are sort of like the service needed light on a car. user might know that something is wrong, but only a qualified repair person will know what to do. developers should avoid showing warnings to end users. But one of the things that the warning system is used for is what deprecation warnings, a lot of projects do this where they kind of want to get rid of a feature. So they can refactor some stuff. And or just doesn't fit in the API very well. So deprecate it, and they'll issue a deprecation warning when somebody uses it. So it's a no it doesn't stop working, but it alerts people to that there's a warning. One of those things
05:00 things I love about warnings is by default pi test turns on warnings. And so you can see those and you can also make them make pi tests so that it fails on warnings. So this is a good thing to pay attention to. But it doesn't stop your project. I'm glad you know, you can make pi tests like observe and use the warnings as air. Yeah, the warning system gives you a whole bunch of stuff pythons warning system, it treats warnings as separate types of output, so that we don't confuse them with either exceptions or printed texts. It lets us indicate what kind of warning we're sending the user. So we have different types. It's like the exception hierarchy, you can have a more there's a warning hierarchy, you can create your own, and you can filter on them so that you can screen out stuff they don't care about, selectively fix things. Anyway, it's a very powerful system, people should use it when they need it. The article goes on to give specifics on the syntax of how to use them how to create warning, custom warnings, and how to filter on them. And it's a good intro. Yeah, this looks super interesting. And like something I should be paying more attention to than I have so far is something I'm not really using. It's I'm more a consumer of warnings, I'm like, oh, that library, it started issuing warnings about something. And sometimes it's really frustrating because it's like, the library being used by the library I'm actually trying to use is doing something wrong. It says, Well, this is going to be deprecated. And now you got to do this and like well, but I'm not doing that. I don't want to see this. But nonetheless, it's it looks like way simpler. And maybe I just haven't looked at it, it looks great. So I should use this more. One of the cool use cases that I heard recently is I'm using pi tests, warnings, or pi tests, knowledge of warnings, and testing your system when you're upgrading Python. So that you can say, oh, when we're because Python will deprecate things too. And then you can have a head heads up that you need to start fixing your code, because it'll pinpoint you Exactly. It's kind of like the exception system, it tells you exactly where it's coming from. So yeah, that is really nice to know something else. That's nice. digitalocean Digital Ocean is very nice. And digitalocean just launched their virtual private cloud or VPC system, and new trust platform, whoo trust platform. Together, these make it easier to architect and run serious business applications with even stronger security and confidence. VPC allows you to create multiple private networks for your account, or your team. Instead of having just one private network digitalocean can auto generate your private networks, IP address range, and or you can specify your own IPS. You can now configure droplets to have to behave as Internet gateways. That's cool. Yeah, it's like your own little baby internet. Yeah, that's neat. And trust platform is a new micro site that provides one place to get all your security and privacy questions answered, and download our available security certifications. digitalocean is your trusted partner in the cloud visit Python bytes.fm slash digitalocean. To get $100 credit for new users to build something awesome. We'd love it. Like I just said, Put boo do 2004 on there. And it's been working great for so many years. Now. One thing that I ran across, there's a few little libraries that are so simple. And yet when you come across them, you're like, Oh, yes, this is so cool. One of those that I go on and on about is unsync how that unifies all the different API's that do asynchronous programming, like async IO threaded, stuff, multiprocessing stuff and whatnot. Right? So this is one, I think that kind of is like that. It's not about unification. But it's about solving a problem in a way that's kind of transparent to the user. But is really, really awesome, because it just adds some nice durability to your code. So there's different levels of like exception handling, if you look at it, right. So if you look at code, there's probably like the beginner level that has no try except blocks anywhere in the code. It's just like, I don't know what you call that optimistic programming. Like, I don't need to do error handling, it's gonna be fine, everything's fine, this is fine. That's one way. The next level would be to say, Okay, I'm gonna have some exception handling, do a try do a bunch of stuff, except handle the error, right? That's good. And maybe you're catching different errors. Like maybe that's another level. I don't know what the make of these levels up a little bit. But even if you are catching an error, something could have gone terribly, terribly wrong and corrupted your data along the way. So there's like durable error handling and there's it isn't technically crashing at the moment error handling, right. So the durable error handling I don't think a lot of people think about nearly as much. So simple example, is what you would maybe use a transaction for in a database is like I'm going to transfer money from this account to that account. But what happens if the transfer to the second account fails?
10:00 Want to make sure I don't actually take the money from the first account, right? Or I want to write some piece of data to a file. So I'm going to open the file, and make sure to try except I'm gonna put it in a width block. So the file pointer gets closed, everything's good. I'm going to make one change and another change. And the third James, like write these three things to the file. What if the exception happens after the second line? You have written to the file. Now? No, wow, that's bad, right? So there's, there's all these ways in which like, you still have a try, except you still catch it, you so close the file pointer, it doesn't matter. It's corrupted, right? So there's like this another level of error handling of like, kind of treating memory and files and whatnot as transaction transactional type things, right? If there's an error, they just go back the way they were. And so this thing that this long winded introduction is about is called safer. So a safer file writer. And it's this cool, simple little thing. Instead of saying with open file name as file pointer, you say with safer dot open file name as file pointer, and then otherwise, all your code is identical. Okay? Okay, here's what it actually does. So as you write to the file pointer, it's writing to a temporary file behind the scenes. And then if you know, when you exit a with block, the width block the exit, the Dunder exit takes whether or not there was an error on the way out the door. So you know, as you exit, the width block did is am I leaving because a crash? Or am I leaving, because everything is cool, and we're done. So it uses that information to either throw away the temp file, or move the temp file over top? The thing you thought you're writing on? Oh, isn't that cool? So if there's an exception in your width block, it still closes up the file pointer and everything, but your data is unchanged. It's kind of like a transaction with a real auto rollback for files. That's pretty cool. Isn't that cool? And it's like, 28 lines of code that does that little bit? Yeah. Is it any idea what the time it is, it's got to be a little bit, but it's pretty small, because it just uses sh utils. To replace the file, if I get writes to the file, just as you would write to the file. And then at the very end, it goes move this file to this destination and overwrite. So it's basically adds a file move, which an SSD is like, nothing, right? Okay. It doesn't matter how big it is. It probably just like updates the I don't know, like the the table in the drive, whatever that means. Yeah, in that cool. That is very cool. I like it. Yeah. So it seems so easy to use, it looks like something that might be worth looking at. So I'm linking to a couple of things. I'm linking to an article that introduces this. And in the beginning, apparently there was like some edge case where something wasn't working quite right. If you passed, like then an integer representing a file handle or something funky like that. It didn't deal with that, right? So there's a another, like an updated article that doesn't have all the motivation, but then talks about this fix. And there's also a GitHub repo and you can just pip install it. So all those things are good. And the final in this section, I'm linking to the actual 28 lines of code. Do you have that open? Did click on that really quick, because I wanted to talk about a couple of really interesting patterns here. Like, if you wanted to study 28 lines of code that took in brought together a bunch of interesting ideas, like, wow, this is pretty crazy. So it has a generator expression on an infinite sequence of numbers to find the temporary file, which is pretty interesting. Because it just says I'm gonna call it dot one, dot two dot three, and in case it does exist, we're just gonna go through all of them until one doesn't. Isn't this crazy? So that's pretty fun. And it uses sh utils to copy the file over, which is pretty cool. It uses yield to automatically return the inner file pointer. So when you say with thing as whatever, even though you said safer dot open, it actually yields out the underlying pointer file pointer that came from open. There's just a bunch of different layers of Oh, that's interesting. That's neat. Yeah. Anyway, I think this is really clever. And it seems like a cool little library. It's the reason I think it would probably be useful and not going to give you a big hit. It's like this is literally it. You can see it's creating a temp file, it writes to the temp file, and then it uses OS dot rename the temp file to the actual thing. So, you know, not a whole lot of magic going on, but really quite useful. I think. Not a lot of code either. Yeah, just yeah, in that case. Yeah. That's pretty cool. I love it useful. Gives You That sort of durable error handling, almost like transactional files. And yet, super simple, very good uses unit test as its test runner though. Oh my god. Well, alright. I retract all of my endorsements of this thing.
14:47 Alright, what's the next one? Okay. I'm on the other tab. So did I distract you? Oh, yeah, you did. In new article, new hat. So code spell though.
14:58 I got this from
15:00 Kristian Klaus, that silly little project I play with inside code cards, I got a pull request against the project to add a pre commit hook to run code spell. And I had never heard a code spell. So I was excited to have a new topic for the podcast. Also, just this is neat. So code spell, what it does is it fixes common misspellings in text files. And specifically, it's designed primarily for checking misspelled words in source code, but it can use be used as other files as well. When Krishnan applied this to the cards project, it noticed that in one of the documentation files, I've got one of the markdown files, I had spelled arguments with an extra u in the middle of it. And one of the problems with spelling. I mean, it's embarrassing to do and distracting to have to have spelling errors in your in your code or your comments or anything. It's hard to deal with because a lot of like, you know, a lot of source code doesn't have, you can't just throw normal spell checkers at source code because it'll just it'll warn you on your variable names and all sorts of stuff, right? You can't drop it and Grammarly as well. It's not gonna work. But so I'm really excited to try this and and to start using it. Because if it can work for just about anything like you might be able to work for, you know, non Python programs, too, as well. Why not? So yeah, it's pretty all sorts of documentation. That's cool. It's a open source project. The GitHub repo has the entire dictionary, so you can scan through it. And there's ways to ignore certain words, if you're like, no, that's the correct spelling, and it keeps doing stuff you can write ignore it. Nice. Well, that's a really good one, the most embarrassing misspelling I've ever done in code was i'd misspelled like a namespace, or a class name, or package name, or something like that. I can't remember quite where it was.
16:54 But it was on a project I had been working on for like a year, and I misspelled it, but everything was autocomplete. And so I don't care. I'm like data is just like, okay, autocomplete. I'm not even like ever typing that again, right? Yeah, I guess I just wasn't paying attention to like that. I kind of suck at spelling. That was like an extra bad case. Some new person came on the team and said, Dude, why is this misspelled all over the place? Like, Oh, we got to fix it. But it was like, other applications depended on that library. And they use the misspelling, it was so bad, because it was like it had become pervasive throughout like all these different things like, we may have to leave that misspelled I think we eventually fixed it, but it was like, it was a quite a bit of work considering what it should have been. That's funny. Yes, awesome. Well, at least you didn't have like both of the Spelling's be valid symbols in your program and mean completely different things. That's true.
17:47 Yeah, so one of the things that's awesome about this podcast is we'll say we'll find some random thing, or maybe somebody will send it to us. And we'll say, oh, did you even know that this was a thing? I'd never heard of this. And then like five other people shoot us a message and say, yeah, and this variation or this other thing, and that's cool. But there's also X, Y and Z. Right? And that awesome. Yeah. Yeah. I learned so much by doing this. Yes, I know. We just got to throw something we vaguely know about and like people, correct us. Yeah. Awesome. So no, seriously, we talked about profilers. And I talked about scalene. How it was really nice and fast. And it did memory profiling and all that. Well, for another show. Anthony Shaw said, Hey, since you're on this kick, for profilers, have you heard about Austin? To me, Austin is either a guy's name or a town in Texas. I hadn't heard about Austin, have you got a neighbor named Austin? Yeah, I don't think this is the same thing. So this is like scaling is a frame stack sampler for C Python, meaning it doesn't have like this huge effect of once you run it on your code, it doesn't become 10 times slower, as instrumenting versions do. You know, I just asked like, Hey, what are you up to really quickly. So that's cool. It's nice and fast. It also is just pure C code. There's no real dependencies like other than like the C runtime, which is in all the operating systems. So it looks at running Python code intervals, and then it dumps out whatever it finds, which is cool. It has a really simple output. But as you will learn, it has all these interesting ways to visualize that output. So it sort of base its atomic unit of output is a flame graph. So a flame graphs are like, stacked up sort of things that are colorful, and they also have information. So like the color communicates information and the height. So it's kind of like a graph with like color bars type of thing. And it has the parser code that running if you want to see what that is just click on the link and it has it right there at the top. And that's cool. So it puts that out. But you can build other tools to analyze that. Or you could even make like a little player application that replays the execution of your application and like slow motion, like replays that flame graph over time. And let's see in that cool, yeah, so now is where it gets
20:00 Really fun because there's a couple of user interfaces on top of this, like simple output that can be interpreted. So the first one is called the to E, the terminal user interface. Do you see this animated in our little show notes and will be nice. Yeah, that's really cool. Yeah. So let me try to describe it. Like imagine you've opened, I don't know, Emacs or something like that. But the top part of it shows the process information, the CPU, it's using the memory it's using, how long it's been running. And then a graph an active like interactive flowing graph across the top of like, the performance analysis. And then it has something that's a little bit like top maybe showing you like, what it's currently running, how much time it's using, is this time being spent on a sub function call like that I call a thing that called requests that is talking to the network. And that's why it's slow because we're waiting on the internet, or is it actually computationally my stuff running in Python or whatever? Right. So what do you think that's cool, huh? Yeah, that bottom part reminds me of the thing that you put the Process Explorer on Windows, you look at all the processes. Yeah, a little bit like Task Manager, but it's actually for like, your functions instead of other processes. Yeah, yeah. That's nice. That's cool. So that's the to E, which is going to be a popular one. But you may also want to be on the web. So there's web Austin, which is another example of making this for the web. So you basically can log in to wherever you're running it, connect to it. And it has a d3 flame graph that's like animated of what your web app or whatever process you're watching on that remote system is up to. So it's kind of the same thing. But like more visual, yeah, graphical, like the flame graph is there, and whatnot. So that's pretty cool. People can check that one out, you can even pause it, and whatnot. Then finally, there's this other format called speed scope, which can be visualized in other tools. And you can convert Austin output into the speed, scope, JSON format. And there's a sample for that in the repo. If you go look at that you can load it into the speed, scope, visualizer type of things and have another way to view the data. So this is really nice, because so many of these profilers are like, we collected all this information. How would you like it as a CSV? Or how would you like it as just like random columns in a terminal? And this is so much like, I would not like it that way. Yeah. I really like the visualization. Because it's one thing to gather the information. It's another to go, Oh, I see right there is actually where it's slow. And if it's, there's just a dump of a bunch of numbers mean, yeah, you can like sort it and whatnot. And it, you can use the profiles, different sorting options and get it to mean stuff. But it's not the same as like, aha, there's the picture. I see. It's red right there. And it's really tall. Let's go figure that out. Yeah. And the web one. The logo is awesome. It's good. It's really good. Yeah, it's like a 70s thing. It reminds me of Austin Powers. Yeah, a little bit, right. Yep. Yeah. In a non copyright infringing way.
23:05 Anyway, that's it. People are looking for a profiler. Austin looks pretty cool. Check it out.
23:11 It's definitely one of the contenders Anthony for sending that in. I want to talk about numbers just fit in the screen. Oh, yeah. You got your mathematician hat on now. Or Yes. I can't decide. I got this from man. He writes to get creative stuff. He first name Marsh said last name Zod, cat sabka mosh, you got to contact me and find out tell me how to pronounce your name. But numbers in Python, really great article. In Python, you don't really have to think about numbers too much. They just sort of work out. But you do kind of need to think about them. And this article is a really good quick tutorial about the different things that you need to know. Like integers, they turn into floats really easily. Like anytime there's a division, it'll turn into a float, right, which is unlike other languages, which are like truncating sort of things, right? That they take the floor of whatever the result will be. Yeah, in earlier Python versions to seven like that. Yeah. Yeah, like truncated off. But right. If you want that old time, now you got a double divide, like the two slashes. Yeah. And I forget about the two slashes thing. I never used the two slashes because that seems wrong.
23:11 Anyway, so the implications are weird, though. And the other thing, okay, so you got integers, they turn into floats. If you divide them, you got floats, which are things with decimal points in them. They're not the only things with decimal points. And then though, one of the things you learn early on in programming, but some people are new to programming are numbers. So it's good thing to remember, is floats don't behave like floating point numbers in math, like the subtraction and addition are not inverses and addition is not associative, always. And you can't multiply and then divide and get the same number. Those are weird things you should be aware of. The normal thing that I mostly need to remember is don't try to compare floating point number
23:11 With the equals the double equals, you have to use something like approximate or something. Yeah, that's the one that can really catch people out. I mean, okay, so I thought I was gonna get 14 and I got 13.999999999718. Okay, well, it's computers. We know that stuff's truncated. But it's really easy to go if x equal equals some number I'm looking for. And that never ever happens, right? Yeah, it looks right. And it is so wrong. And I think just our training for so many years and theoretical mathematics means that it's hard to look at that and go, that's wrong. Yeah, well, it's interesting that when you see it in numbers, you can like for instance, one of the examples is one plus two minus two minus one is zero. Obviously, of course it is it not if it's floating point numbers, though. So floats don't end up with zero, you end up with a very small number, but it's not sir. Okay, so floats are weird. Be careful. fractions. So if you don't use floats, there's fractions. Python has built in fractions. I actually have never really used these. It's neat. They're there. They're there. I've never used them, either. But yeah, there's like a class called fraction with a numerator and a denominator or takes another fraction or a floating point. Yes, a string. How about that the warning in this article is they fractions take a lot longer than you expect they would, for algorithms. So you can represent things as fractions, it's cool that you can do that Be very careful with any sort of algorithm because it can explode in memory and size and time and stuff like that. So probably just floating. That doesn't surprise me because when I have to do like, fraction algorithms, in my mind, it takes a lot longer to so. Yeah, the last one that is which he talks about, and it's something that some people don't realize right away is the decimals are built in. So there's a decimals library, that it's not probably not surprising. One of the reasons it's in there is for financial transactions, they're set up to be correct with precision and do the right thing. And so I'm really glad there otherwise we'd have like competing decimal, third party libraries or something like that. And we probably do. But the one this one's built in this, I'm glad the article was written, though, because they did something weird about decimals that they didn't know about was the there's a global state variable, that called context that holds the precision that's being used for decimal, like division and stuff. It could be anywhere in your program that gets the precision gets changed. So the recommendation in this article is to use a local context. So you can do a those blocks context, what are those things called? context manager? context manager? Yep. You can use the context manager local context to set a local context precision or your arithmetic. So that's good. That seems like that should be the required way. Because just setting it globally seems really, I don't know, it seems wrong. Because, you know, think of the race condition there. I was doing math, and then the precision got cut in half. And then it wasn't what I expected anymore.
23:11 Yeah, or I don't know, maybe there should be a minimum precision. This is interesting, though. Like, I didn't realize that you could even change the precision of decimals. So like in the docs, it says, unlike hardware based binary floating point numbers, the decimal module has a user alterable precision default into 28 places, which can be as large as needed for a given problem. So yeah, you can change it. The example in the in the Python document on the docks show, just globally, changing it halfway through a calculation, which seems like a bad Let's kick them down the stairs, instead of teaching them a hold on the hand railing. But this is really cool, like this local context. Change it, you can set it really high. That's cool. I had no idea that you could actually change that to grow as you need it. And which is cool. Yeah, I guess you could still use the global context as long as you maybe this isn't safe. But as long as you always remember to set it before you do decimal arithmetic. It's safe long as you're not doing threading. Oh, yeah. Okay. Yeah. Cuz what if somebody has some other thread has the same idea and changes it? I think the idea is maybe, it seems to me like possibly it would be better if one set it couldn't be set again, like you could set it at the beginning of your program, but it couldn't be altered and altered and altered. Like, right, something along those lines, like okay, we set it or done. It's an exception if you try to set it again to something else and so on. I mean, it probably the whole world. I have any Yeah, well, I didn't even know about it. Cool. Yeah, I would probably set up some sort of like hook or something to make sure that you're only setting it one place if you're doing that. Yeah. Yeah. Sounds good to me here. So cool. Anyway, yeah, this is actually more interesting than I thought because like, as usual, I've learned something which is cool. Last thing on this, we're gonna link to the standard library documentation for fractions and decimals because you may not have heard of them, and then a very old art
23:11 goal that if you really care about floating point numbers, you should at least know this article exists, although I don't think I've actually gotten through the whole thing ever. But it's what every computer scientists should know about floating point arithmetic. That's a good article. Yeah. Cool. All right. Any extras for us today, Michael, you know, not too much. I don't have too much to share right now. Nothing personal. But I do want to say thank you to everyone who subscribed to the YouTube feed of this podcast. Because we're breaking every segment, we've just covered six things. We're breaking that into six different videos. And you can see us on video, which is kind of cool. A bunch of people are subscribing at Python bytes at FM slash YouTube. Y'all can check that out. And you will see that Brian has awesome hats for every segment.
23:11 This episode, this episode, which Yeah, you got to wait. Yeah, for sure. This episode. So eventually, you'll get to see the hat. Okay. I'm glad we mentioned that. I wanted to mention also that python 3.9. point zero, alpha six is the last alpha release before we go into betas, I believe. And it is available, and it has the pig parser that we talked with them. I think last week about a little bit. Yeah, we talked about that was really cool to work it's been doing there. That's a big, long term upgrade, right? That's something that got written. And the original version of Python, it was unchanged and obviously can be better. Right? Basically, the syntax was limited by the parser. And how much it like looked ahead and stuff. And so this should open up the language for more complex concepts or make it easier to add concepts to it. Yeah. All right. So I see we have some competing jokes here. You want to go first? Yeah, I just put a call out on Twitter and said, I need some more jokes. And boy, I got a whole bunch of great ones back. I'm gonna pick one. This one's from James Ebell. If you put 1000 monkeys at 1000 computers, eventually one will write a Python program. And the rest will write Perl.
23:11 Right. I think maybe like 950 or more, right? Perl, a couple of them are just going to be writing regular expressions like all on their own. Yeah, that's true. All right, I have one that's maybe a similar vein here. So you know, like we talked about Austin has all these different user interfaces, and it's very user friendly. Well, you could say that Unix is very user friendly as well. It's just very particular about who its friends are.
23:11 Yeah, I got friends like that. Yeah. I got that one from the PI joke package. So pip install pi joke, and you can have it too. Yeah, that's good. Yeah. Anyway, cool. Thanks. All right. Fun is always
23:11 way to be everything. Bye. Bye. Thank you for listening to Python bytes. Follow the show on twitter at Python bytes. That's Python bytes as in be yts. And get the full show notes at Python bytes at FM. If you have a news item you want featured, just visit Python bytes.fm and send it our way. We're always on the lookout for sharing something cool. This is Brian Aachen and on behalf of myself and Michael Kennedy, thank you for listening and sharing this podcast with your friends and colleagues.