WEBVTT

00:00:00.001 --> 00:00:05.080
Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.

00:00:05.080 --> 00:00:10.080
This is episode 149, recorded September 18th, 2019.

00:00:10.080 --> 00:00:11.080
I'm Michael Kennedy.

00:00:11.080 --> 00:00:12.120
And I am Brian Okken.

00:00:12.120 --> 00:00:13.800
And this episode is brought to you by Datadog.

00:00:13.800 --> 00:00:15.100
I'll tell you more about them later.

00:00:15.100 --> 00:00:25.240
Brian, this first item that you have here, it actually sparked some philosophical sort of challenge to my way of seeing the world here.

00:00:25.240 --> 00:00:28.280
So why don't you run it by and I'll tell you about my problem.

00:00:28.280 --> 00:00:29.440
Maybe you can help me through it.

00:00:29.440 --> 00:00:30.940
I'm curious about this now.

00:00:30.940 --> 00:00:31.340
Yes.

00:00:31.340 --> 00:00:44.180
I'm pretty sure we've covered this before, but Dropbox is kind of behind a lot of the push to do different type checking or type hinting and checking those type hints within Python.

00:00:44.180 --> 00:00:48.400
The mypy project is, I think, spearheaded by Dropbox.

00:00:48.400 --> 00:00:48.740
Yes.

00:00:48.740 --> 00:00:54.200
There's an article that they put out called Our Journey to Type Checking 4 Million Lines of Python.

00:00:54.200 --> 00:00:55.460
Wow.

00:00:55.460 --> 00:00:56.520
4 million lines.

00:00:56.520 --> 00:00:57.800
That's a big code base.

00:00:57.800 --> 00:00:59.300
That's a lot of Python.

00:00:59.380 --> 00:00:59.780
Yeah.

00:00:59.780 --> 00:01:01.660
I wonder how much of it's interconnected.

00:01:01.660 --> 00:01:06.660
You know, like, you've got all these little utilities and nothing actually depends on it directly.

00:01:06.660 --> 00:01:08.040
Maybe they depend on the output.

00:01:08.040 --> 00:01:14.300
On the other hand, there could be like a super complicated sort of monolith thing.

00:01:14.560 --> 00:01:16.320
It's interesting to think about that much code.

00:01:16.320 --> 00:01:17.200
That is a ton.

00:01:17.200 --> 00:01:19.980
They're leading a lot of stuff, but one of the – I like this.

00:01:19.980 --> 00:01:20.660
So why?

00:01:20.660 --> 00:01:21.780
I mean, that's not free.

00:01:21.780 --> 00:01:25.060
You don't have a huge code base and move it to type checking.

00:01:25.060 --> 00:01:26.840
You don't get that for free.

00:01:26.960 --> 00:01:27.960
So there has to be benefits to this cost.

00:01:27.960 --> 00:01:29.620
So there has to be benefits to this cost.

00:01:29.620 --> 00:01:31.000
And that's one of the things.

00:01:31.000 --> 00:01:37.180
So this article does talk about their – kind of their – does go through some of their story of how they did it.

00:01:37.540 --> 00:01:39.560
What I really liked is it covered some of the benefits.

00:01:39.560 --> 00:01:41.680
And this isn't even that surprising.

00:01:41.680 --> 00:01:51.420
It says experience tells us that understanding code becomes the key to maintaining developer productivity, and that grows with a larger code base.

00:01:51.420 --> 00:02:04.240
So without type of annotation, basic reasoning such as figuring out what the valid arguments to a function are or the return types – that's a key one for me – becomes kind of a hard problem.

00:02:04.240 --> 00:02:10.180
And just answering those questions quickly, more quickly, what does this function return?

00:02:10.180 --> 00:02:11.900
Does it return none sometimes?

00:02:11.900 --> 00:02:12.920
Can it return none?

00:02:12.920 --> 00:02:14.080
Things like that.

00:02:14.080 --> 00:02:17.860
These become more and more of a drain as you're looking at a larger code base.

00:02:17.860 --> 00:02:19.440
I mean, that's definitely true.

00:02:19.440 --> 00:02:21.600
You spend more time reading code than writing it.

00:02:21.600 --> 00:02:29.980
So thinking about the types as you're writing it and putting those in place, especially for interfaces to functions, those are an easy win.

00:02:29.980 --> 00:02:31.000
I like it.

00:02:31.000 --> 00:02:38.640
They talked about some of the other benefits that the type checker is actually finding subtle bugs that they wouldn't have caught easily without it.

00:02:39.260 --> 00:02:40.580
Refactoring becomes easier.

00:02:40.580 --> 00:02:48.080
And then running the type checking is faster than running the suite of unit tests, so the feedback can be faster.

00:02:48.080 --> 00:02:51.100
And I didn't think about that aspect of it.

00:02:51.100 --> 00:02:51.960
That's pretty interesting.

00:02:51.960 --> 00:02:54.960
To include type checking as part of like a TDD flow.

00:02:55.500 --> 00:02:57.080
I haven't tried that.

00:02:57.080 --> 00:02:57.960
That would be kind of fun.

00:02:57.960 --> 00:03:13.580
And then one of the things I do know is that the IDEs such as Visual Studio Code and PyCharm allow for better completion and static error checking and a whole bunch of goodies that you get from the IDEs if you have type hints in there.

00:03:14.180 --> 00:03:21.960
But anyway, the other part of the story that I think is they talk about is the improvements to mypy to fit their needs.

00:03:21.960 --> 00:03:28.360
And so if you like mypy now, it's probably it's because Dropbox needed it to be really good.

00:03:28.360 --> 00:03:30.240
So anyway, it's a good article.

00:03:30.420 --> 00:03:33.420
I'm a big fan of type hinting and stuff.

00:03:33.420 --> 00:03:37.340
I think it all these things here that you've laid out, I definitely think they're all true.

00:03:37.600 --> 00:03:43.200
I would say absolutely the biggest one for me is making the IDEs and the editors just better.

00:03:43.200 --> 00:03:52.640
When I get the return value function that declares its return type and I hit dot on that variable, boom, there's the list of the things that I can do.

00:03:52.640 --> 00:03:54.060
I type one or two characters.

00:03:54.060 --> 00:03:54.920
It autocompletes.

00:03:54.920 --> 00:03:56.100
I just, you know, just flow.

00:03:56.100 --> 00:03:57.600
And yes, it's in the docs.

00:03:57.600 --> 00:03:59.000
What comes back from some of these things?

00:03:59.000 --> 00:04:00.160
Yes, you can go look them up.

00:04:00.160 --> 00:04:03.960
What arguments or what operations you can do on them?

00:04:03.960 --> 00:04:11.780
But if it's one character or two typing and it's just always there, it just massively improves what you're doing and your confidence and the speed.

00:04:11.780 --> 00:04:13.300
And it doesn't take you out of that flow.

00:04:13.300 --> 00:04:15.060
And I really appreciate that aspect of it.

00:04:15.060 --> 00:04:21.580
One of the things I'm embracing more and more is things that can return multiple types because we definitely can do that in Python.

00:04:21.580 --> 00:04:32.380
So things that arguments that can be set to none but are either none or a Boolean or there can be an A element or a list of those types of elements.

00:04:32.820 --> 00:04:40.560
Those sorts of things are great because if they're one of the types most of the time, you don't even really think about making sure that it works for the other one.

00:04:40.560 --> 00:04:40.940
For sure.

00:04:40.940 --> 00:04:43.320
So you want to hear my philosophical dilemma?

00:04:43.320 --> 00:04:44.080
Yeah, I do.

00:04:44.080 --> 00:04:44.400
All right.

00:04:44.400 --> 00:04:52.720
So in that article, it says something to the effect of mypy is an open source project and the core team is employed by Dropbox.

00:04:53.420 --> 00:04:57.840
One of the people who is doing major work on this project is Guido Van Rossum.

00:04:57.840 --> 00:04:58.100
Yeah.

