#12: Deep Dive into Modules and Packages Transcript
00:00 Quick, what's the difference between a module, a package, and packaging in Python?
00:05 Okay, maybe you should listen to this episode of Talk Python to Me, number 12 with David Beasley.
00:10 It's all about packages, and it was recorded Monday, May 27, 2015.
00:15 Hello, and welcome to Talk Python to Me, a weekly podcast on Python, the language, the libraries, the ecosystem, and the personalities.
00:49 This is your host, Michael Kennedy.
00:51 Follow me on Twitter, where I'm @mkennedy, and keep up with the show and listen to past episodes at talkpythontome.com.
00:58 This episode, we'll be talking to David Beasley about the internals of modules and packages in Python.
01:05 I'm thrilled to tell you that this episode is brought to you by Codeship.
01:09 Codeship is a platform for continuous integration and continuous delivery,
01:13 as a service.
01:14 I'll talk more about them later in the show.
01:16 Please take a moment to check them out at codeship.com, or follow them on Twitter, where they're at Codeship.
01:23 This episode is also brought to you by Hired.
01:26 Hired has joined Talk Python as a sponsor because they want to help you find your dream job.
01:30 Hired is built specifically for developers looking for new opportunities.
01:34 You can sign up and expect to get five offers within the first week, and salary and equity presented right up front.
01:42 Check them out and get a very special offer at Hired.com slash Talk Python to me.
01:47 Think them on Twitter, where they're at Hired underscore HQ.
01:51 The last show on Computer Vision with Adrian Rosebrock, that was show number 11,
01:56 we talked about a laptop sticker from years back, which really inspired him.
02:00 It said, Python will save the world.
02:03 I don't know how, but it will.
02:04 Well, I thought that was a great sticker, and I tracked down a picture of it for you.
02:08 Check it out at bit.ly slash Python save.
02:11 I invited David to come on the show and talk about this subject after watching his tutorial
02:17 online at PyCon 2015.
02:19 Remember, I have this list of my essential 30 presentations from PyCon 2015,
02:25 and of course, David's is on it.
02:27 Check it out at bit.ly slash PyCon 2015 MK.
02:32 Now, let's get to the interview.
02:34 Let me introduce David.
02:37 David Beasley is an independent software developer, teacher, and book author living in Chicago.
02:42 He primarily works on programming tools and teaches programming courses for software developers,
02:47 scientists, and engineers.
02:48 He's the author of the Python Essential Reference and Python Cookbook.
02:53 David, welcome to the show.
02:55 Hi, how are you?
02:57 I'm doing fantastic.
02:58 Thank you for being on the show.
02:59 I'm really glad to have you here.
03:01 Okay, thanks for having me.
03:02 Yeah, you bet.
03:03 I saw your packages and modules talk at PyCon 2015, and I thought it was really interesting.
03:10 Okay, you survived that.
03:12 I did survive.
03:13 Unfortunately, my wife was traveling, and we have small kids, so I saw it remotely over YouTube.
03:18 But I wish I was able to be there.
03:21 So I sort of saw it.
03:23 But yeah, it was really, really interesting.
03:25 You didn't put it on for the kids?
03:26 Oh, my kids love it when I put on Python instructional videos for them.
03:30 Yeah, they're like, Dora the Explorer, forget it.
03:32 Give me something to do with, like, async Python.
03:36 I'll do that.
03:37 Yeah, yeah.
03:38 Good.
03:39 So we're going to talk a lot about packages and other stuff that you've got going on as well.
03:43 But let's start at the beginning.
03:45 Where did you get started in programming and Python and all that stuff?
03:50 So I got started, it's hard for me to believe, but about 19 years ago with Python.
03:55 I was actually using it in the context of scientific computing.
04:00 So around that time, I was trying to figure out some way to script scientific software written in C.
04:05 And kind of, for lack of a better description, was trying to create my own version of MATLAB, actually.
04:11 So...
04:12 What kind of science was it?
04:13 Well, I was doing molecular dynamics, material science, sort of on supercomputers and had done a lot of C programming for that.
04:21 And, you know, kind of the biggest problem that we had in that project was not the scientific computing part of it, but it was everything else.
04:29 Like just moving files around and, like, ripping data formats apart.
04:34 Kind of like all the annoying day-to-day stuff.
04:37 And so I was looking for some way to kind of solve that problem.
04:41 Prior to discovering Python, I had actually written my own scripting language, for which I was sort of resoundingly flamed at graduate school.
04:50 They were sort of saying, Dave, like, why are you making your own programming language?
04:54 Why don't you just use Tickle or some, you know, some existing thing?
04:58 And then I had read about Python in a, I think, an article in Computers and Physics or something like that.
05:04 And just said, oh, I'm going to go check that out.
05:07 Yeah.
05:07 And you're like, hey, somebody else wrote a scripting language.
05:10 Look at that.
05:10 Yeah, it is way better than mine.
05:12 You know, the syntax was fairly similar.
05:15 So...
05:15 Did yours have white space?
05:16 Like significant white space?
05:18 I did not have significant white space.
05:20 But I didn't have dollar signs and other kind of, you know, crazy things either.
05:24 So it was...
05:25 Okay, so you started out in the scientific world.
05:27 And, you know, I think Python now is super big for scientific programming.
05:32 How was it back then?
05:33 Back then, it was pretty radical.
05:35 I mean, this was like 96.
05:38 And if you go back that far, there were basically no tools available.
05:43 I mean, or it's very minimal tools.
05:45 And then a lot of the...
05:46 A lot of what you faced was pushback.
05:49 Because people thought, well, you know, can't write real software in a scripting language.
05:55 You know, why are you fooling around with this scripting language?
05:58 This thing.
05:59 Instead of coding in C++.
06:01 Right.
06:01 Especially if it's computational, right?
06:03 Yeah.
06:04 I mean, I actually got quite a bit of negative response.
06:08 Because I was running interactive Python on a supercomputer.
06:11 And people were like, you're just burning up, like, hundreds of dollars of CPU cycles just typing at the keyboard at this prompt.
06:20 You know, like, what are you doing?
06:22 And they didn't really realize that doing that was actually saving us huge amounts of time later.
06:28 You know, like, preventing us from running bad simulations or taking problems that used to take, you know, like, 50 hours and reducing it down to 15 minutes.
06:37 That kind of stuff.
06:39 But, yeah, it was a lot of pushback.
06:41 That's really funny.
06:42 It's interesting how people can focus on the wrong things.
06:45 You know, like, oh, we've got to have another server for that.
06:47 Or, you know, otherwise we'd have to have another person.
06:50 Or something like this, right?
06:51 I actually got quite a few people sort of mad in talks.
06:56 I gave some talks about this, and every now and then I'd get a, you know, like a question, like, how did you get permission from management to do this project?
07:03 And I would just say, well, we didn't ask.
07:06 They didn't explicitly forbid it, so it's permitted.
07:09 Yeah, so it was very much kind of a, you know, I don't know whether hidden project.
07:15 It was not really an approved project.
07:17 Yeah, a guerrilla project, maybe.
07:18 Project.
07:19 Although, you know, the people involved, I mean, at the time I was, you know, I was doing this work in Los Alamos.
07:24 You know, there was a group in Livermore National Lab kind of doing the same things.
07:29 And a lot of that early work is sort of led to kind of the precursors of things like NumPy and the SciPy tools that people are using now.
07:37 So, yeah.
07:38 Think of how the world would have been different if you had that to start from, right?
07:43 It would have made a big difference for you guys, I'm sure.
07:45 You've got to start somewhere, I guess.
07:47 Somebody has to shake things up, I guess.
07:51 Yeah, well, that's really cool.
07:53 What are you doing today with Python?
07:54 So, right now, well, a variety of things.
07:58 I'm teaching classes.
07:59 I'm also involved with a startup company.
08:02 That's been a little bit secretive.
08:03 But I'm technically co-founder of a startup doing some education tech stuff.
08:09 And I'm actually coding with that.
08:12 I'm doing a lot of just back-end web programming, databases, SQLAlchemy, things like that.
08:19 I'm supposed to be working on a new version of the Python Essential Reference book.
08:24 I haven't really started that yet.
08:27 I hope my editor doesn't listen to this.
08:29 But, you know, that's coming soon as well.
08:32 Well, we'll make it up to him by promoting the book in the show notes or something like that.
08:38 How's that?
08:38 Right, right.
08:39 Yeah, the tech education scene is insanely hot right now.
08:43 And VC and people, it's really an amazing place to be.
08:47 And I'm doing a little bit of stuff there as well.
08:49 And just, you know, knowing what's going on there is just amazing right now.
08:52 Yeah, a lot of crazy, crazy things there.
08:55 I guess if it wasn't crazy, it wouldn't be, I don't know, it wouldn't be worth doing, I guess.
08:59 Exactly.
08:59 It'd be like going back to high school instead.
09:01 Right, right.
09:01 Yeah.
09:09 CodeChip is a hosted continuous delivery service focused on speed, security, and customizability.
09:16 You can set up continuous integration in a matter of seconds and automatically deploy when your tests have passed.
09:21 CodeChip supports your GitHub and Bitbucket projects.
09:25 You can get started with CodeChip's free plan today.
09:27 Should you decide to go with a premium plan, Talk Python listeners can save 20% off any plan for the next three months by using the code TALKPython.
09:36 All caps, no spaces.
09:38 Check them out at CodeChip.com and tell them thanks for sponsoring the show on Twitter where they're at CodeChip.
09:45 Awesome.
09:53 So what inspired you to do a tutorial on packages?
09:56 I mean, that seems like, you know, doing a tutorial on for loops or something.
10:01 But obviously, you know, it was a two, three hour tutorial and it was really great, I thought.
10:06 So, but, but what started you on this path?
10:09 Yeah.
10:09 A three hour tutorial on packages.
10:11 Import.
10:12 Okay.
10:13 Now you can just contemplate this for two and a half hours to get the zen of it, right?
10:17 Yeah.
10:17 So I guess it was like probably a, so packages, I mean, modules and packages.
10:22 I mean, one part of it, it's something that, that I've rarely thought about.
10:26 You know, it's like you learn Python, you know, 19 years ago.
10:29 I was like, yeah, there's the import statement.
10:31 And yeah, sometimes you have to fiddle with the system path and, and, and, and, and so forth.
10:36 You know, you sort of, you sort of get over it.
10:39 But in, you know, in teaching a lot of classes and working with other people, it seems like
10:45 the import statement is like this no end of just hell for people.
10:49 Like, you know, I'll be teaching a class somewhere and then, you know, kind of walk around and I'll
10:54 see somebody struggling.
10:55 And they're like, yeah, I've been fooling around with this for like half an hour or something.
10:59 And first, first of all, like, why didn't you get my attention earlier?
11:02 But then you, but then you go over there and you realize that they're just fiddling around with
11:05 some stupid thing with the import statement.
11:07 Like, you know, the file is named wrong or that it's in the wrong directory or they're trying to
11:12 reload something or.
11:13 It could be subtle as well.
11:16 It's like, you might have a number as the starting name for your directory or something like that.
11:19 Right.
11:20 Yeah.
11:20 Subtle things or, you know, or like, you know, you're working with people on a project, you know,
11:25 it's like four o'clock in the afternoon and somebody's like, why are they cursing so much
11:28 over there?
11:29 You know, I go walk over, walk over there and they're like cursing about like why Python isn't
11:33 running their code correctly only to, only to realize that they, they've forgotten that
11:38 module loading.
11:39 It's a one-time operation.
11:40 Right.
11:41 Exactly.
11:41 It's not reloading there.
11:43 I changed it, but it's not changing.
11:45 Loading.
11:46 So, so, so part of it was just, it's like, I should do something on modules and packages to
11:51 try and like, I don't know, clear confusion maybe.
11:54 But I think, I think also part of it is the, the whole module system in Python has,
11:59 has been basically rewritten.
12:01 I don't know whether it's like a, it's almost like a from scratch rewrite where all of the
12:05 mechanics of it have actually been pulled out of C and put up into the Python level.
12:11 So almost, almost all the internals of modules and imports and packages and stuff is, is sort
12:16 of way more accessible now.
12:19 And so I thought it'd be kind of, kind of interesting to, to, to look at that as well,
12:23 just sort of take like a totally modern take on it and just see, you know, like what's going
12:29 on with modules and packages.
12:30 Yeah.
12:31 Before we get into the details, I, I'm sure everybody kind of gets a sense of what are modules,
12:36 what are packages, but just to make sure we're all on the same page, I could import things.
12:41 And sometimes I import a module and sometime I'm importing a package.
12:45 What's the deal there?
12:46 Well, I mean, a module, you know, maybe a simple view of it is, you know, people think of it
12:51 as like a single file, you know, single, single, file of source code, package would
12:57 be more of a collection of files.
12:59 You know, maybe larger application or a framework or, or, or something like that.
13:05 I think one thing that can be a little bit muddled is sometimes things look like modules
13:09 when in fact they're big packages and, you know, it can be kind of muddled sometimes.
13:16 So it seems to me like with modules, I'm getting just a file, right?
13:19 Like, Hey, I've written some code over here.
13:21 I've written some code over there.
13:22 Let me grab the code in the one file and use it.
13:25 And with packages, it seems like there's a lot more going on potentially, right?
13:31 I've got the, the under, under init.py and I can sort of declare this all under, under all
13:37 variable.
13:38 Can you maybe talk a little bit about the structure of a package and why you might build one?
13:43 Okay.
13:43 Well, I think, you know, the, so, so one thing with packages is, well, let me, let me back
13:49 up for a second here.
13:50 I think like, like if you're thinking about module, typically you're thinking about something
13:54 kind of small, like a single file, maybe a small library, you know, maybe, maybe not a
14:00 huge amount of functionality, but you know, it's just like a, you know, like just a single
14:04 point of, of, of code that, that is very easy to use.
14:08 I think with a package, you're getting into something much more complicated, you know, it's
14:12 like much larger code base.
14:14 And part of what you, what you want to avoid is just putting all of your code in one file.
14:19 Like nobody wants to have a file where it's 50,000 lines of Python code in there.
14:23 Especially not if you inherit that file.
14:26 Yeah.
14:26 Well, yeah.
14:26 So especially if it's given to you.
14:28 So with a, you know, with a package, you're really thinking about kind of breaking up your
14:31 code into different, you know, different sub modules, different parts of the application
14:36 and so forth.
14:36 It's more of an organizational, you know, organizational tool than, than anything.
14:41 Also, also just keeping your code separate from the, from the rest of the Python universe,
14:46 you know, avoiding like naming clashes with other bits of, bits of code.
14:51 I think the thing that gets complicated with a package is once you do that, you know, once
14:56 you separate your code out into multiple files, you have to start worrying about all sorts of
15:02 side issues.
15:03 Like, like how do those files interact with each other?
15:06 You know, like how does one sub module refer to another sub module or how do they, you know,
15:10 combine pieces together and, and so forth.
15:14 And that's actually where a lot of the, I think a lot of the tricky parts of packages come into
15:17 play is that just, you know, relationships within the package causes a lot of complexity that
15:23 you wouldn't see with a single, you know, a single file module.
15:27 Right.
15:27 I totally agree.
15:28 There's a lot of stuff you can do in that init file to sort of make it explicit about
15:34 what you want to export.
15:35 And I think of these packages as like reusable libraries that you're going to grab and they
15:40 have a bunch of functionality.
15:41 Whereas modules, I kind of feel like, Hey, I'm just, I'm reusing a file that I wrote.
15:44 This file wants access to that part of my code.
15:46 So I pull that in.
15:47 And so you talked about a lot of cool tips and tricks that you can kind of do there.
15:53 You talked about like the all, all variable.
15:56 You talked about importing sub modules in the main level module and stuff like that.
16:02 Yeah.
16:02 I think one of the, one of the things that, it might be more of a personal complaint,
16:06 but you know, when you use packages a lot, you can sometimes get a pull, like a huge number
16:11 of imports that start showing up in your code where, you know, instead of just importing a
16:16 single file, all of a sudden you're, you're putting in like 20 import statements and not a,
16:22 I'm not a huge fan of doing that.
16:24 So, you know, these are knit files that you sometimes see in packages.
16:27 I mean, those, one, one use of those is, is to basically coalesce the pieces into one
16:33 place.
16:34 And, you know, sometimes you can cut down on the number of imports that you have to do.
16:38 Right.
16:39 Maybe you import the top level thing, like import SQLAlchemy.
16:43 And then you could say SQLAlchemy dot and get to the sub packages, something like that.
16:47 Right.
16:47 Right.
16:48 Right.
16:48 You don't have to worry about, you know, how they organize that under the covers of SQLAlchemy.
16:53 It could be, you know, spread across, you know, 20 different files for all you care.
16:56 Yeah, exactly.
16:58 But you have to manually do that in the init file, right?
17:00 In order to sort of force the top level import to bring in the sub packages.
17:04 Is that correct?
17:04 You, you have to take some steps there.
17:07 Yeah.
17:07 I mean, it's, you know, if you're the author of a package, you have to figure out
17:10 some way to, some way to do that.
17:12 I've done some tricks involving decorators doing that.
17:16 Like, you know, they, being one of the applications I'm working on now, I, I mean, I
17:21 have a, I have a decorator I can put on functions that will automatically sort of hoist them up
17:27 into the init file.
17:28 So, I mean, there are, there are tricks that you can do to, to, to do that kind of thing.
17:33 That's really cool.
17:34 Is that a decorator that you wrote?
17:35 I just cooked it up myself.
17:37 Yeah.
17:37 Is it on GitHub or something?
17:38 It's, I don't know if it's on GitHub.
17:41 it is in the tutorial though.
17:43 Right.
17:44 Okay.
17:44 A module.
17:45 It's somewhere in that tutorial.
17:46 So.
17:46 Nice.
17:47 one thing that I thought was interesting that you spoke about the tutorial was that
17:52 structure guidelines, the PEP8 guidelines sometimes make your code more brittle in packages
17:57 than otherwise should be.
17:58 Oh yeah.
18:01 Yes.
18:01 One of the things with PEP8, I think is it predates some of the work that went on in
18:06 packages.
18:07 I mean, you know, like, like PEP8 sort of talks that you should, you know, well, it
18:11 sort of says things like, oh, you should just do like an absolute import from kind of a top
18:16 level package name.
18:18 So if we were writing like the, the, a package called math and it had a, a class called library,
18:24 calculator, something like that, we might in the init file say import math dot calculator
18:30 where math is the actual name of the package.
18:32 Right.
18:33 I don't know that I'd use math as the best.
18:35 Okay.
18:36 Yeah.
18:36 So I'm lacking creativity.
18:38 Yeah.
18:38 Pick another example.
18:39 Yeah.
18:39 I, it's, it's more concerning things like imports within the package.
18:43 Like if you, you know, if you had a package where, you know, you had a, like there was a
18:48 sub module called graphics and there was another module called data or something like that.
18:53 You would end up importing from the top level name down.
18:57 So if you're, if your package was named spam, for instance, you'd have to say, you know, import
19:01 spam dot graphics or import spam dot data.
19:04 And you would, you would do that within the package, within the package itself.
19:10 but the thing that I don't, that I don't like about that is it ends up hard coding the
19:14 package name.
19:15 Right.
19:16 For example, if you rename the package, what happens?
19:18 Well, then you have to go change all of your code.
19:20 Great.
19:22 See, that's the part I don't like.
19:23 Is there a fix?
19:23 Well, you could use, one of the things that you can use are these package relative imports.
19:28 This is this form.
19:30 I, it's, I'm actually surprised how many people have not seen it sometimes, but it's, what it
19:35 looks like is you have these dots where you would say something like, oh, from dot import
19:39 graphics or from dot import data.
19:41 And the, the dot is just telling Python that you want to load relative to your current location,
19:47 for instance.
19:48 Right.
19:49 Exactly.
19:49 So then it doesn't matter what you call the package.
19:52 Right.
19:52 Right.
19:52 Right.
19:52 That's really excellent.
19:53 I'm sort of thinking about things like versioning and stuff.
19:56 I mean, it's, you know, I could imagine situations where, you know, I have code where I, I need
20:01 to have an old version of some package coexisting with a modern version of the same package.
20:06 You know, one of the ways that you could deal with that is just to rename the old one.
20:11 Right.
20:12 Exactly.
20:13 Exactly.
20:13 Graphics dot, graphics dot old or underscore old or something like that.
20:16 Right.
20:17 Right.
20:17 Right.
20:17 As long as you don't have the package name hard coded in there, that, that, that all works
20:22 fine.
20:23 So.
20:23 Yeah.
20:24 I think it's, I think it's really good advice.
20:26 I propose we amend PEP8 to have the package relative imports.
20:31 I wonder when that part was written in PEP8.
20:34 I mean, it's, I have to, I hate to admit this on like a podcast, but I'm sort of a flagrant
20:40 PEP8 violator.
20:42 Don't worry, you, nobody can see the code, so they won't really know about it.
20:45 It's fine.
20:46 Yeah.
20:46 It's, I, I, I don't mean to violate it, but I think it's, you know, PEP8 comes after
20:53 the point at which I got involved with Python.
20:55 So it never really entered my consciousness of something that I would pay attention to.
21:00 I mean, it's.
21:01 Your style was already set by the time.
21:02 Yes.
21:02 Yeah.
21:03 I haven't, I have enough trouble just with the, people are always giving me a bad time
21:08 for using double quotes on all my strings.
21:11 Even, you know, I think like, you know, it's, that's fine in Python, but you know, most people
21:15 tend to use like the single quote and instead I'm kind of locked into double quotes just because
21:20 I've done so much C programming.
21:21 Exactly.
21:22 The, the single quote in C doesn't do the same thing.
21:25 I just can't get out of C programming, even though that's not my day-to-day job.
21:29 So yeah, I have the same problem.
21:31 I'm kind of back and forth on it.
21:41 This episode is brought to you by hired hired.
21:46 Hired is a two-sided curated marketplace that connects the world's knowledge workers to the
21:52 best opportunities.
21:53 Each offer you receive has salary and equity presented right up front, and you can view the
21:58 offers to accept or reject them before you even talk to the company.
22:02 Typically candidates receive five or more offers in just the first week.
22:06 And there are no obligations ever sounds pretty awesome.
22:10 Doesn't it?
22:10 Well, did I mention there's a signing bonus?
22:12 Everyone who accepts a job from hired gets a $2,000 signing bonus.
22:16 And as talk Python listeners, it gets way sweeter.
22:21 Use the link hired.com slash talk Python to me and hired will double the signing bonus to
22:27 $4,000 opportunities.
22:30 Knocking.
22:30 Visit hired.com slash talk Python to me and answer the call.
22:34 One thing that goes, you know, hand in hand with packages and trying these things out and
22:48 so on is virtual environments.
22:50 Do you use those often?
22:52 This is going to sound really shocking, but I almost never use them.
22:55 Okay.
22:56 I don't know why I never use them.
23:00 It's like I tend to, when I want to do something custom, I tend to just kind of build Python
23:06 myself.
23:07 And I might just put it in its own directory somewhere.
23:10 I don't know.
23:12 You know, that's probably just a bad thing to be doing, but maybe it's more historical.
23:16 Just having used Python for a while, that's something that's never been that hard to do.
23:22 Right.
23:22 Well, you understand it well enough.
23:24 You just do what virtual environment does more or less, right?
23:26 Yeah.
23:27 I do it the inefficient way, you know.
23:29 The explicit way.
23:31 How's that?
23:32 The explicit way.
23:33 You just download from source.
23:34 Yeah.
23:36 One of the things I do like about, well, I think is that I've actually have started using
23:41 them a little bit more ever since they got built into Python 3.
23:46 So that's actually a big win, I think, for sort of the newer versions of Python is they
23:51 have the virtual environment feature kind of just baked into the language.
23:55 I think that is really nice.
23:58 You know, we could go into a whole side conversation on Python 2 versus Python 3.
24:04 Yeah, we probably don't want to go there.
24:05 We probably don't want to go there.
24:07 But I think it's interesting that things like that are like, hey, here's a little less friction
24:11 if you go down the Python 3 path.
24:13 I talked with Kenneth Reitz on show number six.
24:15 We talked a little bit about that.
24:17 And he's like, I think what we really need is a killer feature that only appears in Python
24:22 3 in order to get people really to switch.
24:24 I mean, there's small gains that are making around like Django switching their documentation
24:29 by default to Python 3.
24:30 And that made a measurable dent in the world.
24:34 But, you know, things like maybe in Python 3, there's no such thing as a global interpreter
24:39 lock.
24:40 Well, that would be a big win.
24:42 I don't know whether that's going to happen anytime soon.
24:45 Of course.
24:45 You know, possibly with something like PyPy, right?
24:48 Or Pyston.
24:48 Maybe.
24:49 I don't know.
24:50 Yeah, maybe.
24:50 Anyway, you know, I think it's interesting.
24:52 But yeah, so these things like the virtual environment stuff being built into Python 3,
24:57 it's really cool.
24:58 And it's, you know, one more check in the box of, hey, you know, consider Python 3.
25:01 So another thing that you talked about is like splitting modules into a bunch of multiple files.
25:08 And I really like to do this.
25:10 Like you sort of started out the conversation.
25:12 I really, really dislike large files, right?
25:16 I would much rather have 10 50 line files than one 500 line file or two 250 line, you know,
25:24 whatever the math works out to be.
25:25 It's a bunch of smaller files.
25:27 It seems like Python kind of dislikes me doing this.
25:30 You know, it's the more I break stuff into small files, the more I have to put a whole bunch of imports at the top.
25:39 Right.
25:39 And that's that that is one thing.
25:40 I mean, you can definitely solve that with those init file.
25:43 I mean, if you put it all in a package, you can kind of stitch it all back together in a knit.
25:48 Right.
25:49 So I could have like all those in a subfolder, which has an under under init.
25:53 So it's a sub package.
25:55 And in that under under init, I would have like import and say from my class import my class or whatever.
26:04 And then they would sort of drop into that top level namespace.
26:07 Right.
26:08 Right.
26:08 Right.
26:08 Right.
26:09 So there's actually quite a few things in the standard library that do that already.
26:13 You know, like things like I think the collections module does that.
26:17 Multiprocessing does that.
26:19 I mean, if you if you look at how those are implemented, they're actually collections of files.
26:23 But to kind of an end user from kind of the Python side, it just looks like you're using a single module, basically.
26:30 Yeah, exactly.
26:31 Just collections dot.
26:32 And it's all there.
26:33 So they pull that off with the package stuff.
26:36 Right.
26:36 With the init file.
26:36 Yeah.
26:37 OK.
26:38 That's cool.
26:39 So one thing that you talked about that I don't know very little bit about are import hooks.
26:43 What are the stories with import hooks?
26:44 What can I do with those?
26:45 Well, import hooks.
26:49 I mean, essentially, some of the new machinery with import gives you complete control over like locating modules on the system.
26:58 What happens when you load modules?
27:02 You can actually completely customize what happens at import.
27:06 You know, for instance, pulling you could pull modules off of URLs.
27:10 You could pull modules out of a database.
27:12 You could even pull in code that wasn't Python.
27:15 You know, one of some things I did a tutorial maybe three.
27:19 It was three years ago, two years ago.
27:21 I don't know.
27:21 It was a Python three metaprogramming tutorial.
27:25 At the end of that, I had some import hook that loaded an XML file and translated it to Python class definitions at import time.
27:37 So I'm not saying this was a good idea.
27:40 It was sort of an example of some crazy thing that was possible.
27:46 That's pretty awesome.
27:47 Maybe not recommended, though.
27:48 Maybe not.
27:49 Let me rephrase.
27:51 It's probably awesome that you can do it, but not awesome if you do do it.
27:55 Yeah, I think I pitched the XML example as something that's been very enterprise ready.
28:00 Oh, that definitely sounds enterprise ready.
28:03 Yeah.
28:04 So what about threading?
28:06 Is there any special considerations for modules if I'm like working with threads?
28:11 Well, one of the things that I didn't realize doing the tutorial is just how nasty the import statement combined with threads is under the cover.
28:20 Well, under the covers.
28:23 It turns out that module imports is not really a totally thread-safe thing to do.
28:31 Like, you know, if you're loading a module or Python is in the process of importing something, potentially you could have another thread that tries to import the same module at the same time.
28:42 And it actually has to take some steps to avoid just complete chaos with that.
28:47 Like, one of the things that you don't want is you don't want it to – you don't want Python to load a module twice.
28:55 Like, you wouldn't want – because that violates the way that modules work, that they only get loaded once.
29:00 So if you had two threads trying to import the same module, one of them has to do it and the other one has to wait.
29:05 The other thing that's tricky is, you know, that the thread that has to wait can't use like a half-loaded module either.
29:14 So it turns out there's a bunch of just nasty stuff with threads and import.
29:20 I think a lot of that comes from code that does import statements inside functions.
29:26 Yeah, yeah.
29:27 That's kind of a temporary import it, throw it away sort of thing, right?
29:30 Yeah, right.
29:31 And so sometimes people will put like an import inside of a function.
29:34 And then if that function happens to execute within a thread, you know, the import might not happen until some thread hits that function.
29:43 And then all of a sudden you have concurrent imports taking place.
29:48 Yeah, that doesn't sound good.
29:50 So does Python take care of it for us though in the end?
29:53 Python takes care of it for us, thankfully.
29:57 But some of the code for that is really nasty.
29:59 I looked at some of the implementation and they're doing all sorts of things like thread deadlock avoidance algorithms.
30:05 And there's like all sorts of corner cases.
30:08 I tried to actually get Python to fail with some of the cases that they checked for.
30:14 I was not successful in doing that, which I think gives me maybe some bit of relief thinking,
30:20 wow, okay, if I can't make it fail there, then it's unlikely this would happen in most code.
30:27 But yeah, there's a lot of just really weird, nasty corner cases on that.
30:33 Yeah, the whole threading story in Python looks a little shadowy.
30:37 Like it doesn't get exposed to the light nearly as much as a lot of the other pieces.
30:40 Not shadowy and necessarily evil, but, you know, it's just less used, I would guess.
30:45 Yes.
30:46 Well, especially if it interacts with something like import.
30:49 I mean, you know, already import is pretty dark magic.
30:52 And, you know, you combine that with threads and then you're sort of in a weird place at that point.
30:58 So.
30:58 Yes, you are.
30:59 So you also said that you can reload modules programmatically.
31:03 And Python doesn't do that for you, but you can.
31:06 But you also said it's not a super good idea.
31:09 What's the story of that?
31:10 I would not do that.
31:12 I mean, so Python has traditionally had this reload statement.
31:17 You know, Python 2, you have to reload thing that would reload a module.
31:20 And then there's always been this kind of like advice surrounding it.
31:25 Like, well, you can do it, but you should basically never do it because, you know, puppies will die or something.
31:30 If you do that, then there's, you know, some kind of vague, ominous sort of mystery surrounding that.
31:35 And then in Python 3, they just took it out altogether as a built in.
31:40 They sort of said, well, OK, we're going to get rid of reloading.
31:43 Although you can find it in one of the libraries.
31:45 So I think it's an import lib or something like that.
31:50 The thing that I think is kind of interesting about reload is it's one of these things that somebody, they could think that it might be an interesting idea.
31:58 Like, OK, I have some Python code running in a server somewhere.
32:02 And I want to, I don't know, I want to make a code change and then, you know, have it load up into my server without restarting it or something like that.
32:13 Yeah, maybe I've got a website sitting there running and I don't want to have to deal with it.
32:16 I want to just notice if a new file gets dropped in here, just pick it up and run with it, right?
32:20 Right, right, right.
32:21 You know, maybe, you know, maybe somebody has seen, you know, like a demo of Erlang somewhere, somewhere at some place.
32:27 And they're like, oh, I want to be able to do that in Python, you know, do like a hot swap of code or something on the fly.
32:33 And, you know, so in the tutorial, talked about reload a little bit.
32:38 Is there anything that you could do to make that work?
32:42 I mean, so here's some of the problems with reload.
32:46 One big problem with it concerns instances of objects that you've created.
32:51 So let's say you had some code.
32:53 You have a bunch of instances of classes kind of floating around.
32:57 If you reload all of the class definitions, what ends up happening is you have all these existing instances that are basically using the old code.
33:06 And then any new instance you would make would end up using the new code.
33:10 So you could actually end up with like instances in your code using two different class definitions at the same time.
33:16 Oh, that's kind of crazy.
33:17 I suspect it runs, but things like static class level data might be kind of broken.
33:23 Static stuff breaks.
33:24 Another thing that breaks horribly is the super call.
33:28 If you ever use that.
33:29 One of the arguments to super is the name is the class that you're that you're working with.
33:35 If you ever if you ever do that, you'll end up getting this extremely cryptic error message.
33:43 Something about kittens.
33:44 Yeah, about kittens dying or something like that.
33:47 Although, I mean, here's here's kind of the wild thing.
33:50 You actually can kind of hack this.
33:54 I mean, one of the one of the things that people.
33:56 Well, one of the things you can do with Python objects is you can change the class attribute.
34:01 I don't know if anybody's done that, but like all objects, they have this this magic attribute class that sort of points to the class.
34:09 You could do some reloading hacks where, you know, on a module reload, you go through all of the existing instances and then flip their class attribute to the newly loaded class.
34:22 And then all of a sudden they'll be all of a sudden they're using the new code.
34:25 Yeah.
34:25 So maybe it's possible if somebody really wanted to change the standard library to support this, it maybe could be done, but maybe it's not really the best idea.
34:35 I my gut feeling is that you could probably do it if you wanted to surround your application with these sort of like 10,000 lines of code to manage it in some kind of sane way.
34:47 And then maybe it would work.
34:49 It's like a qualified maybe.
34:51 You know, maybe it would work.
34:52 I'm just not sure it's even tractable problem to solve in the big picture, though.
34:59 I mean, it's just.
35:00 And maybe it's not a good idea anyway.
35:02 You know, things with, you know, I just released a show with Docker and things like Docker and these microservices and so on.
35:10 It probably means it's less of a big deal to restart your app.
35:13 Yeah, that's probably my feeling, too.
35:15 I mean, I have to admit, Mike, in the code I'm working on now, if I want to do a deployment of new code, I just kill minus nine, the old one.
35:25 Yeah, sure.
35:26 You know, it's it's I mean, the system actually has a sort of a like a monitor or a watchdog or something that's, you know, just watches to see whether the thing is running or not.
35:36 If it's not, it restarts it.
35:37 Oh, it died.
35:38 Bring it back.
35:38 Oh, yeah.
35:39 So if you want to if you want to do a deployment, you just kill the old one and then it will automatically respawn itself at some point.
35:45 So, yeah, that that works.
35:48 Nice.
35:49 So you talked a little bit about the reloading stuff being different in Python three.
35:54 Is there other stuff that you're aware of, like this dramatically different from Python two to Python three?
35:59 Like if I'm down at the package level, writing code, worrying about those things, do I have to do something to make my Python two code friendly to Python three upgrades and things like that?
36:09 I wouldn't say there's a huge number of differences on the Python two, three side.
36:13 You know, one thing that might impact people is you can't do a relative import within a package.
36:19 So if you had a if you had a like a package directory spam and then you had two files in there, you know, like foo and bar dot foo dot pi bar dot pi.
36:30 In Python two, you can one of those files like like bar dot pi can just say import foo and it will find it in the same directory.
36:38 That does not work in Python three.
36:41 You would have to say from dot import foo or something.
36:45 So so this relative import feature, that is one place that might break in Python two, like from two to three.
36:53 I'm not really aware of much else, though.
36:56 And I haven't been using three for a while.
36:59 I haven't really noticed anything that would that would break across languages like that.
37:04 OK, that's cool.
37:05 So you said the from dot sort of relative import style.
37:09 Does that also work in two?
37:10 That also works in two.
37:11 Yeah.
37:11 It's just there's another syntax in two that wouldn't work in three, right?
37:15 No, it's the same syntax in two and three, actually.
37:18 Oh, OK.
37:18 So the syntax works in both.
37:21 It's just that the Python two is, you know, lets you do this relative import.
37:26 They they've taken that away from you in Python three.
37:29 So.
37:29 Yeah.
37:29 OK.
37:30 Yeah.
37:30 That's what I was thinking of.
37:31 OK, cool.
37:32 One of the things that I don't know, I wanted to ask you about was what surprised you about going through like this deep dive into this world?
37:39 Like what do you feel like you learned from this adventure?
37:41 I think one takeaway from looking at it is that there has been really an effort at cleaning up a lot of hacks.
37:50 Like a lot of the features that's been that have been built into the new import machinery are actually solving problems that people have been solving with Python two for maybe 10 years or more.
38:00 Like you'll you'll you'll see some feature in Python three where it's like, oh, this is kind of interesting.
38:05 You know, why did they do that?
38:06 And then you kind of chase it down through maybe, you know, descriptions through peps and and things like that.
38:12 And you realize that, you know, the motivation for this maybe came from some thing that somebody had done in, you know, in soap or something or some big Python two package.
38:21 And they've and they've just sort of rethought it in Python three.
38:25 And now what's interesting is the old hack that somebody would have done in Python two is just completely unneeded at this point.
38:34 But, you know, it's been cleaned up in a totally different way.
38:38 That's really cool.
38:39 It's just not a problem anymore.
38:40 Whereas you used to have to have this kind of special knowledge to survive whatever case they were dealing with.
38:46 Right.
38:46 Yeah.
38:47 I think that's actually a theme with a lot of Python three, actually, not just not just imports, but to, you know, if you look really deeply at a lot of things in Python three, they're solving problems that people have been dealing with for a long time.
39:02 But just trying to simplify it or or or make it more sane, if you will.
39:07 And, you know, I think that's throughout the language, actually.
39:10 You see a lot of cleanup of stuff where it's like, well, OK, you no longer have to do this kind of weird hack because it just works.
39:17 And in Python three, the thing that's tricky is that's just a really hard selling point.
39:22 You know, if you're trying to convince somebody to go from Python two to three and say, well, Python three is better because it cleans up this weird hack that somebody was doing on Python two.
39:32 And, you know, 10 years ago, that's often not a compelling story.
39:37 Sure.
39:37 It's hard to say.
39:38 You know what?
39:38 It's easier for the people writing Python three, the standard library stuff to maintain it.
39:44 So you should use it.
39:45 And I think, OK, I don't care about that.
39:46 That's not my problem.
39:47 Right.
39:49 You know, actually, one surprising thing in the Python.
39:52 This is a well, this is one example of some Python three stuff that I thought was surprising.
39:58 Like right now in Python three, you can ask you can ask the import system to locate a module for you without importing it.
40:07 Which is kind of an you say, well, that's kind of an obscure thing.
40:12 But what's kind of interesting about that is it solves a problem that people have doing what I would call a trial import.
40:19 You've probably seen this pattern from time to time where somebody will do a try statement and then they'll try to import a module.
40:26 And then they'll just catch like an import error exception and then maybe take action if it doesn't exist.
40:32 Right.
40:33 Maybe do like some sort of polyfill or try to load the version, Python two version versus Python three or something like that.
40:40 Right.
40:40 Yeah.
40:40 And it turns out there's some really weird, obscure failure modes of that.
40:45 Like, you know, like somebody might try to import a module.
40:48 Maybe the module exists, but it can't import some other module.
40:54 And then you end up with like these, these like weird failure modes where you might get error messages related to the wrong thing.
41:01 Or it might be kind of pointing you in completely the wrong direction.
41:04 Yeah.
41:05 You might tell the user, hey, make sure you have this package installed.
41:07 They're like, I do have this package installed.
41:09 Right, right, right.
41:10 Right.
41:10 You can get like a false message saying, hey, I wasn't able to detect your package.
41:13 And then the users like they're looking at their directory and they're cursing because they're like, wait, it's right there.
41:18 I'm looking at it.
41:19 Like, why can't you find this?
41:21 I'm going to email this guy the pip list and show him it's here.
41:23 Yeah, right.
41:24 And so, you know, some of the things that you can do now is it's, yeah, I guess in Python terminology, it's almost like a look before you leap kind of thing with import.
41:35 You can go to the import system and you can say, hey, where is this module?
41:41 Do you have this?
41:42 And it can tell you whether it has it or not without actually importing it.
41:46 Interesting.
41:47 What's the code look like for that?
41:48 It's not try import or anything, right?
41:51 You have to import a single function and you just call it.
41:55 It's like a function call.
41:56 Okay.
41:57 Yeah.
41:57 So there's some library call you say, hey, does this thing exist?
42:00 Show me where it is.
42:01 Yeah.
42:02 It actually gives you this thing known as a module spec.
42:05 So it will actually tell you a whole bunch of information about it, like what path it's in.
42:09 Like, is it Python source code?
42:11 Is it C source?
42:12 Is it C module?
42:13 Is it a built-in?
42:15 You know, you can actually find out a lot of information about the module without even touching, without actually loading it.
42:22 Interesting.
42:22 Will it tell you the version?
42:23 I don't know whether, no, because usually the version is inside the file.
42:29 Yeah, it's in the init.
42:29 Okay.
42:30 Well, that's really cool.
42:32 You can do some interesting things with that as well.
42:34 Doing like, I guess sort of module stand-ins, for instance.
42:37 I don't know that this will make sense, but you can make like a, you can basically ask Python to locate a module.
42:43 And then what you could do is make a dummy module to take its place temporarily.
42:48 Like you could make like an empty module.
42:51 And then you could program that to auto-load the source code when it's accessed later on.
42:59 So if you've ever had this phenomenon, probably people have done this, where you do an import on some module, and then Python just sits there for like 30 seconds while it loads the entire universe of code behind the scenes.
43:13 You know, you might be able to use that to kind of solve loading time issues.
43:17 You know, setting up modules where they don't actually load until they're needed.
43:21 You could have, you know, you could do things like that, which is kind of interesting.
43:24 Could you do something insane like kick off another thread to import it, and maybe it'll already be loaded by the time the code needs it actually gets there?
43:33 I hadn't thought of that, but yeah, maybe.
43:35 That probably would be wrong.
43:37 It is kind of insane, actually.
43:39 Yeah, so you could do like a...
43:40 Like a lazy load.
43:41 A lazy...
43:42 It would be sort of a lazy load.
43:44 Sort of a lazy concurrent.
43:46 Yeah, I hadn't thought of that, but yeah, that is kind of devious.
43:50 Yeah, you could program it.
43:53 I mean, yeah, I guess you could do that.
43:55 Man, I'd have to...
43:57 That would...
43:58 I don't know.
43:58 You might have to explain that at a code review or something like that if you sprung that on your...
44:03 Could you just tell me why this is here?
44:05 Who knows?
44:07 Maybe someday Python will have a lazy import keyword.
44:11 Probably not.
44:12 Yeah, I'm just trying to think how that would work.
44:14 I mean, I guess that would be...
44:16 I think you could just kick off a thread and just do nothing but import it, right?
44:19 And then technically, I mean, Python should manage that concurrency.
44:23 And if you don't end up calling the function that actually needed it till later, maybe.
44:27 I don't know.
44:27 So in a sense, you'd be sort of lying to the user, right?
44:31 I mean, they would...
44:32 I'm thinking how this would be useful, like interactively, right?
44:35 They could type the port and it would come back instantly.
44:38 Oh, look, they made it fast.
44:41 The person using it would think, oh, Python is awesome.
44:44 It's so fast.
44:45 And then not realizing that it's actually importing the universe behind the scenes, in a thread taking like 30 seconds or something.
44:53 Exactly.
44:54 It's probably wrong.
44:55 A lot of things are wrong, though.
44:58 It's true.
44:59 Okay, I have to think about that.
45:00 So another thing I wanted to ask you about is, you know, in the init file, it kind of felt like that is there mostly to like structure your import.
45:09 So I'm going to say import this module, this module, this module, put them in the top level namespace and so on.
45:15 But you can write arbitrary code there.
45:17 Do you think that that kind of stuff is like abusing the intent of that?
45:22 Or is it kind of, it's just taking advantage of what you should be able to do?
45:25 I see modules that do that.
45:28 I don't have a strong opinion on it.
45:31 Although I have to say it kind of rubs me the wrong way a little bit to see tons and tons of code in the init file.
45:39 Partly because that's not where I'm expecting to see it.
45:42 If I'm looking at somebody else's code and I want to know, oh, where's the source code for the database object or something like that?
45:48 I'm more inclined to look for maybe a file called db.py or something.
45:54 It doesn't occur to me that the code would be in the init file.
45:59 Yeah, I kind of feel the same way.
46:01 I was wondering what your thoughts were there.
46:03 I try to keep the init files kind of small.
46:07 Yeah, I agree.
46:08 Like I said, more small files is my style as well.
46:12 Just sometimes, you know, I feel like I'm importing a thousand things.
46:16 Yeah.
46:17 I mean, I have seen that technique used.
46:19 I mean, sometimes I run into that where, you know, maybe somebody started with just a single file module.
46:24 And then all of a sudden they want to have unit tests shipped with it or something.
46:29 Like maybe they want to have like a subdirectory of unit tests.
46:32 And they'll do things like, oh, I'll just take my whole module and drop it into the init file.
46:37 How could that be wrong?
46:38 You know, and then I'll have like a separate test subdirectory or something where I'll put my unit tests.
46:44 So I don't know.
46:46 Okay, there's two questions that I like to ask my guests near the end.
46:52 And so I'll ask you those now.
46:54 Do you have any favorite PyPy packages or like libraries that, you know, you think are really cool?
47:01 I just want to say, hey, world, check out this package.
47:03 It's really awesome.
47:05 Okay.
47:05 Well, there are the obvious ones.
47:08 I'm a big fan of pandas.
47:10 Pandas is cool.
47:11 For data analysis.
47:12 Things like requests, SQLAlchemy.
47:15 I think these are used by a lot of people, though.
47:18 So I'm trying to think of it.
47:19 Yeah, requests is downloaded 40 million times.
47:21 Yeah, I'm trying to think of a more obscure, cool thing.
47:27 Well, you're thinking of one of the ones that I was reminded of yesterday is something called passlib that'll do all the management of like hashing correctly passwords and stuff.
47:35 Oh, okay.
47:37 So you can say, here's a password.
47:38 And I want to use SHA-512 hashing.
47:40 And please iterate that hash 40,000 times so it's super computational to like, you know, brute force it.
47:46 And boom, here.
47:47 And that's like one line of code in that thing.
47:49 That's beautiful.
47:49 Okay.
47:50 I have to look at that.
47:52 Well, actually, this is a standard library module that's in Python 3 that I think blows people's mind.
47:58 I had some people in a class.
47:59 They were very fixated on manipulating IP addresses.
48:03 Okay.
48:04 I was like, you should look at the IP address module.
48:08 This is something that's in the standard library in 3.4.
48:10 There's a whole module just related to manipulating IP addresses.
48:14 Wow, I don't think I've even touched that thing.
48:15 Oh, it's like, yeah, iterating over like subnets and all sorts of things like that.
48:20 That might be something to look at to kind of blow people's mind.
48:22 Yeah, that is pretty cool.
48:23 All right.
48:24 Awesome.
48:24 And the other question is, what editor do you like?
48:27 I use Emacs.
48:28 Emacs.
48:29 All right.
48:29 Right on.
48:30 Yeah, I use Emacs back in the day.
48:32 These days I've been doing PyCharm.
48:33 I guess I'm patient, waiting for stuff to start to get all the features.
48:38 I don't know.
48:38 I have too much invested in Emacs at this point to give it up.
48:44 You know, I've been using it so long.
48:48 I don't know.
48:50 Lost cause.
48:51 Absolutely.
48:51 We could almost have a Python 2 versus 3 type debate with Emacs versus Vim versus IDs.
48:57 But we won't go down that path right now.
48:59 Mostly I just like, I like to use Emacs to kind of troll people a little bit.
49:02 So that's always, uh...
49:04 Hey, it's written in Lisp.
49:05 That's kind of fun, right?
49:06 Always fun.
49:07 Yeah.
49:07 So, although actually my big shameful thing with Emacs, I have to admit that I never customize it.
49:13 Oh my gosh.
49:14 I know it has all that Lisp and stuff in there.
49:17 Never go there.
49:19 I have too many other projects to work on than that.
49:23 You don't need to change your editor.
49:25 Just get some work done.
49:26 Just get work done.
49:28 I actually wish they'd fix Idle a little bit.
49:31 Yeah.
49:32 Yeah, I could use some help.
49:33 They like to hate on Idle.
49:35 And I use it a fair amount for teaching classes.
49:39 You know, it has the one feature of it comes with Python.
49:44 And so if you're looking for just an easy way to get started without having to install all this stuff, it's great.
49:51 But it could definitely use some love these days.
49:53 Yeah, I agree.
49:54 All right.
49:56 David, I think that might make a show for us.
49:58 That was a really interesting conversation.
50:00 Before we head out, there's two things.
50:02 One, I want to say people can find your tutorial on YouTube.
50:06 In the previous show, I had a playlist of my favorite talks from PyCon 2015.
50:11 And I'll put that in the show notes.
50:14 But you can just go to bit.ly, B-I-T dot L-Y slash PyCon 2015 M-K, all lowercase.
50:20 And that'll be a list of like 30 really good sessions from PyCon 2015.
50:24 And yours is definitely in there.
50:26 Okay, great.
50:27 Awesome.
50:28 And anything else you want to give a shout out to, let people know about?
50:30 I don't know.
50:31 If you like the tutorials, come take a class with me in Chicago.
50:34 That'd be the only thing I'd say there, I think.
50:36 All right, awesome.
50:36 You got a website they should check out for that?
50:38 They can find it on my personal site.
50:41 Okay, cool.
50:42 We'll put that in the show notes as well.
50:43 Okay.
50:44 All right, David.
50:45 Thanks for being on the show.
50:46 It's been fun.
50:46 Okay.
50:47 Thanks a lot.
50:49 Today's guest was David Beasley.
50:51 And this episode has been sponsored by CodeShip and Hired.
50:54 Thank you.
50:55 Thank you.
50:55 Thank you for keeping this show going.
50:57 Please check out CodeShip at CodeShip.com and thank them on Twitter via at CodeShip.
51:03 Don't forget the discount for listeners.
51:05 It's easy.
51:05 Talk Python.
51:07 All caps.
51:07 No spaces.
51:08 Hired wants to help you find your next big thing.
51:11 Visit Hired.com slash Talk Python To Me to get five or more offers with salary and equity right up front
51:17 and a special listener signing bonus of $4,000 US.
51:21 Remember, you can find the links from the show at Talk Python To Me.com slash episodes slash show slash 12.
51:29 Be sure to subscribe to the show.
51:32 Open your favorite podcatcher and search for Python.
51:35 We should be right at the top.
51:37 You can also find the iTunes and direct RSS feeds in the footer of the website.
51:42 This is your host, Michael Kennedy.
51:43 Thanks for listening.
51:44 Smicks, take us out of here.
51:47 Stay tuned.
51:48 Stay tuned.
51:48 Stay tuned.
51:49 Stay tuned.
51:49 Stay tuned.
51:49 Stay tuned.
51:51 Haven't been sleeping.
51:52 I've been using lots of rest.
51:54 I'll pass the mic back to who rocked it best.
51:57 I'll pass the mic back to who rocked it best.