What if you could bottle up all the wisdom and hard-fought experience of many expert Python developers and power up your skills?
That's what Brett Slatkin did, and he put it in his new book, Effective Python.
This is episode number 25 of Talk Python to Me, recorded Wednesday, August 12, 2015.
Welcome to Talk Python to Me, a weekly podcast on Python, the language, the library's,
the ecosystem, and the personalities.
This is your host, Michael Kennedy.
Follow me on Twitter, where I'm @mkennedy.
Keep up with the show and listen to past episodes at talkpython.fm.
And follow the show on Twitter via at Talk Python.
This episode is brought to you by Hired and CodeChip.
Thank them for supporting the show on Twitter via at Hired underscore HQ and at CodeChip.
It's another week with a book giveaway.
And just like last week's, this one is a really excellent one.
Make sure you're a friend of the show and you'll be in the running to win the free e-book version of Effective Python.
Just visit talkpython.fm, click on Friends of the Show, and boom, winning happens.
Well, sometimes, if you're lucky.
Now let me introduce Brett so we can get right to the show.
Brett Slatkin is the author of Effective Python.
He's the engineering lead and co-founder of Google Consumer Surveys.
He formerly worked on Google App Engine, the PubSub Hubbub protocol, and managing Google's fleet of servers.
Outside his day job, he works on open source tools and writes about software, bicycles, and other topics on his personal website.
And today, he lives in San Francisco.
Brett, welcome to the show.
Thanks for having me, Michael.
Yeah, I'm really excited to talk to you about your book and the other stuff you have going on with Python.
We're going to talk about this book that you recently released called Effective Python.
And I was a big fan of the Effective series back in the C++ days.
And so when I saw your book title, I was like, oh, this is going to be awesome.
So it's going to be a fun conversation.
Yeah, definitely.
And I similarly, Effective C++ was the best programming book that I ever had.
And so I totally agree with that.
So that was 1997 or 1998 when that came out when I first read it.
And being able to make the Python version of that was really a great honor for me to be able to write.
Yeah, I bet it was.
That's great.
Before we get into the details of your book, though, maybe we could just talk a bit about how you got to where you are.
How did you get into programming in Python?
Yeah, so I won't bore you with the super long details of my history of writing code.
But I've been writing code since I was about 10 or 11 years old.
My first job out of college was at Google.
And I showed up for my first day of work.
And they said, OK, here's this Python code base.
You need to make it better.
Here's a book.
And Alex Martelli sits right there.
Figure it out.
So I had seen Python.
I hadn't written any Python at all.
And I went from basically knowing nothing about Python and then actually writing a book about it in about 10 years, which is pretty funny.
Yeah, that's great.
The student becomes the master sort of thing, right?
Yeah.
I hope so.
I hope it's worthwhile.
Well, I think what was funny is that my first impression of Python was from the BitTorrent code base.
Because Bram Cohen had had this post all about Python and how it makes him more efficient.
And that's why BitTorrent's so awesome.
I don't think people realize that BitTorrent was written by Python.
But then like Zope and Plone, I thought were just really, they were code bases that I was very unhappy with using when I tried Python for the first time.
And that kind of turned me off.
So then when I showed up at Google and they said, OK, you're using Python, I was cautiously optimistic.
But it ended up turning out real well.
And so I can just go real quick, just the kind of projects that I used Python for at Google.
Yeah, people would love to hear that.
My first job there was kind of doing janitorial services for data centers.
Google has a bunch of machines in their data centers.
Those machines have a life cycle.
They're built.
They're repaired.
They break.
And I worked on a bunch of the tools to help that life cycle, which are primarily written in Python.
And I got to scale that out into Google's kind of worldwide network of data centers, a lot of system level code, a lot of networking, kind of database accessing, all kinds of stuff like that, workflows.
So that was my first kind of big role.
I did some other things similar to that around security and securing the machines in a data center.
And then shortly after that, that was a couple of years.
And then shortly after that, I heard of this really cool project that was being created called App Engine that had just started.
And I thought it really had a lot of potential.
And so I went and talked to that team.
I think it was four people at that point, the original founding team.
And I was like, what can I do to get on this team?
How can I work on this?
And in my 20% time, I built the App Engine Dev App Server, which is, I don't know if you've ever used App Engine, but you spend a lot of your time using this development tool to actually write your apps.
And so, yes, I built that.
And they're like, oh, this is pretty good.
And then they invited me to join the team.
And then I helped build App Engine out and launch it, which was, so it's, you know, platform as a service, Google's cloud kind of system.
Yeah, that's, it's really cool.
And was Python the very first language or was it Python and Go?
What was it?
It launched with just a restricted set, right?
Yeah.
So Python was the first language.
Java came like a year and a half or two years later.
And then, and then Go came a little bit after, like maybe two, two or three years after that.
I think the first language is actually supposed to be JavaScript, server-side JavaScript in the old Netscape, LiveScript scheme of things.
But in 2008, that seemed like a completely ridiculous proposition, which is pretty funny looking at all the Node.js stuff that's happened in the last few years with V8.
This is way before V8.
JavaScript is still really slow.
And so anyway, so they went with Python because it was one of the main languages that Google had used.
And Google had a lot of expertise in Python in general.
So on the App Engine team, I spent a lot of time working on Python infrastructure, Python APIs,
just kind of the feel of what it was like to write apps on top of App Engine using Python and fix a lot of bugs,
vetted new APIs to go out to make sure they felt good, built infrastructure around task queues and MapReduce and offline processing and all kinds of different things.
Did that for a few years.
And then also started this project called PubSubHubbub in there, which was a real-time RSS project for making RSS feeds real-time,
which is kind of hilarious also in hindsight now since that's pretty – it's kind of like saying I made something to design pogs or something like that.
It's kind of old.
Yeah, that's pretty funny.
But that was the Google Reader days and all that kind of stuff, right?
Yes, the good old days.
Yeah.
I kind of miss that thing still.
I do too, all the time.
I've been using News Blur recently, which I believe is also a Python app written in Django.
But, you know, anyway, I miss Reader.
Yeah, definitely.
So that is a bunch of really cool stuff.
And we might have to come back and talk about that at some later date in more detail.
That'd be really fun.
But let's talk about your book today.
It's called Effective Python.
What's the subtitle?
It's 59 Specific Ways to Write Better Python.
It's kind of based in this – the heritage of the Effective series, which, as we kind of hinted at the beginning,
I think that started out with Scott Myers and Effective C++, right?
Yeah, he invented the format.
And, you know, he's really the guy who came up with this way of educating people.
And all the other books are in his style.
Yeah, that's cool.
And so I remember when I was learning C++, I could sort of do stuff with it.
You know, I could write code and so on.
But after I read his book, I felt like it really took my understanding and effectiveness to a new level.
And so you're kind of trying to bring this to the Python developers, right?
Definitely.
Yeah, that's the goal of the book.
It's a bit of an audacious goal, but yeah.
Yeah, I mean, I think it's really simple is that, like, I read an introductory Python book.
This Effective Python is the book I would have given to myself as a second book if I had had the chance.
So there was a gap in my knowledge that took me years and years and years to fill.
And this book is kind of a way to shortcut and get all that practical knowledge without having to actually pay the dues.
So I wish I had had this book when I was starting out.
You know, we talk a lot about the concept of Pythonic code and idiomatic Python and stuff.
And there's a lot of that concept in there.
You know, like, this is the way you should do things in Python, even if you already know if you could accomplish it using your old idioms from, say, Java or C# or something.
But then there's another part, another angle to it that's just sort of broadening your horizon, I think.
So it's not just about writing Pythonic code.
And I'm thinking of things like how you would use, say, subprocess to manage child processes and parallelism from your Python app, right?
That's not technically a Pythonic thing, but it definitely ups your game and what you can do.
Yeah, I think, you know, a lot of the advice is pure language construct kind of stuff.
And then other things are like, yeah, the subprocess is item.
But, you know, it's important to remember that one thing that they say about Python is, you know, batteries are included, right?
And so, you know, the difference between Python as a language and Python as an ecosystem or Python as a set of libraries that you can use.
When people think of Python, they think of all of it together, both the syntax, the language features that it has, and then the libraries that you know you can rely on to always be there.
So those are tools you should have in your toolbox that are part of being a Python programmer, just like, you know, the collections API if you're a Java programmer, because it's basically all you write all the time.
Yeah, absolutely.
I have many friends that work in other languages, and they often want to compare their language to Python.
And like you said, I think that's not even a conversation you can begin to have if you don't think about the entire standard library and the 60,000 PyPI packages.
And, you know, you've got to take it as a whole, right?
It's not just, here's how you do properties here and properties there.
So this is either better or less good, right?
Yeah, totally.
I mean, a lot of these things, you have so much, I like to use the word leverage, you know, to describe, you get to stand on the shoulders of giants.
There's a lot of different ways to say it.
But yeah, things like NumPy, as an example of a library, it's a whole ecosystem unto itself.
And trying to do the equivalent in Java or C++ is extremely difficult.
Yeah, that's for sure.
So I thought one way that would be fun to have a conversation about your book is kind of go from section to section or chapter to chapter and pick out a few interesting pieces of guidance from each one of them.
Yeah, definitely.
Yeah, cool.
So you broke your book into six parts, and we'll just take them one at a time.
So the first one is this concept of sort of the libraries and Pythonic thinking, right?
Yeah, that's the first part.
It's actually eight separate chapters is how many there are, because it keeps going.
But yeah, the first one is Pythonic thinking.
Excellent.
So why'd you start with that?
Yeah, I think that it's kind of like the strange universe of Python syntax.
You have to get used to doing things.
Even simple expressions like, I remember when I first started writing Python, and the not operator, as opposed to using the bang or exclamation point, getting used to where that not goes.
And things like is not, as opposed to, you could do A is not B, or you could do not A is B.
And, you know, understanding that the Pythonic way is A is not B. That's how you'd say it.
So you really need this base to start with, so that all the other things make sense or are in context.
Right. I also think it's probably a good way to kind of shock the system a little bit to prepare them for, like, this is a different world, probably, than you're coming from.
Yeah.
And so get prepared to think differently.
Yeah, it's to open, I think it's a good way to say it, because I think it's, if you try to fit it into the way you're writing other languages, you're going to have a bad time.
And you really need to embrace the Pythonic way of doing it.
I had one person told me once that my C++ code looks like Python.
I thought that was a really great compliment, I guess.
But you don't really want your Python to look like C++, right?
Yeah.
Absolutely.
Cool.
So the very first thing that you talk about, literally the first piece of guidance, is to know what version of Python you're using.
And I do a lot of training in Python, and it's always a problem.
Someone's always running the wrong version of Python, or even worse, they're trying to use a package and they install it into the wrong version of Python,
and then they're running the right one or something like that, right?
Yeah, that's a big problem, especially with the Python 3 move that's going on.
You know, you can get confused really easily.
And then a lot of the features that people like to use, like even with statements, are actually more recent developments.
So if you're on some old version, some versions of macOS are like running Python 2.5, and you don't know it,
and you try to do simple things like a with statement, it doesn't work.
And so that can be very surprising.
So it's always good to check your assumptions.
Yeah, absolutely.
So sort of level set, all right, we all know what we're talking about.
Now we can move forward, right?
Yeah, exactly.
So what I think probably a lot of people are familiar with, but some are not, is sort of working with sequences.
And you say you should prefer using list comprehensions over like chaining a map and a filter call together.
Yeah.
Yeah, so I think if you, yeah, I think the story, so it's interesting, because if you look at the history of Python, people will talk about how, oh, I like Python, because it's kind of functional, but it's kind of object oriented, and it's kind of scripty.
And so you'll still see examples or guides today.
You'll be searching around the internet, and you'll find some old guide on active state from like 2006.
And it's like, here's how you should use map and filter.
And, or even 2003, like, you know, a long time ago.
And those are useful tools, sometimes they're useful, but the list comprehension syntax is just so much more pithy.
I think that Python over the years has added more and more tools to maximize the readability of code, and to minimize the visual noise, the extra parentheses and brackets and various symbols that you need to express something.
And so I think that map and filter are kind of just antiquated tools that are in the language, because they're hard to take out, because they're, you know, kind of keywords, built in functions.
If I had my way, I would just take them out, because I think list comprehensions are better.
This episode is brought to you by Hired.
Hired is a two-sided, curated marketplace that connects the world's knowledge workers to the best opportunities.
Each offer you receive has salary and equity presented right up front, and you can view the offers to accept or reject them before you even talk to the company.
Typically, candidates receive five or more offers in just the first week, and there are no obligations, ever.
Sounds pretty awesome, doesn't it?
Well, did I mention there's a signing bonus?
Everyone who accepts a job from Hired gets a $2,000 signing bonus.
And as Talk Python listeners, it gets way sweeter.
Use the link Hired.com slash Talk Python to me, and Hired will double the signing bonus to $4,000.
Opportunity's knocking.
Visit Hired.com slash Talk Python to me and answer the call.
But yeah, the main thing is that, you know, if you have two ways of doing something, I think the Pythonic way of doing it is always the more clear and more explicit and obvious way of doing it.
And so yeah, so that's why I think list comprehensions are definitely the way to go.
Yeah, that's cool.
I totally agree.
It's not exactly a more declarative way of programming, but it's closer, right?
That's nice.
Yeah, it's more obvious.
Sort of related to that, one of your other pieces of guidance was that you should use generators for large list comprehensions.
Yeah.
It's so easy to switch from one to the other, but when should I use one?
When shouldn't I?
What's the story of that?
Yeah, so I think that, you know, Python can use a lot of memory is one big thing.
And depending on what you're trying to do, if you're dealing with a small data set that entirely fits within memory, then you don't have to really think about this.
You can just read everything as a list and just work on lists.
So if you're reading a file, like a CSV file, and you want to deal with it line by line or something like that, then reading the whole thing into memory is fine.
But what always happens is you end up wanting to do something a little bit bigger than you expected, especially with a lot of the data processing stuff that people are doing in Python these days.
And so I'm trying to change the culture a little bit to say, hey, why not use a generator if you can?
Because if you use a generator, then all of these memory problems go away.
A generator returns one item at a time.
It doesn't fully materialize the list.
So the total memory space that's occupied is just the last thing you return from the generator.
The rest of it gets cleaned up, garbage collected.
Yeah, that's fantastic.
Especially if you're like chaining one to another to another, and they're kind of building up.
It's really efficient.
Yeah, and to that point, I mean, I think that if you start by at the base level, like if you want to switch to generator code, it's difficult because you have to, you have to,
put generators all the way down to the leaves of your call stacks.
But if you start with generators at the leaves, then it's very easy to start saying, hey, you know, I'm going to turn this into a streaming generator.
And so creating those cascades of generators becomes very straightforward.
And so you can get quick, you know, very fast executing code that's easy to follow and uses a low amount of memory very, you know, very cheaply.
And it's very readable.
So that's why I suggest that.
So the final language one that I wanted to sort of point out is something that I always thought was weird is the whole concept of the else statement on a loop.
Yeah.
And something I recently learned is that try except finally also supports else.
It does.
Yeah.
And you have really interesting guidance.
You say, you know what, these, this else statement on loops, maybe not so much, but on exception handling, it's very cool.
It's like an alternative to the catch.
Yeah, definitely.
Yeah.
So I think else, else makes a lot of sense for try except finally, because you're basically saying, you know, try to do this.
If an exception happens, do this.
And if no exception happens, then do this other thing.
And that's what the else block is on a, on an exception, kind of try except.
Uh, and so that makes things really clear, clearly delineated what will and will not happen inside your exception handling.
Um, and when you're doing exception handling, you want the, the try block to be as small as possible to narrow what you're catching.
So that, that exceptions you didn't plan to catch are raised back up.
That's, that's like a really important thing.
Yeah, that makes sense.
And the other thing is, you know, you might think, well, just the last bit of code in your try bit, your try try block could be what would go in the else statement, but that doesn't account for like early returns.
And so, you know, if you were to do, try to do some stuff, if this, oh, just return, it would still run that else, but then you'd have to be really careful, you know, trying to put that cleanup all over the try.
So yeah, it's really nice.
Yeah, it's nice.
And yeah, you can put like final cleanup stuff in the finally, and that'll always run if you have an early return.
And if you have an else with an early return, that'll also still run the finally.
So it's, it's super nice.
Going to that back to that for loop part of it.
Yeah, I think that's one of the big things.
Like when people first learn about that in Python, they're like, oh, this is so great.
I can, I can use it for doing this and that.
And it's, there's really, yeah, I think it's something to avoid.
It's kind of like, it's a shiny new toy and you want to use all the different parts of it for you, you know, and you have to like stab yourself in the eye before you realize that you're getting, that wasn't a good idea.
That thing hurts.
Yeah, it hurts.
Like, oh, it's short.
It's pointy.
I shouldn't touch that.
And I was talking to, I was talking to Guido about this one in particular because he said, you know, cause I was asking him what he thinks about this one.
Cause it's kind of, it's kind of tough.
I had worked with Guido on App Engine for a few years and, so, and I see him at PyCon from time to time.
And so, you know, I felt bad by saying like, hey, you shouldn't use this part of the language.
I just, you know, wanted to make sure it wasn't ridiculous to him.
And, you know, he said that it's actually an implementation detail of how the Python, the CPython runtime is implemented.
Um, the way that the for else block, the else with loops works has to do with the way these go to statements actually work in the Python interpreter.
Uh, and so if you, if you, if you wrote that code, then it makes perfect sense because the else has to do with the way the certain switch or go to statement works.
Um, it's switch statements.
Sorry.
It's not a go to thing.
It's a switch.
And, but if you don't have that mental model, then it makes no sense.
And, you know, I think that, so for, for Guido and maybe other people who've hacked on the core, they just get it and it makes sense to them, but everyone else they have, it does the opposite of what you would expect.
And so just because of that, I think it's too sharp and I think it's something you should avoid.
Talk Python to me is partially supported by our training courses.
Do you want to learn Python, but you can't bear to subscribe to yet another service at Talk Python Training?
We hate subscriptions too.
That's why our course bundle gives you full access to the entire library of courses for one fair price.
That's right.
With the course bundle, you save 70% off the full price of our courses and you own them all forever.
That includes courses published at the time of the purchase, as well as courses released within about a year of the bundle.
So stop subscribing and start learning at talkpython.fm/everything.
All right.
So the next chapter was functions and there's a lot of good stuff in there.
One of them that I'm a fan of is the whole sort of concept of it's easier to ask for forgiveness than permission.
Okay.
And, you know, that sort of manifests in your recommendation of saying prefer exceptions rather than returning none from functions.
Yeah.
Yeah, definitely.
Yeah, this one I think that people, they're always looking, I don't know if you've ever heard of like a tribool.
There's always this joke about a tribool.
It's a Boolean value of three, you know, values, tribool.
People are always dying for a tribool because it's, you know, it's true or it's false or it's some exceptional case that's neither true or false.
And none in Python ends up playing that role a lot of the time.
And that's a problem because in Python, both false and none evaluate false.
They're falsy values.
And so what ends up happening is it introduces a lot of bugs into your code because you say, hey, you know, x equals this function call.
And then if x, then do this other thing.
Or if not x, do this, then there's an error.
But if you're returning none, then that if not x kind of statement is going to run no matter what.
And so my whole point, I've been hit by this bug in production a whole bunch of times.
I had to learn this one the hard way over the course of many years.
And I'm still managing a code base that has a bunch of this in it and trying to take it out.
And so my advice here is if you have anything exceptional, just always raise an exception.
That's what exceptions are for.
I think people coming from other languages are used to exceptions costing a lot of CPU time or somehow, you know, cause a lot of cache problems.
And that's true for C++ and other languages.
But in Python, raising exception is a little bit of cost to it, but it's not enough to matter.
And the clarity is worth it.
Not enough to introduce bugs into your code, right?
Yeah, exactly.
It's like, okay, well, it's fast, but it doesn't work correctly.
It's like, all right, well, if that's what you want, then that's fine.
Yeah, that's not a trade-off you want to make, right?
Yeah, not the right trade-off.
Sure.
So another one you had around functions that I thought was good advice was if you're going to return a lot of data, just make that function a generator rather than returning a list.
Yeah, and this kind of goes hand in hand with, you know, generator statements that I was talking about before.
I think I kind of covered both of those when I was talking before.
So, you know, generator expressions, there's list comprehensions, which, you know, are a fastest way of doing map and filter on lists.
Then there's generator expressions, which is a way of doing exactly the same thing, but the data is generated one at a time.
And then a generator function is just a, it's not just a one-liner, it's like a full function that does this.
And that's, so what I was talking about before, I think I kind of conflated both of those together.
Yeah, I think just having functions that return, that are generators, like I was saying, lets you kind of start with the leaves and move up to make things streaming.
Yeah, and it's so easy to just throw in a yield, you know, instead of list.append or whatever, right?
Yeah, exactly.
It's very clear.
And what's interesting is that, you know, JavaScript and other languages are adopting the yield semantics because it's such a powerful tool that people love to use, which is really great.
And I'm sure Python stole it from something else.
I actually don't know exactly where it yields from originally, but it's a really great tool.
Yeah, it's really great.
And it's one of those that I find that a lot of people, they haven't taken the time to really learn it and appreciate it.
They know it's there and then they just kind of ignore it, right?
But knowing, sort of raising the awareness is great.
Yeah, definitely.
And it should be the default.
I think you should just always, you should like plan to yield.
Plan, like if you're returning and it's not, if you're returning a sequence, like question what you're doing.
Yeah, exactly.
The thing better be pretty short.
So the last one I want to talk about in functions, which I haven't necessarily decided my feelings on it yet, but is if you use keyword arguments, that can help in the expressivity and clarity of functions.
Yes.
So I think the actual recommendation was to use just keyword arguments if you get a chance sometimes, right?
Go ahead.
Yeah.
Maybe speak to that a bit.
Sure.
So, well, I was curious what part you don't necessarily agree with because I'm curious.
So, yeah, I mean, because I have a few different parts to my advice, but yeah, keyword arguments are extremely powerful.
They let you be explicit about your intention.
And yeah, I think that using them in general for optional parameters is really important.
So if you have a function that takes an optional flag, then you should always use, you know, keyword argument is a great way to do that.
No, I was going to say that I totally agree with.
I think where there's an optional thing, it definitely helps because it's not part of what you expect to pass all the time.
Right.
Yeah, because Python doesn't have polymorphism like other languages.
So in Java, you can define the same function name that takes three different sets of parameters.
You know, C++ can do that too.
And in Python, you can't do that.
So the only way to deal with this is to basically add additional optional parameters to one function and have it kind of deal with the various types of input or define a totally different function of the different name, which can get verbose.
Right.
Yeah, I'm not sure I disagree with you.
I just haven't fully internalized that one yet.
Yeah.
So the use case that I was thinking of is if you have some kind of rich IDE, something like PyCharm or Python tools for Visual Studio or something, and you hit open parenthesis and there's like a nice listing of all the parameters without even looking at the docs, which for optionals, I think that still does show up.
But if you just do like the star star KWRs.
Oh, yeah.
Then you got a problem.
Then it's really like, okay, what the heck can I pass?
Yeah, no, that's totally true.
So star star KWRs, which basically is a catch all.
It's you catch any keyword arguments no matter what they are, including garbage.
It can be a problem.
And this is one of the things that I've tried really hard in the book to do, which is I provide advice that applies both to Python 2 and 3.
So it's not a Python 2 book.
It's not a Python 3 book.
It's like the most overlapping subset that I could find of both.
So it should be relevant to everyone.
And this is a great example.
Python 3 has specific language features that would make it so your IDE will continue to work properly, whereas Python 2 does not.
So in Python 2, you can't say these arguments can only be passed by keyword.
And you want to do that in situations where you're passing two integer values and you don't know which is which.
And so you want to use the keyword part in the function call to make it really clear that, like, hey, this is the numerator and this is the denominator.
And it's not the other way around.
So here's a label in the function call.
Numerator equals 5 and denominator equals 10 or something like that.
And you want to enforce that behavior so that people can't call it by just passing 5 and 10 or 10 and 5 on accident.
And so in Python 3, you can just add this star into the arguments list and then that's enforced by the compiler and everything's great.
And in Python 2, you can't do that.
So that star star kwrks is a way to deal with that.
And you're right.
It breaks your IDE.
It makes it harder to understand the documentation.
You have to make that tradeoff for you and say, hey, how error-prone is this function?
Is it worth doing this, you know, having these optional parameters that are in this way?
And, yeah, maybe there's a better design that you could have, maybe a helper class that would be a better way to approach it than having kwrks, star star kwrks, sitting there.
Right.
It's definitely a cool language feature.
It's just I think sometimes it gets overused and you're like, okay, I've got to basically keep the documentation up for a while so I know what my possibilities are, you know?
You're totally right.
I would say don't use star star kwrks unless you're doing something like this.
I think it's one of the few times you should use it.
There's some other glue kind of infrastructure times that are good to use it if you're doing, like, generic wrappers of functions and stuff like that.
But in general, I try to stay away from it.
And I'm really happy that Python 3 has this extra forcing keyword arcs feature.
Yeah, that's cool.
Okay, then I definitely agree with you.
Okay.
Thanks.
This episode is brought to you by Codeship.
Codeship has launched organizations, create teams, set permissions for specific team members, and improve collaboration in your continuous delivery workflow.
Maintain centralized control over your organization's projects and teams with Codeship's new organizations plan.
And as Talk Python listeners, you can save 20% off any premium plan for the next three months.
Just use the code TALKPYTHON, all caps, no spaces.
Check them out at Codeship.com and tell them thanks for supporting the show on Twitter where they're at Codeship.
So let's move on to classes.
One thing that Python supports is multiple inheritance.
And speaking about, oh, that's sharp, that hurts, is I did a lot of C++ and even COM with insane templating, multiple inheritance.
And I just, I kind of prefer single inheritance and just keep it really simple.
And so you were, you're saying that to some degree and you're saying, look, this multiple inheritance stuff should be used for mix-ins.
Yeah, definitely.
Yeah.
So I.
Can you tell people what you mean by mix-ins in this case and like how that would go?
Yeah.
So I think that a mix-in to me is, is a set of functionality that you can add to a class.
You can add to any class.
So helpers for serialization, helpers for logging, helpers for, you know, doing some kind of introspection on functions and stuff like that.
Those are the mix-ins where you're like, hey, I have this class.
Wouldn't it be nice if it automatically logged every function call or something like that?
Or every attribute access.
Let me, let me, let me inherit from this mix-in utility to do that for me.
So I think that those are the times where you want to use multiple inheritance, where the class structure doesn't actually matter.
It's more like aspect-oriented programming or something like that, where, which I'm not necessarily a huge fan of, but I'm just trying to say that it's nice to be able to kind of compose functionality.
And so mix-ins are a way of doing composition with class inheritance.
If there were another way to express that composition in Python, that'd be great.
But the tool that we have is, is multiple inheritance.
Yeah.
And I have seen some really beautiful mixing code that, that when done right, right, is nice.
Yeah.
When it's done correctly, it's, it's really, really nice.
And, and it doesn't, it's not brittle.
I think a lot of the time, multiple inheritance is, is really brittle and it breaks in weird ways when you refactor it.
And mix-ins are built not to be brittle.
And so that's why it works out.
So it's about composition, primarily.
Nice.
So let's move on to the next section, meta classes.
Yeah.
And in there, one thing that was sort of stood out to me was you're talking about that you can register class existence with the meta class.
What's the story of that?
Yeah.
So, you know, meta classes are like the sharpest tool you can poke yourself with in Python.
And it's kind of like, once you use it enough, Python enough, you're like, okay, I'm going to try out these meta classes thing.
And maybe you read Eric Raymond's thing about meta classes and some email filtering thing he wrote with them and how awesome that was.
And you realize that essay is from 12 years ago and it's worth to think about that again.
But it's a really powerful tool.
I have three different kind of main ways I think you should use it in Python.
I don't think you should use it in other ways unless you really know what you're doing.
And the registration is one of the big ones.
So it's really nice to know, you know, if you're creating infrastructure and you're creating, you know, classes to represent database tables or sensors that self-register,
a lot of that kind of like, you want the program to kind of sign itself up and initialize itself up so you don't have to write a lot of boilerplate to say,
oh yeah, hey, remember, configure this sensor, configure that sensor, configure this database row.
You know, you have a lot of programs end up having these main functions that are just like lists of registration calls for 100 lines of registration.
And then it says go after that.
And so meta classes give you a really nice way of saying, hey, anytime anyone creates a class,
it's part of this hierarchy, register it in a central database of classes or central, you know, dictionary of classes so that when I start my program,
I can go through and do all the housekeeping I need to do for initialization.
So that's one thing, lets you do initialization really easily.
And it also lets you do lookups really easily.
So you say, hey, you know, is there a class that does this in the system?
Yes, there is.
I know exactly where it is.
It's right here.
I've already imported it.
I've already looked at it.
I know what it's capable of.
So anytime you see yourself doing that pattern where you have one of something now and you're going to have 50 of them later and you need a registry of those things,
there's no reason to explicitly register things.
You should always just have them automatically register themselves so that it's less error prone.
And that's the big thing that I'm trying to kind of advise you to do here.
It's, you know, we're humans.
We leave things out all the time.
And so helping people make fewer mistakes is really important.
And so metaclasses are a great way of helping people make fewer mistakes.
And that's what that item is specifically about.
Nice.
The other sort of topic you talk a little bit about there is attributes.
I think you talk about like private versus somewhat private, you know, the sort of underscore versus double underscore attributes in there.
Is that right?
Yeah, I think it's a common thing also that people have when they come from other languages that have like strict definitions of public and private.
And, you know, Python doesn't have those things.
It has kind of best equivalents of that.
And the gist of it is, you know, you should just make everything public by default in almost all cases.
Because people are going to go in there and reach in and make things that are private, public anyway.
There's some nuance to it, but that's the gist of it.
And Guido refers to this as, you know, we're all consenting adults.
You know, you should let people reach into the class and use it however they want if they want to.
As long as you know you're getting yourself into trouble, then, you know, if you're willing to take on that risk, then it's up to you.
So, yeah, I think the whole idea here is that Python is a dynamic language.
So things are mutable and more fluid.
So you don't have to have this kind of draconian public-private enforcement that maybe Java programmers have.
It's interesting that other languages are so focused on not letting people do things by default,
where Python is focused on really letting anyone do anything with a class by default.
Yeah, that's an interesting just language philosophy statement altogether, isn't it?
Yeah, it is.
And some people say that's why Python gets difficult for really large projects,
because that's why defaulting to closed is good.
It's because once the project's a million lines of code, then, you know, it's too late.
I understand that.
But I think, you know, a million line Python project is a very large program.
A lot of people have never worked on something that size and probably never will.
So it's kind of like one size does not fit all.
Yeah, that's a good point.
I mean, I see a lot of people that learn design patterns and other things, and they just want to apply them.
Exactly.
To whatever, right?
But these design patterns maybe make sense on very large scales or certain circumstances, right?
Absolutely.
And that's why I think all the advice needs to be in context.
You know, okay, you're giving me this advice.
Who are you?
What are you doing?
How big is the code base?
You know, like, how often do you have to do it?
Like, I need to know those things because your design constraints are different than mine.
So.
Right.
How similar are we?
Yep.
So one of the sections I really liked, and I'm looking forward to digging into it more,
is the concurrency and parallelism section.
Yeah.
And you draw an interesting distinction between what you're calling concurrency and parallelism.
Can you maybe speak to that first?
And I think this goes back to, there's this great talk that Rob Pike, who's one of the
creators of the Go programming language, a language who also works at Google, he did called concurrency
is not parallelism.
It's a great, great talk to check out.
But yeah, it's basically, you know, concurrency is a programming pattern.
It's a way of doing multiple things at the same time and having tools to let you do that at the programming level.
So threads are one of those tools.
Coroutines are one of those tools.
And then parallelism is actually running two lines of execution on a processor at the same time.
And that's not necessarily a programming tool.
It's just the way that the program runs.
And Python is great at doing concurrency style stuff.
But Python can actually do, cannot do parallelism because of the global interpreter lock, which I'm sure people listening to this have probably heard of.
But that's one of its big shortcomings as a language.
Concurrently, you're thinking of maybe I'm going to make two web service calls at the same time and I can wait for one to come back.
But parallelism is I'm trying to compute this financial algorithm and it's just a computational thing.
And breaking that up into steps and trying to run that with threads is not really going to do much for you, right?
Yeah.
Or if you're trying to decode two frames from a video stream simultaneously on two different CPU cores, you can't do that in Python without actually going down to the C API.
Whereas asynchronous things, you can do it in parallel.
You can even run threads where that computation looks like it's happening in parallel, but it's actually not.
It's happening concurrently.
So you can't increase your throughput of computation with threads or any kind of concurrent infrastructure in Python.
You can't get parallelism, cannot get parallelism that way.
Right.
So your first piece of guidance was to use the subprocess module to manage child processes.
And those might be Python subprocesses or they might just be other executables, right?
Yeah.
And that's a cheap way to get some parallelism because, you know, at the system level, multiple processes can be doing multiple things on multiple cores.
So you can really take advantage of your computer that way.
Yeah.
Nice.
Another one that you had was to use threads for blocking IO, but to avoid threads for CPU parallelism.
And that kind of is a little bit what we were talking about, right?
Yeah.
Your web service calls exactly that.
So you can do a web service call in one thread, another web service call in another thread, and they will happen concurrently.
But they actually won't process in parallel.
So it's great for kind of blocking tasks or IO bound tasks, threads are, but they don't actually help you go faster.
Right.
So verify my mental model here.
I think I recall that if I have a thread in Python and it does some blocking IO, that thread will release the global lock, right?
Exactly.
Yeah.
So you can use threads to avoid waiting.
It's basically all you get.
But you can't use them to.
And so the gill, yeah, will unlock and then another thread will start running.
And that's nice.
And that's what threads are good for.
But that's as far as it'll go.
Right.
Sort of the Node.js style of parallelism, maybe.
Yeah.
It's very similar, actually.
Node has a lot of the same constraints and problems.
It only has one executing thread at any time.
Okay.
So another one was to use or consider coroutines for running many functions concurrently.
How's that look?
Yeah.
This is my favorite item in the book, item 40.
Yeah.
I implement Conway's Game of Life as a set of coroutines.
I would say if you understand this one, then you've understood the Xenopython pretty
well.
And it's basically just trying to say that you can express very complicated, high-level
ideas of the way that things should interact.
Whole system flows should work, workflows, using coroutines in this really abstract way that's
extremely powerful, easy to test, easy to expand.
It's really hard to go into detail without explaining the whole thing from the beginning.
Sure.
It's definitely worth checking out.
It's actually online, fully published.
If you search for it, I think you can actually find it on effectivepython.com because I'm so
proud of that one.
Yeah, nice.
That's awesome.
So you kind of pulled it out so everyone can get to it?
Yeah, definitely.
Cool.
And then the final concurrency one that I thought was interesting was to consider concurrent
dot futures for true CPU parallelism.
Yeah, and this is the kind of hack that someone came up with.
So there's this multiprocessing module that's built into Python now that will actually farm
out work to sub-processes that are also Python.
It's really ridiculous how it works, but for certain cases, it's extremely powerful, and
it will actually speed up your program by the number of cores on your machine.
It doesn't always work.
It also breaks in a lot of weird ways, but when it does work, it's magical because you can go
from something that was slow to something that's 10 times faster.
So it's worth checking out, at least trying.
I just wouldn't go too far.
I think you just summed up multi-threaded parallel programming right there.
It sometimes works, it sometimes breaks in weird ways, and when it works really well,
it's magical, right?
Yeah, it's true.
Yeah, that's very true.
I guess that's no exception.
Yeah, but Python has its own peculiarities about how it breaks and how it works and whatever,
right?
That's a really good point.
People forget to mention that, oh, Python only has one thread.
It's like, that is a problem.
It's a problem.
But multiprocessing, multiprocess programming, multithreading in any other language was also
really hard and error-prone, so let's not forget that.
That's a great point.
There was a group that was referring to the bugs that you get from multithreading as
Heisen bugs, and I really like that way of thinking about it.
Yeah, definitely.
They're very hard to track down.
So let's talk about just one more section in the book, and that was collaboration, like
how you work well with other people and sort of like on teams and so on, right?
Yeah, yeah.
And I think Python is a huge community, like we were talking about before, and so working
with others in Python is really important.
Yeah, that's cool.
And one of your pieces of guidance was to use packages rather than just patch around a bunch
of files, right?
Yeah.
And this all depends on the size of your code base.
You know, when you're starting out, it doesn't matter.
Like until you have 10 files or something like that, it really doesn't matter.
But you know, you should be willing to refactor your code into packages once you realize you
have enough different working pieces, especially if you're working with different people.
It's nice to split things a little earlier than you might have expected.
So you give them room to grow.
It's kind of like you'd buy, you know, if you have a kid, you buy them shoes a little, like
one size a little bit bigger so that they can grow into them.
Yeah.
So packages are kind of like that.
I think it's a good way to modularize your code base before it becomes too late.
And I've been in code bases where it's been way too late.
And we have files, six lines of Python code in them.
And you're just like, why?
How did this even happen?
It's terrible.
Yeah, I can imagine.
Do you recommend having like an internal private package server?
You know, it really depends on your company.
I think if you're comfortable with PIP, then yeah, it's pretty good, especially if you're
doing deployments off of it.
It can be really useful.
If you have a security team that needs to vet things, it can be really valuable.
Right.
Maybe one team that builds the API and another team that builds the web part that consumes
the API or something like that.
Yeah, you can do stuff like that.
I mean, it also depends on your source code repo.
Google, we have just one giant repo for the entire company.
So for us, I don't need a package server because I have the code.
But yeah, it's good hygiene to have people publishing APIs that are stable and to think
about things in that way.
It's kind of the Netflix or Amazon approach to software engineering.
And it works really well, more like a service-oriented architecture, but at the API level.
Yeah, that's cool.
So another piece of advice you had for collaboration was to consider the Reaper method for debugging
output and helping people understand the state of your program.
Yeah.
So yeah, Reaper Reaper print representation.
I don't know why they call it that.
I think it's pretty silly.
But yeah, this is the most valuable tool for me in Python.
Like, print is the first most valuable tool for me in Python.
But the second most valuable tool besides print is Reaper.
Because you can get detailed information about an object.
And you can basically make an object that'll self-describe itself so that when you're debugging, you can
print it out and say, hey, what's in this thing?
What were the parameters that created this object?
How did I even get here?
Reaper and under-under-repper is a really great way to do that.
And Python has built-in support for it all over the place.
So it's definitely worth checking out if you don't use it.
Right.
Absolutely.
If you just take a list and print it, you'll get that representation for all the items it
contains.
That's right.
And it basically evaluates back to the Python statement that it would have taken to create the
same list.
And so you usually can copy and paste reppers back into an interpreter to test them out.
So it's a really nice way to do kind of an interactive debugging session with your own code.
That's cool.
And the final collaboration thing that I actually hadn't heard of was you can understand memory
allocations and leaks with something called trace malloc.
Yeah.
And this is another Python 3 only thing.
And it's wonderful.
Because if you've ever had memory leaks in Python, for especially long-running processes,
it's really hard to track down where your memory usage is going.
Any project of size that I've been on, we run a lot of servers at Google, so we have this
a lot.
You end up having this problem where you look at your garbage collection or your heap, and
it just keeps growing.
You're like, where's the actual space going?
And the tools to do that in Python are horrible.
Python 2.7 and before, they're all bad.
And trace malloc, they finally fixed this in Python 3.
And yeah, it basically will tell you exactly like, this is the object you have too many of.
This is exactly where it was allocated.
Here are the parameters that were used at the time.
And so now it's like, orders of magnitude easier to figure it out, which is really great.
There is a port of that code to Python 2.7, I believe.
But I don't know how well-maintained it is.
And I don't think it's actually, it has to actually modify the CPython run, like binary
itself.
It can't be done as a C extension module.
So I think it'll never be added to Python 2, which is unfortunate.
Right.
So you might have to like build your own version of the source code with that baked in and then
run your code on that.
Which is pretty scary, but it might be worth it.
Yeah, maybe not for use in production too much.
Yeah, I wouldn't use in production.
For sure.
Okay.
So those are a bunch of really awesome things that I think will help, you know, pretty
much people of all level.
Thanks, man.
Yeah.
How long has the book been out?
It's been out since April, basically.
And it's doing pretty well.
And this week we also have a video that's coming out, which is a lot of the same content, but
in me just typing out the actual code format.
So some people who learn better from seeing demonstrations, it might be better for them.
But yeah, it's had a lot of good feedback, a lot of good reviews on Amazon and other places.
A lot of bugs reported of things I did wrong, but not too many bugs.
There's only one bug so far that I'm really embarrassed about where I did a multiply instead
of divide, but the rest of them are all pretty good.
Well, the multiply, divide, what's the difference?
Yeah.
You know, I just, I got confused.
Math is hard.
So people can go get it on Amazon and I'll definitely link to the book, but you have
a book code that we can give to listeners so they can get a bit of a discount, right?
Yeah.
And it's, it's the, the, the code is, FPI, E F F P Y. And the simplest way to use
it is you go to inform it.com like I N F O R M I T.com slash F PI, all caps E F F P Y.
And, that, that lets you buy the book directly from the publisher.
And for some places, that are not in the United States also, it can be cheaper
this way than going through Amazon.
Uh, and it's a, it gives a discount off the ebook version, the physical book, and then also
this new video that just came out this week.
Uh, you can get them all there.
Yeah.
You just released that.
You, released this, this nice new video training version of the book.
So, I'll be sure to link to that as well.
That'd be cool.
Yeah.
Thank you.
Yeah.
You bet.
So Brett, anything else you want to give a shout out to or let people know about that
we somehow didn't touch on?
Um, the only other thing is, yeah, like the, the book websites, effective python.com and,
uh, everything you want to know about me, you can find there, and, please report
any bugs you have.
Those are on, on GitHub with all the example code.
And I'm trying to make sure that, anything that's wrong, I, I, I address in there.
Um, but yeah, if you have questions, there's also a link to
email me directly.
So if you, if you hit an issue, I'd love to hear from you.
I'm happy to answer your question.
Excellent.
So two final questions before I let you go.
What is your current favorite code editor?
If you're going to sit down and write some Python, what do you, what do you open up?
I, I am a sublime fan.
I use text mate for a long time.
Uh, I still use Emacs, when I'm on a, on a terminal.
So I use Emacs every day also.
Um, I don't use VI, but I can use less so I can, I can do the read part of it, I guess.
Uh, and, but yeah, sublime is my favorite, editor.
Nice.
And then of all the 60,000 plus, whatever it is, PyPI packages, what, what ones do you
think people should know about that?
Maybe they don't know.
NumPy, obviously, I guess that's, everyone knows about that one.
SQLAlchemy is an amazing tool, especially the relational package, for doing, database
lookups.
Uh, flask is a great web framework that I like a lot.
Uh, and then there's a bunch of stuff around, speeding up programs that I'm, I'm trying
to get more into.
Um, Theano is one and Numba is another.
These are things that let you use your GPU through Python, which is super cool.
And you can use that for things like neural network training and machine learning and stuff
I haven't really spent enough time doing.
So I think I'm really excited to try out some more of these computational tools and Python
packages.
Yeah, that's really awesome.
If you, you know, people who've looked at it, they know, but if you've not looked at
the parallel capabilities of GPUs, it's like, it's astounding, right?
It's crazy.
And the fact that you can like use that in three lines of Python is crazy.
So I think it's just speaks to the community that Python has of scientists and, and, you
know, it's just such a, such a diverse community.
So it's really great to see these packages, blossoming in Python before many other languages.
Yeah, absolutely.
Brett, it's been a very interesting conversation.
I appreciate it.
Yeah.
Thanks a lot for having me on and asking all those great questions.
Yeah.
And I love the book and I encourage the readers to go check it out and they'll enjoy it.
Thanks very much.
Yeah.
Talk to you later.
All right.
See ya.
This has been another episode of talk Python to me.
Today's guest was Brett Slacken.
And this episode has been sponsored by hired and code chip.
Thank you guys for supporting the show.
Hired wants to help you find your next big thing.
Visit hired.com slash talk Python to me to get five or more offers with salary.
And equity presented right up front and a special listener signing bonus of $4,000.
Code chip wants you to always keep shipping.
Check them out at code chip.com and thank them on Twitter via at code chip.
Don't forget about the discount code for listeners.
It's easy.
Talk Python, all caps, no spaces.
You can find the links from the show on talkpython.fm/episodes slash show slash 25.
While you're there, be sure to subscribe to the show.
Open your favorite podcatcher and search for Python.
We should be right at the top.
You can also find the iTunes and direct RSS feeds in the footer of the website.
Our theme music is Developers, Developers, Developers by Corey Smith, who goes by Smix.
You can hear the entire song at talkpython.fm/home slash music.
This is your host, Michael Kennedy.
Thanks for listening.
Smix, take us out of here.
Chilled in, haven't been sleeping.
I've been using lots of rest.
I'll pass the mic back to who rocked it best.
Developers, developers, developers.
developers.
you