00:04:58.100 --> 00:04:58.440
Yeah.

00:04:58.440 --> 00:05:02.200
I think he did something in Python, like created things like that.

00:05:02.200 --> 00:05:02.400
Right.

00:05:02.400 --> 00:05:04.100
He created the language and whatnot.

00:05:04.100 --> 00:05:13.520
And it wasn't until, gosh, I don't know, well into the 2010s or something like that until type hinting became a thing in the language.

00:05:13.520 --> 00:05:15.700
So Python was created.

00:05:15.700 --> 00:05:20.500
Its sort of core essence is a language without type declarations.

00:05:20.500 --> 00:05:20.860
Right.

00:05:21.220 --> 00:05:22.720
So here's my philosophical debate.

00:05:22.720 --> 00:05:33.400
Like, would Guido have gone back and said in 1991, actually a little bit of type hints should have been how Python originally came into the world?

00:05:33.820 --> 00:05:42.540
Or is this something that you have to go through and you're like, oh, it's fine when you have 100 lines of code that don't have any type information.

00:05:42.540 --> 00:05:48.040
But if you have 4 million, all of a sudden you're in a bad place with 4 million and hundreds of people working on it.

00:05:48.040 --> 00:05:57.120
Well, all of a sudden these types now are super valuable because here he is working explicitly on this thing that, you know, he probably decided not to have in his original language.

00:05:57.120 --> 00:05:58.200
And there's my dilemma.

00:05:58.200 --> 00:06:00.120
I think it's the size thing.

00:06:00.600 --> 00:06:03.740
It's helpful for large projects for tiny little things.

00:06:03.740 --> 00:06:04.280
It's not.

00:06:04.280 --> 00:06:10.320
I mean, has it ever bothered you that there are no type declarations in Bash scripts?

00:06:10.320 --> 00:06:12.060
Yeah, not really, I guess.

00:06:12.060 --> 00:06:14.400
I don't do really huge Bash applications.

00:06:14.400 --> 00:06:18.700
Yeah, that's probably some form of anti-pattern right there, isn't it?

00:06:18.700 --> 00:06:20.180
Yeah, I don't know.

00:06:20.180 --> 00:06:21.620
Maybe it's also the tooling, right?

00:06:21.620 --> 00:06:24.600
Like the editors do a lot more with that information now.

00:06:24.600 --> 00:06:27.920
It is an interesting question of why didn't it have it to begin with?

00:06:28.060 --> 00:06:33.620
If someone else was working on this, sure, okay, these are two philosophies and they kind of come together or don't in different ways.

00:06:33.620 --> 00:06:35.120
But it's the same person, right?

00:06:35.120 --> 00:06:38.920
So that was my thought as I was looking through this article.

00:06:38.920 --> 00:06:39.300
Yeah.

00:06:39.300 --> 00:06:39.600
Yeah.

00:06:39.600 --> 00:06:39.960
But cool.

00:06:39.960 --> 00:06:41.260
I'm happy to see them doing it.

00:06:41.260 --> 00:06:44.820
And I like to bring this sort of stuff into my code as well.

00:06:44.820 --> 00:06:45.560
I think it makes it better.

00:06:45.560 --> 00:06:46.180
All right.

00:06:46.220 --> 00:06:47.320
Well, what do you got for us?

00:06:47.320 --> 00:06:54.020
I did mention that we have these editors these days that do so much more than they did in 1991.

00:06:54.020 --> 00:06:58.100
And namely, this would be PyCharm and Visual Studio Code, right?

00:06:58.100 --> 00:06:59.620
Those are the two main ones.

00:06:59.620 --> 00:07:00.700
Obviously, there's others.

00:07:00.700 --> 00:07:02.940
But these are the main ones that are like super rich, right?

00:07:02.940 --> 00:07:03.140
Yeah.

00:07:03.140 --> 00:07:13.440
Our friend Miguel Grimberg decided he was going to put together a cool video about setting up Visual Studio Code to work with a full-fledged Flask application.

00:07:13.640 --> 00:07:16.300
So with PyCharm, I think it's pretty straightforward, right?

00:07:16.300 --> 00:07:18.520
PyCharm kind of is what it is.

00:07:18.520 --> 00:07:20.920
You go in and like, all right, here's the project.

00:07:20.920 --> 00:07:21.720
I see that.

00:07:21.720 --> 00:07:23.220
Here's how I run stuff.

00:07:23.220 --> 00:07:26.540
Here's how – like it's sort of really clear what you do.

00:07:26.540 --> 00:07:28.600
There's a lot of stuff going on there and it's really busy.

00:07:28.600 --> 00:07:30.920
But you can look at it and see what you're supposed to do.

00:07:30.920 --> 00:07:32.720
With Visual Studio Code, I don't feel that way.

00:07:32.720 --> 00:07:38.380
I look at it and I go like, all right, I know that this thing can be configured and adapted to do all this amazing stuff.

00:07:38.580 --> 00:07:44.060
And it gives me no breadcrumbs or hints on how to even like take that first step.

00:07:44.060 --> 00:07:46.420
I'm like, man, I know this thing's cool, probably.

00:07:46.420 --> 00:07:49.620
But I'm just going to edit this file and go on, right?

00:07:49.620 --> 00:07:56.880
But this is a video that also has a blog post version from Miguel.

00:07:57.120 --> 00:08:00.720
And it's actually a follow-up to doing the same thing in PyCharm about a year ago.

00:08:00.720 --> 00:08:09.640
And I think the reason he did it in PyCharm, even though I just told you how easy it was, is he's doing it in PyCharm Community, which is not officially able to support web development.

00:08:09.640 --> 00:08:10.740
It's the free version.

00:08:10.740 --> 00:08:17.520
So he's like, how do you set up a web development project in a thing that's not meant for that or officially configured for that or whatever?

00:08:17.520 --> 00:08:20.500
Anyway, so it goes through and it sort of walks you through all the steps.

00:08:20.500 --> 00:08:21.480
And you know what?

00:08:21.480 --> 00:08:22.340
It's really nice.

00:08:22.340 --> 00:08:24.980
And I think the grand finale, you will appreciate it, Brian.

00:08:25.300 --> 00:08:28.440
So as I think a lot of people do, so here's what we're going to do.

00:08:28.440 --> 00:08:29.260
We're going to go set up.

00:08:29.260 --> 00:08:30.540
We're going to clone the repo.

00:08:30.540 --> 00:08:31.640
We're going to create a virtual environment.

00:08:31.640 --> 00:08:48.460
We're going to install the requirements and sort of configure environment variables, maybe run some custom flask commands like flask deploy, which initializes the database or does database migrations and all that kind of stuff in the terminal before we actually get to the editor.

00:08:48.460 --> 00:08:49.720
And this is how I work as well.

00:08:49.720 --> 00:08:50.440
How about you?

00:08:50.440 --> 00:08:53.480
Do you like start from within PyCharm or do you kind of get to it eventually?

00:08:53.480 --> 00:08:55.440
Oh, no, same thing.

00:08:55.440 --> 00:08:56.780
I'm setting up.

00:08:56.780 --> 00:09:04.460
Well, I've got little extra little hooks to create an environment and activate an environment because I'm doing that on the command lane all the time anyway.

00:09:04.460 --> 00:09:08.360
Like if I'm going to clone a repo and stuff, I'm just going to do that.

00:09:08.360 --> 00:09:08.880
Same.

00:09:08.880 --> 00:09:14.520
And I have all these aliases and stuff that will like do multiple steps at once and make it a little bit nicer and so on.

00:09:14.520 --> 00:09:15.000
All right.

00:09:15.000 --> 00:09:16.780
So all that is in terminal.

00:09:16.780 --> 00:09:18.500
But then he says, all right, here's what we're going to do in VS Code.

00:09:18.500 --> 00:09:24.700
You're going to open the folder, which is a thing you could do in VS Code, and it will automatically find the virtual environment.

00:09:24.700 --> 00:09:31.220
But in order for all that stuff to happen, you have to encourage Visual Studio Code to go into Python mode.

00:09:31.220 --> 00:09:32.980
So just open any Python file.

00:09:33.140 --> 00:09:41.900
And that like activates all the little subsystems that fire up like the environment variable detection and all that kind of stuff, the virtual environment detection and so on.

00:09:41.900 --> 00:09:45.760
And then he says, all right, now what we want to do is how do you run the thing?

00:09:45.760 --> 00:09:50.120
So he talks about how to set up a run configuration in the debugger.

00:09:50.120 --> 00:09:54.840
So you open the debugger tab, add a configuration, and you can actually pick Flask.

00:09:55.040 --> 00:09:56.280
And it knows all about Flask.

00:09:56.280 --> 00:09:59.260
It asks you a couple of questions like, well, what's the app PY called?

00:09:59.260 --> 00:10:01.220
And things like that.

00:10:01.220 --> 00:10:02.620
So then it'll set it all up.

00:10:02.620 --> 00:10:06.160
And then you can run it in the debugger or run it without, and that's pretty nice.

00:10:06.160 --> 00:10:12.820
And then it says, finally, there's another thing about this UI that, like I said, it's kind of like water, right?

00:10:12.820 --> 00:10:20.820
It can be whatever you want, but you don't look at water and go, I bet that could be like a sculpture of a seal if I froze it and carved it down, right?

00:10:21.420 --> 00:10:23.700
So it's our example, but yeah, sure, go on.

00:10:23.700 --> 00:10:24.080
Yeah, right.

00:10:24.080 --> 00:10:25.220
Like, okay, ice sculptures.

00:10:25.220 --> 00:10:28.600
So there's another command you can run in VS Code.

00:10:28.600 --> 00:10:31.920
And this I didn't know about is you can ask it to discover Python tests.

00:10:31.920 --> 00:10:32.760
That's nice.

00:10:32.760 --> 00:10:33.020
Yeah.

00:10:33.020 --> 00:10:37.780
So you can say discover Python tests, and it'll hunt through and find all the tests in your project.

00:10:37.780 --> 00:10:40.240
And it'll even offer what test frameworks you want to run.

00:10:40.240 --> 00:10:43.040
You want to run unit tests or PyCharm or whatever.

00:10:43.040 --> 00:10:49.280
And then once you do that, like a new UI element sort of pops up, and now you can run your tests in a pretty cool runner.

00:10:49.280 --> 00:10:51.240
So it's about a half hour video.

00:10:51.640 --> 00:10:52.640
It's good, I think.

00:10:52.640 --> 00:10:55.680
And there's something really nice about seeing it in action.

00:10:55.680 --> 00:11:01.260
I'm a big fan of learning through, you know, video stuff, as people might imagine, since I put some time and energy into it.

00:11:01.260 --> 00:11:02.880
But it's one thing to read it.

00:11:02.880 --> 00:11:07.860
It's another to, like, see just that sort of process gone through and explain step by step.

00:11:07.860 --> 00:11:10.520
And Miguel does a good job, and I like it.

00:11:10.520 --> 00:11:18.680
At the end, he also talks about a limitation of handling crashing Flask applications with a debugger.

00:11:18.680 --> 00:11:21.800
And he says it's a Flask thing, not a VS Code thing.

00:11:21.800 --> 00:11:24.360
So you have to do it in both PyCharm and VS Code.

00:11:24.360 --> 00:11:26.480
But he shows you the little workaround.

00:11:26.480 --> 00:11:38.020
Yeah, basically you have to stop going through the Flask run option and go to the Flask.py or app.py, run it, and then override some settings in the run there.

00:11:38.020 --> 00:11:38.840
So yeah, it's pretty straightforward.

00:11:38.840 --> 00:11:40.220
But that's definitely a nice touch as well.

00:11:40.300 --> 00:11:47.460
Yeah, and then the other thing I wanted to touch on is when he's showing how to run tests in the video, they're just sort of magically running in the background.

00:11:47.460 --> 00:11:49.980
And you don't see what they're doing.

00:11:49.980 --> 00:11:59.120
And he doesn't cover this, but at the bottom of the screen or at the bottom of your VS Code window, there's some icons that show you the status of the tests.

00:11:59.120 --> 00:12:03.920
And if you click on that, that's where you go look at the output and look at the failures and whatever.

00:12:03.920 --> 00:12:04.740
Yeah, very cool.

00:12:04.740 --> 00:12:05.180
Nice.

00:12:05.180 --> 00:12:06.480
So that's a good one.

00:12:06.480 --> 00:12:09.720
Another thing that I'm a big fan of is parallel programming.

00:12:09.720 --> 00:12:12.580
And you've got a few things on that one for us, huh?

00:12:12.580 --> 00:12:19.580
There's an article called Multiprocessing vs. Threading in Python, What Every Data Scientist Needs to Know.

00:12:19.580 --> 00:12:22.880
It talked about multiprocessing and threading.

00:12:22.880 --> 00:12:24.620
It did not talk about async.

00:12:24.620 --> 00:12:32.860
And I don't know if that's appropriate or not, if async is even something that would be useful for data science or not.

00:12:32.860 --> 00:12:33.260
Sometimes.

00:12:33.260 --> 00:12:34.820
Not computationally, though.

00:12:34.820 --> 00:12:36.300
In any case, I liked it.

00:12:36.300 --> 00:12:39.260
Because a lot of people from data science are coming into programming.

00:12:39.260 --> 00:12:41.920
Like we know, they're coming in not as programmers.

00:12:41.920 --> 00:12:43.440
They're coming in from other fields.

00:12:43.440 --> 00:12:48.840
So there's a lot of background computer science knowledge that they just don't have.

00:12:48.840 --> 00:12:50.900
Or, you know, there might be gaps.

00:12:50.900 --> 00:12:53.440
So that's one of the reasons why I picked this, because I like it.

00:12:53.820 --> 00:13:00.500
I like that it talked about some of the basic concepts of parallelism, parallel computing, how to think about it.

00:13:00.500 --> 00:13:01.560
It has some diagrams.

00:13:01.560 --> 00:13:07.020
And then what the difference between multiprocessing and threading is in general.

00:13:07.020 --> 00:13:11.240
Specifically, threading is within one process.

00:13:11.660 --> 00:13:13.540
You've got a bunch of stuff going on.

00:13:13.540 --> 00:13:16.460
And multiprocessing is you get a bunch of processes.

00:13:16.460 --> 00:13:17.480
But there's tradeoffs.

00:13:18.120 --> 00:13:23.560
And then it also talks about specifically that Python has a GIL, so it's a little different.

00:13:23.560 --> 00:13:27.920
But because of the GIL, so, you know, it talks about that threads wait on.

00:13:27.920 --> 00:13:29.540
You can use either one.

00:13:29.540 --> 00:13:33.420
But in general, the general rule of thumb is CPU intensive work.

00:13:33.420 --> 00:13:35.640
You need multiprocessing.

00:13:35.800 --> 00:13:41.760
If you're IO bound or waiting on users, then threads are fine for that.

00:13:41.760 --> 00:13:47.380
So the surprising bit to me was the charts and some of the graphs that he has.

00:13:47.380 --> 00:13:57.620
Because he sort of does some benchmarks of code, running something on, like, both CPU intensive and IO intensive work.

00:13:57.620 --> 00:14:01.800
And how it speeds up with multiprocessing and multithreading.

00:14:02.240 --> 00:14:07.240
Obviously, throwing more processors at it helps.

00:14:07.240 --> 00:14:08.800
Or more threads.

00:14:08.800 --> 00:14:13.340
But what surprised me is that the difference between the two wasn't really that great.

00:14:13.340 --> 00:14:15.540
I thought it would be more pronounced.

00:14:15.540 --> 00:14:19.340
Basically, if you're not sure which one to use, pick one.

00:14:19.340 --> 00:14:20.780
And it'll speed up your code.

00:14:20.780 --> 00:14:22.700
Interesting, yeah.

00:14:22.700 --> 00:14:28.120
I kind of thought it would be, even with CPU intensive stuff, at least with stuff he was showing,

00:14:28.120 --> 00:14:31.540
that even multithreading helped speed things up.

00:14:31.540 --> 00:14:33.060
So I think this is good.

00:14:33.060 --> 00:14:36.860
And then he goes through a couple of data, specifically data science examples,

00:14:36.860 --> 00:14:42.720
and shows the code and how to throw multiprocessing and multithreading at data science problems.

00:14:42.720 --> 00:14:43.860
That sounds super useful.

00:14:43.860 --> 00:14:45.560
And the comparisons are interesting.

00:14:45.560 --> 00:14:51.260
These benchmarks are always so full of landmines and special cases.

00:14:51.260 --> 00:14:52.720
And I didn't use it that way.

00:14:52.720 --> 00:14:54.780
So I didn't get the right results that you said.

00:14:54.780 --> 00:14:56.700
You know, like, they're just so tricky to get them right.

00:14:56.700 --> 00:14:58.720
But it is cool to have them here.

00:14:58.720 --> 00:14:59.660
I like that a lot.

00:14:59.660 --> 00:15:03.260
One thing I would like to throw out there is, you know, a lot of times you have these sort of,

00:15:03.260 --> 00:15:05.780
I could do it this way or I could do it that way.

00:15:05.780 --> 00:15:06.860
And we'll see what we get.

00:15:06.860 --> 00:15:09.140
And then sometimes it's this, sometimes it's that.

00:15:09.140 --> 00:15:11.460
So now you've got to know two APIs and how you combine them.

00:15:11.820 --> 00:15:26.240
And I'm a big fan of the unsync, U-N-S-Y-N-C library, which takes the async programming model and applies it to multiprocessing to threads and async methods and makes it all nice and clean.

00:15:26.240 --> 00:15:28.680
Just a couple of decorators and they're all the same.

00:15:28.680 --> 00:15:29.880
So do you still have to pick?

00:15:29.880 --> 00:15:32.560
You have to pick at the implementation level.

00:15:32.560 --> 00:15:34.100
So imagine you have three functions.

00:15:34.440 --> 00:15:38.600
One of them is async because it actually implements async await it uses them.

00:15:38.600 --> 00:15:41.720
One is just a regular function you'd like to run on a thread.

00:15:41.720 --> 00:15:43.000
One is a regular function.

00:15:43.000 --> 00:15:46.860
Sorry, one is a function that does computational stuff and one does a weighting.

00:15:46.860 --> 00:15:48.460
So you just put a decorator.

00:15:48.460 --> 00:15:51.500
You say at unsync on the regular async one.

00:15:51.500 --> 00:15:52.600
That will run on asyncio.

00:15:52.600 --> 00:16:00.540
On the one that's doing weighting stuff that would work for threads, you just say at unsync and it automatically runs on threads if it's not an async method.

00:16:00.540 --> 00:16:05.200
In the last one, you would say at unsync CPU bound equals true.

00:16:05.200 --> 00:16:13.180
But then once you consume those, the way you program against it, they're all the same regardless of which style it is.

00:16:13.180 --> 00:16:15.740
So it's like when you define the function, like, oh, this is a CPU bound one.

00:16:15.740 --> 00:16:17.340
Oh, this one is actually async.

00:16:17.340 --> 00:16:19.900
So it just is async and it just adapts.

00:16:19.900 --> 00:16:21.900
It's a pretty cool library.

00:16:22.020 --> 00:16:25.020
It's 126 lines of Python in one file.

00:16:25.020 --> 00:16:27.580
And it does all that to unify all these APIs.

00:16:27.580 --> 00:16:27.980
It's great.

00:16:27.980 --> 00:16:28.640
Wow, that's cool.

00:16:28.640 --> 00:16:29.400
Yeah, so pretty cool.

00:16:29.400 --> 00:16:33.720
Anyway, yeah, this is really nice and certainly something people want to think about.

00:16:33.720 --> 00:16:35.060
It's a little bit tricky.

00:16:35.060 --> 00:16:38.820
We'll see if this is still a discussion in a couple of years, right?

00:16:38.820 --> 00:16:47.180
In Python 3.9, there's talk of maybe using subinterpreters to remove the limitation of the GIL inside of single processes and all sorts of stuff.

00:16:47.180 --> 00:16:48.840
Eric Snow is working on that.

00:16:48.960 --> 00:16:57.980
So if they actually got that working, then you'd probably be better because you can share data better, more richly and faster within a single process.

00:16:57.980 --> 00:17:01.460
And it's about to get even more crazy.

00:17:01.460 --> 00:17:03.000
That's a long discussion.

00:17:03.000 --> 00:17:03.620
Yeah.

00:17:03.620 --> 00:17:08.360
How much more do you have to care about, like, blocking and stuff like that?

00:17:08.360 --> 00:17:08.560
Yeah.

00:17:08.560 --> 00:17:12.080
Yeah, it brings all that stuff back in because you don't have the GIL anymore.

00:17:12.080 --> 00:17:18.220
Actually, with the subinterpreters, they're talking about a mechanism to explicitly share data in a safe way between them.

00:17:18.220 --> 00:17:20.260
So still, it's faster, though.

00:17:20.260 --> 00:17:20.500
Okay.

00:17:20.500 --> 00:17:20.760
Cool.

00:17:20.760 --> 00:17:34.200
Well, speaking of making things faster, you know, if you're looking at your app and you wonder what's going on, it would be nice to see everything that's going on across all the layers, across the database, across the web tier, things like that.

00:17:34.820 --> 00:17:36.180
So you should check out Datadog.

00:17:36.180 --> 00:17:37.160
They're sponsoring this episode.

00:17:37.160 --> 00:17:44.760
It's a modern cloud monitoring and cloud scale monitoring platform that brings together metrics and logs and distributed traces all in one place.

00:17:44.760 --> 00:17:52.340
So it auto instruments things like Django and Flask and Postgres means you get to see everything across all those boundaries.

00:17:52.680 --> 00:17:55.640
And it helps you optimize your Python apps in just a few minutes.

00:17:55.640 --> 00:17:59.360
Start monitoring your environment for free and get a sweet Datadog t-shirt.

00:17:59.360 --> 00:18:02.220
Just visit pythonbytes.fm/Datadog to get started.

00:18:02.220 --> 00:18:02.680
Nice.

00:18:02.680 --> 00:18:06.500
Well, not to be outdone by your async stuff.

00:18:06.500 --> 00:18:09.500
I also chose some async stuff here.

00:18:09.500 --> 00:18:13.620
So remember, we talked about Starlette a little while ago.

00:18:13.620 --> 00:18:18.560
And Starlette comes from this GitHub organization called Encode, E-N-C-O-D.

00:18:18.560 --> 00:18:21.720
And that place is full of magic.

00:18:21.840 --> 00:18:25.640
So they have UVicorn, which is the ASGI server.

00:18:25.640 --> 00:18:27.180
That's pretty awesome, like G-Unicorn.

00:18:27.180 --> 00:18:33.700
But for async based on the uv event loop, uv loop, event loop, and so on.

00:18:33.700 --> 00:18:34.780
And there's Starlet.

00:18:34.780 --> 00:18:35.960
There's also a Django REST framework.

00:18:35.960 --> 00:18:38.840
But there's HTTPX, which we talked about last time.

00:18:38.840 --> 00:18:42.200
And the last thing I want to just cover is a few more things in here.

00:18:42.200 --> 00:18:43.960
Because like I said, there's a lot of great stuff.

00:18:43.960 --> 00:18:47.520
There's a project just simply called ORM.

00:18:47.520 --> 00:18:50.120
We've got SQLAlchemy and Django ORM.

00:18:51.000 --> 00:18:52.620
And these guys just said, you know what?

00:18:52.620 --> 00:18:55.440
Well, just the term ORM is just free in Python.

00:18:55.440 --> 00:18:56.400
So let's just do that.

00:18:56.400 --> 00:18:59.780
Which is an async ORM.

00:18:59.780 --> 00:19:07.100
And they also have a thing called databases, which adds async support for talking to all these different databases.

00:19:07.520 --> 00:19:09.080
Postgres and whatnot.

00:19:09.080 --> 00:19:13.220
So this is a really cool project, especially this ORM one.

00:19:13.220 --> 00:19:16.460
Because it's kind of like SQLAlchemy.

00:19:16.460 --> 00:19:20.300
And it's actually based on the SQLAlchemy core for building queries.

00:19:21.140 --> 00:19:23.100
And that gives you a bunch of benefits, right?

00:19:23.100 --> 00:19:27.460
That means if you already have some stuff that works with SQLAlchemy, to some degree it will be similar.

00:19:27.460 --> 00:19:36.260
It means that Alembic, which is the tool to do database migrations on SQLAlchemy, also works with this ORM.

00:19:36.260 --> 00:19:38.800
So you can automatically just apply Alembic to it.

00:19:38.800 --> 00:19:39.420
And that's pretty cool.

00:19:39.420 --> 00:19:39.840
Wow.

00:19:39.980 --> 00:19:45.420
Yeah, it uses this database project that I talked about for cross-database async support.

00:19:45.420 --> 00:19:49.840
And it also has this thing called type system for data validation, which is pretty cool.

00:19:49.840 --> 00:19:50.660
I hadn't heard of that either.

00:19:50.660 --> 00:19:59.000
But yeah, it's a really sweet async API for working with databases and ORMs.

00:19:59.000 --> 00:20:01.880
So the way you create the models, it's very similar to SQLAlchemy.

00:20:01.880 --> 00:20:03.420
It's not identical, but it's similar.

00:20:04.060 --> 00:20:10.680
And then from there on, you just work with it kind of like you would do normal ORM stuff, right?

00:20:10.680 --> 00:20:16.340
Like I would say, if I'm working on an album, I might say album.objects.create.

00:20:16.340 --> 00:20:19.300
Or maybe I would do some kind of filter.

00:20:19.300 --> 00:20:22.740
So I'd say track.objects.filter, and I would do something.

00:20:22.740 --> 00:20:25.260
But every one of these operations is async.

00:20:25.260 --> 00:20:26.940
So you just put a weight in front of it.

00:20:26.940 --> 00:20:33.480
And if you have something you've got to scale, a whole lot of concurrent data traffic, like say a website,

00:20:33.480 --> 00:20:35.960
well, this is a pretty good combo.

00:20:35.960 --> 00:20:41.260
So like in the future, will we just have a weight in front of every other word?

00:20:41.260 --> 00:20:42.120
Everything.

00:20:42.120 --> 00:20:42.980
Exactly.

00:20:42.980 --> 00:20:47.560
So I was going to point out that you've got to be pretty async and await savvy to be doing it.

00:20:47.560 --> 00:20:50.700
Like there's a lot of awaiting, isn't there?

00:20:50.700 --> 00:20:52.240
Yeah.

00:20:52.240 --> 00:20:56.560
I think if you want to work with this library, you just have to say, we're just going all in on async.

00:20:56.560 --> 00:20:58.260
And that's the way it goes, right?

00:20:58.260 --> 00:20:59.020
No, it's good.

00:20:59.020 --> 00:21:01.400
If you're already working with async, that's when you would think,

00:21:01.560 --> 00:21:04.540
hey, I wonder if there's an async ORM that I can use.

00:21:04.540 --> 00:21:05.240
Yeah.

00:21:05.240 --> 00:21:06.240
Yeah, it looks good.

00:21:06.240 --> 00:21:08.200
And I like that it's based on SQLAlchemy Core.

00:21:08.200 --> 00:21:16.940
That means a big chunk of like the database conversation and the, say, the table creation and the migrations,

00:21:16.940 --> 00:21:20.360
all that stuff is already known and proven and working really well.

00:21:20.360 --> 00:21:27.560
It's just this API kind of site around the side of the traditional SQLAlchemy conversation,

00:21:27.560 --> 00:21:28.920
like directly with the database.

00:21:29.240 --> 00:21:32.320
I do wish that SQLAlchemy would take this approach.

00:21:32.320 --> 00:21:34.720
I interviewed Mike Bayer about it a long time ago.

00:21:34.720 --> 00:21:39.280
And like four years ago, he said, I don't really think it's going to make that big of a difference.

00:21:39.280 --> 00:21:42.660
But I think it actually would make a huge difference.

00:21:42.660 --> 00:21:45.500
You just got to think about, you know, what is your goal, right?

00:21:45.500 --> 00:21:48.040
If your goal is performance, it probably won't make a big difference.

00:21:48.040 --> 00:21:52.900
If your goal is scalability, it can make a tremendous difference, right?

00:21:52.900 --> 00:21:56.720
Are you trying to make an individual user's experience a little bit faster?

00:21:56.720 --> 00:22:02.700
Or are you trying to make the website not take 10 concurrent users, but 10,000, right?

00:22:02.700 --> 00:22:09.540
Like it probably might even make it a tiny bit slower for that one person, but it might make that 10 to 10,000 like no big deal.

00:22:09.540 --> 00:22:11.500
So it depends on what you're after, right?

00:22:11.500 --> 00:22:12.280
Yeah, definitely.

00:22:12.460 --> 00:22:14.200
Speaking of what you're after, what's next for us?

00:22:14.200 --> 00:22:19.340
One of the things you might be after is some data on somebody else's website, like through an API.

00:22:19.340 --> 00:22:19.900
Yes.

00:22:19.900 --> 00:22:20.840
There's more and more people.

00:22:20.840 --> 00:22:28.340
And I think it's great kind of doing the data science stuff of people coming into Python and programming from just trying to get their work done.

00:22:29.100 --> 00:22:34.900
And this is a dataquest.io blog post called Getting Started with APIs.

00:22:34.900 --> 00:22:37.880
And it's not getting started writing APIs.

00:22:37.880 --> 00:22:41.240
It's getting started consuming them with Python.

00:22:41.240 --> 00:22:50.100
If you kind of know what all this stuff is, but you haven't really thought about the basics, that's why I picked up this post is because it's really good with the basics.

00:22:50.100 --> 00:23:20.080
It's really good with the basics, right?

00:23:20.080 --> 00:23:21.440
If you want to specify it.

00:23:21.440 --> 00:23:28.740
So with APIs, you can have parameters to your queries to say, I only want the data for this user.

00:23:28.740 --> 00:23:33.260
Or they gave an example of Spotify music or something.

00:23:33.260 --> 00:23:41.660
You don't want to have all the data for all the songs that Spotify knows about, but maybe just the songs from a particular artist or something.

00:23:41.660 --> 00:23:44.200
So things like that are good.

00:23:44.200 --> 00:23:48.220
But this is actually the first time I've seen this, and they're probably all over the place.

00:23:48.220 --> 00:23:55.280
But talked about status codes, especially git status codes, because that's what we're doing here is retrieving things.

00:23:55.280 --> 00:24:06.900
And had a nice list of all the descriptions and things that you might run into for error codes, including like the 301, which isn't necessarily a problem, but you're getting redirected.

00:24:07.060 --> 00:24:08.800
So maybe you want to know about that.

00:24:08.800 --> 00:24:14.020
And then the 400 is something's not wrong on their end.

00:24:14.020 --> 00:24:15.200
It's wrong on your end.

00:24:15.200 --> 00:24:18.320
It's the server thinks you made a bad request.

00:24:18.800 --> 00:24:24.760
So that might be an endpoint that expects data or parameters, but you didn't send any parameters with it.

00:24:24.760 --> 00:24:27.480
Or you sent an end when it expected a string or whatever.

00:24:27.480 --> 00:24:34.900
And then, you know, it talks about endpoints and endpoints that take query parameters, endpoints being the specific API.

00:24:35.180 --> 00:24:40.040
So we think of a service providing an API, but it's usually not just one API.

00:24:40.040 --> 00:24:49.840
It's usually a whole bunch of related different bits of data that you can query together or query separately for different aspects of it.

00:24:49.840 --> 00:24:53.800
And then, of course, what APIs usually return is JSON data.

00:24:53.920 --> 00:24:57.200
So it has a little bit of an explanation for what JSON looks like.

00:24:57.200 --> 00:25:04.340
And then using the JSON module to convert back and forth between native Python stuff and JSON.

00:25:04.340 --> 00:25:08.280
And it also talks about requests and a bunch of examples for how to pull this.

00:25:08.280 --> 00:25:15.100
So if you're getting started trying to pull some data from an API somewhere, this is a good way to get started.

00:25:15.100 --> 00:25:18.200
It's a nice blend of theory and steps, right?

00:25:18.200 --> 00:25:20.500
It doesn't just say, well, you open up requests and you do this.

00:25:20.500 --> 00:25:22.860
It's like, here's what an API is.

00:25:22.920 --> 00:25:24.620
Here's what the HTTP verbs mean.

00:25:24.620 --> 00:25:27.120
Here's what the status codes are.

00:25:27.120 --> 00:25:28.180
Here's how you get to that.

00:25:28.180 --> 00:25:31.260
And, you know, how do you, like, manifest that in Python and stuff?

00:25:31.260 --> 00:25:31.760
Yeah, it's nice.

00:25:31.760 --> 00:25:35.360
Yeah, but it's not at the level of, like, a college course lecture.

00:25:35.360 --> 00:25:38.500
It's just enough to get the concepts right.

00:25:38.500 --> 00:25:38.960
Exactly.

00:25:38.960 --> 00:25:44.040
It's not trying to make you read the restful dissertations and things like that.

00:25:44.040 --> 00:25:47.220
Yeah, I don't even know if it mentions rest, even though that's what we're talking about.

00:25:47.220 --> 00:25:47.480
Cool.

00:25:47.480 --> 00:25:48.680
That's probably a good thing.

00:25:48.680 --> 00:25:50.320
That was overdone for a while.

00:25:50.700 --> 00:25:53.680
Now, last thing I want to cover is memory management in Python.

00:25:53.680 --> 00:25:56.440
This is an article entitled Memory Management in Python.

00:25:56.440 --> 00:26:02.100
But what it really is, is it's a narrow slice, but a common slice of memory management in Python.

00:26:02.100 --> 00:26:05.080
So you probably don't think about memory very much in Python, huh, Brian?

00:26:05.080 --> 00:26:06.320
No, I usually forget about it.

00:26:06.320 --> 00:26:07.640
Yeah, just forget about it.

00:26:07.640 --> 00:26:08.320
That's right.

00:26:09.260 --> 00:26:14.300
So you don't use malloc or free or new or any of these things.

00:26:14.300 --> 00:26:15.680
Definitely not delete.

00:26:15.680 --> 00:26:19.520
If you use delete, it means something else, sort of, and things like that, right?

00:26:19.520 --> 00:26:19.940
Yeah.

00:26:20.040 --> 00:26:30.780
So I think it's actually pretty interesting that the story of understanding how the runtime experience is in CPython is kind of opaque a little bit, right?

00:26:30.780 --> 00:26:37.120
There's not a lot written about memory management, which is why I decided to pick this thing and talk a little bit about what it covers.

00:26:37.120 --> 00:26:43.000
Because I think it doesn't really matter that you know this in some sense, right?

00:26:43.000 --> 00:26:54.220
Like your Python code will still work, but you more closely understand what your code is doing, how that might map over to like CPU architectures and caches and RAM and all that kind of stuff.

00:26:54.280 --> 00:26:58.000
And, you know, just having a high-level understanding of that's good.

00:26:58.000 --> 00:27:04.400
Yeah, so here's a pretty deep, detailed article, not too long, get to it pretty quick, about memory management in Python.

00:27:04.400 --> 00:27:07.440
But it only covers, like I said, a little bit.

00:27:07.440 --> 00:27:14.440
It's really about how does small object allocation and deallocation happen in Python.

00:27:14.440 --> 00:27:17.860
It doesn't talk about the gill, which is about thread safety and memory allocation.

00:27:17.860 --> 00:27:19.800
It doesn't talk about reference counts.

00:27:19.920 --> 00:27:24.740
It doesn't talk about garbage collection for cycles or much else.

00:27:24.740 --> 00:27:26.500
So it's all about small objects.

00:27:26.500 --> 00:27:29.800
But most things we make in Python are small objects.

00:27:29.800 --> 00:27:33.420
Even when they're big, they're really just a bunch of small things all pointed at each other, right?

00:27:33.420 --> 00:27:39.680
So if I've got like a list of a million items, I don't have each of those items is 10 bytes.

00:27:39.680 --> 00:27:41.340
I don't have 10 million bytes.

00:27:41.340 --> 00:27:44.900
I have this big list with a bunch of things.

00:27:44.900 --> 00:27:49.140
But then each one of those is a pointer out to its actual thing that it is, right?

00:27:49.700 --> 00:27:53.520
Even when you have strings or even numbers, right?

00:27:53.520 --> 00:27:58.280
A lot of languages, numbers are allocated on the stack and treated as value types and stuff.

00:27:58.280 --> 00:28:00.520
But, you know, everything is an object.

00:28:00.520 --> 00:28:03.560
So every little thing that you make has to get allocated and deallocated.

00:28:03.560 --> 00:28:08.440
So understanding how these small objects get allocated, that's pretty interesting.

00:28:08.440 --> 00:28:10.000
So that's what this article talks about.

00:28:10.000 --> 00:28:13.200
So I'll try to like summarize some of the stuff covered there.

00:28:13.200 --> 00:28:18.700
One of the problems you have with memory allocation is that memory can get super fragmented, right?

00:28:18.740 --> 00:28:27.060
If I just allocate a bunch of stuff and then delete it and keep allocating it and just let that grow, you know, just keep adding on the end, wherever the memory is.

00:28:27.060 --> 00:28:28.840
And I want to interact with that.

00:28:28.840 --> 00:28:34.500
That can really mess up like reading from RAM and getting stuff on cache to be high performance and stuff like that, right?

00:28:34.700 --> 00:28:55.380
So what Python does is it actually pre-allocates these little 256K chunks and then it partitions those up and it plucks in the small objects into those spaces and then will potentially take them back out and then reuse those spaces that it had already allocated when it needs to make a new small thing.

00:28:55.880 --> 00:28:55.960
Okay.

00:28:55.960 --> 00:28:56.260
Okay.

00:28:56.260 --> 00:28:56.660
All right.

00:28:56.660 --> 00:29:03.880
So that's supposed to help with memory optimization, the locality stuff, the fragmentation and so on.

00:29:03.880 --> 00:29:10.420
So there's a special memory manager in Python called PyMalloc, general purpose allocator.

00:29:10.420 --> 00:29:14.800
On top of like C malloc, there's a Python allocator, right?

00:29:14.820 --> 00:29:19.120
So there's like this layer, we have RAM, we have the operating systems, virtual memory management.

00:29:19.120 --> 00:29:20.820
We have C's malloc.

00:29:20.820 --> 00:29:23.960
We have this PyMem, PyMalloc thing.

00:29:23.960 --> 00:29:29.360
We have the Python object allocator that then figures out where to place these things and we actually have object memory.

00:29:29.360 --> 00:29:33.940
So there's a lot of stuff going on here and they break it into three levels of organization.

00:29:34.780 --> 00:29:35.260
Okay.

00:29:35.260 --> 00:29:41.600
So for small objects, which are things that are individually smaller than 512 bytes, right?

00:29:41.600 --> 00:29:45.540
Not like maybe a list that has a bunch of stuff, but each, each little bit smaller, right?

00:29:45.540 --> 00:29:48.440
So those are the things we're talking about.

00:29:48.440 --> 00:29:54.760
And what happens is it gets broken into these three things called the block, the pool and the arena.

00:29:54.760 --> 00:30:02.940
So a block is a chunk of memory of a certain size and it only holds Python objects of a certain size.

00:30:03.160 --> 00:30:07.780
So maybe there's a block that holds 16 byte Python things.

00:30:07.780 --> 00:30:08.380
Yeah.

00:30:08.380 --> 00:30:08.720
Okay.

00:30:08.720 --> 00:30:09.560
It's weird.

00:30:09.560 --> 00:30:10.440
Yeah.

00:30:10.440 --> 00:30:17.000
So the reason is, is Python can then, it knows how to exactly fill up and then reuse those blocks.

00:30:17.000 --> 00:30:17.660
Oh yeah.

00:30:17.660 --> 00:30:18.140
Right.

00:30:18.140 --> 00:30:23.360
So if it's like, oh, I'm going to get a bunch of numbers, all the numbers are the same size unless they become utterly huge.

00:30:23.360 --> 00:30:26.100
So we can just like allocate them into the spot.

00:30:26.100 --> 00:30:27.120
Some of those numbers go away.

00:30:27.120 --> 00:30:27.860
We got another block.

00:30:27.860 --> 00:30:32.280
We dropped that new number pointer in right there or the number, which we then point at right there and so on.

00:30:32.600 --> 00:30:34.260
So there's these different blocks.

00:30:34.260 --> 00:30:39.120
Each one is a uniform size between eight and 512 bytes.

00:30:39.120 --> 00:30:45.760
And then the blocks are managed by this thing called a pool, which is usually limited to a memory page size.

00:30:45.760 --> 00:30:47.020
So four kilobytes.

00:30:47.020 --> 00:30:51.500
And then the pools are managed as these things called arenas.

00:30:51.760 --> 00:30:54.120
And these are the things that are allocated on the heap.

00:30:54.120 --> 00:31:04.320
I believe they are 256K pieces of memory, which hold 64 pools, which hold some number of blocks and things like that.

00:31:04.320 --> 00:31:04.520
Right.

00:31:04.520 --> 00:31:14.860
So there's this really intricate way in which memory is trying to be grouped together and then also trying to be reused without reallocating it from the operating system.

00:31:14.860 --> 00:31:15.160
Okay.

00:31:15.160 --> 00:31:15.440
Right.

00:31:15.440 --> 00:31:23.140
So even though Python might new up a bunch of objects, it actually says, well, but we already have this block that holds those size of things.

00:31:23.140 --> 00:31:24.160
And there's some spots in there.

00:31:24.160 --> 00:31:25.340
So let's fill that bad boy up.

00:31:25.340 --> 00:31:25.920
Oh, all right.

00:31:25.920 --> 00:31:26.160
Yeah.

00:31:26.160 --> 00:31:33.000
Anyway, so it's pretty interesting how all the stuff is working together, but that's the Python small object allocator.

00:31:33.000 --> 00:31:35.940
Never thought about that before, but kind of interesting.

00:31:35.940 --> 00:31:41.420
Also, I'm trying to visualize like a sports arena with 64 swimming pools in it.

00:31:41.420 --> 00:31:43.440
That's not a bad one.

00:31:43.440 --> 00:31:48.900
And then each pool is filled with exactly the same size people or creatures swimming around, something like that.

00:31:48.900 --> 00:31:49.200
Yeah.

00:31:49.200 --> 00:31:49.780
Yeah, there you go.

00:31:49.780 --> 00:31:50.560
That makes a lot of sense.

00:31:50.560 --> 00:31:52.820
The first part of it totally made sense.

00:31:52.820 --> 00:31:54.620
The last bit, maybe not so much.

00:31:54.620 --> 00:31:54.880
All right.

00:31:54.940 --> 00:32:04.020
Well, anyway, what I like about this article is it seems like it has a lot of stuff from like, here's the actual C code that defines what an arena is.

00:32:04.020 --> 00:32:06.800
Here you can see it's like a doubly linked list and how it all fits together.

00:32:06.800 --> 00:32:08.360
And it's just got some good analysis.

00:32:08.360 --> 00:32:11.060
So have a look if you've wondered about this.

00:32:11.060 --> 00:32:11.840
All right.

00:32:11.840 --> 00:32:12.980
Well, that's it for our main items.

00:32:12.980 --> 00:32:18.740
I know, Brian, you have big news for the entire world if they live near Portland.

00:32:18.740 --> 00:32:22.360
If they live in Portland or really close to Portland.

00:32:22.360 --> 00:32:23.580
Or want to come to Portland.

00:32:23.960 --> 00:32:29.020
September 26th, I'll be speaking downtown at the Portland Python user group.

00:32:29.020 --> 00:32:32.240
And I'm still working on my talk, but I'll be there.

00:32:32.240 --> 00:32:33.400
That'll be fun.

00:32:33.400 --> 00:32:35.780
And then I'll probably polish it more.

00:32:35.780 --> 00:32:38.680
And people have to volunteer for this other talk.

00:32:38.680 --> 00:32:46.540
So on October 6th, it's the inaugural first day of meeting the Python PDX West.

00:32:46.540 --> 00:32:50.500
So we've got a new user group for Python in town.

00:32:50.500 --> 00:32:52.660
I'm hosting it along with you.

00:32:52.660 --> 00:32:53.240
Yeah, it'll be fun.

00:32:53.240 --> 00:32:54.380
I'm really looking forward to it.

00:32:54.380 --> 00:32:54.660
Yeah.

00:32:54.660 --> 00:32:55.860
And you'll be speaking there.

00:32:55.860 --> 00:32:56.280
I will.

00:32:56.280 --> 00:32:58.720
And I'm trying to get other people to volunteer to speak.

00:32:58.720 --> 00:33:01.220
And if they don't, then it'll just be you and me speaking.

00:33:01.220 --> 00:33:02.540
But I think it'll be fun.

00:33:02.820 --> 00:33:05.140
So we've got a bunch of people signed up so far.

00:33:05.140 --> 00:33:07.100
So it's filling up fast.

00:33:07.100 --> 00:33:08.300
People should sign up.

00:33:08.300 --> 00:33:08.640
That's cool.

00:33:08.640 --> 00:33:12.660
Maybe we could do a live Python Bytes sometime there as well at the end of the day or something.

00:33:12.660 --> 00:33:13.140
Who knows?

00:33:13.140 --> 00:33:14.040
That's a great idea.

00:33:14.040 --> 00:33:14.500
Yeah.

00:33:14.500 --> 00:33:14.940
We could have.

00:33:15.020 --> 00:33:18.020
Maybe not Tuesday, October 6th, but maybe someday we can make that happen.

00:33:18.020 --> 00:33:18.780
Maybe someday.

00:33:18.780 --> 00:33:19.080
Yeah.

00:33:19.080 --> 00:33:19.320
Yeah.

00:33:19.320 --> 00:33:19.960
That's great news.

00:33:19.960 --> 00:33:23.480
If you happen to be around, definitely drop in.

00:33:23.480 --> 00:33:24.020
That'd be great.

00:33:24.020 --> 00:33:25.360
It's on meetup.com, right?

00:33:25.360 --> 00:33:26.320
People want to sign up there.

00:33:26.320 --> 00:33:26.580
Yep.

00:33:26.580 --> 00:33:27.700
And a link in the show notes.

00:33:27.700 --> 00:33:34.840
Do you have any intention of recording live casting or otherwise spreading this in a farther path?

00:33:34.840 --> 00:33:35.960
It's not a bad idea.

00:33:35.960 --> 00:33:38.100
We don't have anything like that set up right away.

00:33:38.100 --> 00:33:39.800
In the future, maybe we could do that.

00:33:39.800 --> 00:33:42.500
Probably people would be interested in watching these.

00:33:42.880 --> 00:33:47.920
But I also want to make it really accessible to people that are new to presenting as well.

00:33:47.920 --> 00:33:52.440
I'd love to have people come in and do a talk that they're working on.

00:33:52.440 --> 00:33:53.760
It's not quite polished yet.

00:33:53.760 --> 00:34:02.100
I want it to not just be experts talking to everybody else, but I'd like it to be people working out things that they're just interested in.

00:34:02.100 --> 00:34:03.780
So I think it would be good.

00:34:03.780 --> 00:34:03.960
Yeah.

00:34:03.960 --> 00:34:05.540
That sounds like a great philosophy for it.

00:34:05.540 --> 00:34:06.040
How about you?

00:34:06.040 --> 00:34:07.140
Any extras?

00:34:07.140 --> 00:34:12.760
I have a couple presenting and speaking PyCon 2020, which is a little earlier this year.

00:34:12.840 --> 00:34:14.460
I believe it's like in April or something.

00:34:14.460 --> 00:34:15.460
The website's up.

00:34:15.460 --> 00:34:16.200
Yeah.

00:34:16.200 --> 00:34:19.020
So April 15th to 23rd.

00:34:19.020 --> 00:34:23.520
So the call for proposals is now open for PyCon 2020.

00:34:23.520 --> 00:34:29.000
So if you would like to be considered, a talk of yours to be considered there, then now is the time.

00:34:29.000 --> 00:34:29.220
Yeah.

00:34:29.220 --> 00:34:33.280
Go ahead and submit those because you know you're only going to spend like a week writing it up anyway.

00:34:33.280 --> 00:34:34.440
So I may as well get that done.

00:34:34.440 --> 00:34:36.320
That's right.

00:34:36.320 --> 00:34:37.420
Do it like a Band-Aid.

00:34:37.420 --> 00:34:38.280
Stop worrying about it.

00:34:38.280 --> 00:34:39.020
Just get it over with.

00:34:39.020 --> 00:34:39.460
Yeah.

00:34:39.460 --> 00:34:40.040
Pull it right off.

00:34:40.180 --> 00:34:40.400
All right.

00:34:40.400 --> 00:34:41.960
Another thing I just...

00:34:41.960 --> 00:34:42.880
Have you heard of Gitbook?

00:34:42.880 --> 00:34:45.140
Yeah, but I haven't really looked into it much.

00:34:45.140 --> 00:34:45.900
I hadn't either.

00:34:45.900 --> 00:34:50.900
I was interviewing the guy, Joe, from Masonite, the Masonite Web Framework.

00:34:50.900 --> 00:34:56.700
And I noticed that Masonite's documentation is written in Gitbook.

00:34:57.180 --> 00:34:59.580
And so I looked at it and Gitbook is pretty interesting.

00:34:59.580 --> 00:35:05.000
You can use it as kind of like almost a base camp project management type thing.

00:35:05.000 --> 00:35:09.180
So stuff, personal notes or things you want to track or stuff like that.

00:35:09.180 --> 00:35:13.540
But you can also use it for documentation and knowledge bases and whatnot.

00:35:13.540 --> 00:35:15.280
So it looked pretty cool.

00:35:15.280 --> 00:35:17.740
And so I thought I'd just, you know, let people know that it's out there.

00:35:17.740 --> 00:35:19.880
It's free for small teams, like with some limitations.

00:35:20.820 --> 00:35:26.560
It's cost a little bit of money for non-trivial small teams, like $7 user.

00:35:26.560 --> 00:35:30.600
But it's also free for open source and nonprofit teams, which is kind of cool.

00:35:30.600 --> 00:35:32.840
So I'm also a big fan of Read the Docs.

00:35:32.840 --> 00:35:35.480
So it's, you know, I'm not saying they shouldn't use that.

00:35:35.480 --> 00:35:38.320
But here's an interesting project that I ran across that I hadn't heard of.

00:35:38.320 --> 00:35:39.160
It looks nice.

00:35:39.160 --> 00:35:43.760
If people, for some reason, are opposed to Read the Docs, I don't know why you would be.

00:35:43.760 --> 00:35:46.760
Or just like this look better is another opportunity.

00:35:46.760 --> 00:35:48.400
So good to have options.

00:35:48.540 --> 00:35:49.180
Good to have options.

00:35:49.180 --> 00:35:50.560
Also good to have laughs.

00:35:50.560 --> 00:35:51.700
Yeah, let's do some jokes.

00:35:51.700 --> 00:35:52.460
All right.

00:35:52.460 --> 00:35:53.860
How about you go first?

00:35:53.860 --> 00:35:54.460
Okay.

00:35:54.460 --> 00:36:00.660
So I pulled these out of a list of dad jokes you had posted somewhere on our Trello, but

00:36:00.660 --> 00:36:01.780
changed it a little bit.

00:36:01.780 --> 00:36:05.400
So what do you call a 3.14 foot long snake?

00:36:05.400 --> 00:36:05.980
I don't know.

00:36:05.980 --> 00:36:07.840
Well, that would be a python, of course.

00:36:07.840 --> 00:36:10.160
With the Greek symbol thon, yeah?

00:36:10.160 --> 00:36:10.500
Python?

00:36:10.500 --> 00:36:10.860
Yeah.

00:36:10.860 --> 00:36:15.140
So if it's not feet, but 3.14 inches, then what is it?

00:36:15.140 --> 00:36:16.360
It's a micro python.

00:36:16.360 --> 00:36:18.720
It's a micro python, a mu python.

00:36:18.720 --> 00:36:20.080
Yeah.

00:36:20.080 --> 00:36:21.900
I feel like we're back in calculus or physics.

00:36:21.900 --> 00:36:22.360
Yeah.

00:36:22.360 --> 00:36:23.940
So do you want to do some of these?

00:36:23.940 --> 00:36:24.480
Sure.

00:36:24.480 --> 00:36:28.020
So why doesn't Hollywood make more big data movies?

00:36:28.020 --> 00:36:28.660
I don't know.

00:36:28.660 --> 00:36:28.900
Why?

00:36:28.900 --> 00:36:29.580
No sequel.

00:36:29.580 --> 00:36:32.920
This last one, it's a little bit crass.

00:36:32.920 --> 00:36:35.920
It's, I don't know, it's a little low level, but I'll see what I can do here.

00:36:35.920 --> 00:36:40.060
So why didn't the angle bracket div get invited to the dinner party?

00:36:40.060 --> 00:36:40.620
I don't know.

00:36:40.620 --> 00:36:40.920
Why?

00:36:41.240 --> 00:36:42.360
It had no class.

00:36:42.360 --> 00:36:45.040
Oh, yeah.

00:36:45.040 --> 00:36:45.640
That's a good one.

00:36:45.640 --> 00:36:45.980
All right.

00:36:45.980 --> 00:36:47.480
Well, thanks for throwing those in there.

00:36:47.480 --> 00:36:47.940
These are fun.

00:36:47.940 --> 00:36:48.140
Yeah.

00:36:48.140 --> 00:36:51.940
Thank you once again for talking with me on a nice Wednesday.

00:36:51.940 --> 00:36:52.500
Absolutely.

00:36:52.500 --> 00:36:53.180
See you later.

00:36:53.180 --> 00:36:53.420
Bye.

00:36:53.800 --> 00:36:55.380
Thank you for listening to Python Bytes.

00:36:55.380 --> 00:36:57.920
Follow the show on Twitter via at Python Bytes.

00:36:57.920 --> 00:37:00.780
That's Python Bytes as in B-Y-T-E-S.

00:37:00.780 --> 00:37:04.020
And get the full show notes at pythonbytes.fm.

00:37:04.020 --> 00:37:08.220
If you have a news item you want featured, just visit pythonbytes.fm and send it our way.

00:37:08.220 --> 00:37:10.920
We're always on the lookout for sharing something cool.

00:37:10.920 --> 00:37:14.020
On behalf of myself and Brian Okken, this is Michael Kennedy.

00:37:14.020 --> 00:37:17.460
Thank you for listening and sharing this podcast with your friends and colleagues.

