« Return to show page
Transcript for Episode #66:
Faster Python Programs: Measure, Don't Guess
Python is a wonderful programming language that is often underestimated because it's so clear and simple. Oftentimes people mistake this simplicity for being too simple for real-programs. After all, you didn't even struggle to get your program to link against an incompatible static library or battle a DLL version mismatch in your Python app today did you?
Usually we find this simple and clear programming language to be powerful and fast. But what happens when it's not fast enough? Do you have to stop and rewrite it in C, C#, or Java?
Well before you do something drastic, Mike Mueller is here to teach us the techniques and steps to determine why our Python programs might be slow and give us some tips to make them faster.
This is Talk Python To Me, episode 66, recorded Monday, July 4th.
Welcome to Talk Python To Me, a weekly podcast on Python- the language, the libraries, the ecosystem and the personalities.
This is your host, Michael Kennedy, follow me on Twitter where I am at @mkennedy, keep up with the show and listen to past episodes at talkpython.fm and follow the show on Twitter via @talkpython.
This is episode is brought to you by Rollbar and SnapCI.
Hey everyone, it's great to be with you today. I have a couple of news items for you this week; first up- Stitcher. if you've been listening to Talk Python To Me on Stitcher I have some news for you. Unfortunately due to some business practices that I believe are harmful to the podcasting space in general, I have asked them to delete my listing and remove the show from Stitcher. If you aren't familiar with the service, it's basically a podcasting client but instead of just serving my content from my servers like most players do, unmodified, Stitcher downloads my mp3 files, reincodes them into a low bandwidth format and then slices it apart and inserts their own audio adds into my show without any form of revenue share or whatsoever. I don't get a penny from them for this. To me, this is unacceptable. I did a bit of write up about it and you can find the link to the write up in the show notes, the article was entitled "Stitcher and Talk Python Podcast". A farewell letter.
Next up, on a positive note, a review. I want to say thank you to Jamal Moir who did an excellent review of my Write Pythonic Code course called The Course Everyone New To Python Desperately Needs To Take. It's an interesting view on what's good and what's not so good about my course, I gave Jamal access because I was interested in his opinion, I didn't know he'd write a review but I am really glad he did. Thank you Jamal. You can find the link to his review in the show notes. Jamal actually has a bunch of great Python content, so I encourage you to go check out his site.
2:50 Now, let's hear from Mike about making Python programs faster.
2:55 Michael: Mike, welcome to the show.
2:56 Mike: Hello.
2:56 Michael: It's great to have you finally on the show, I've seen a lot of your presentations and I've always thought that they were really great. And today, we are going to take one of your PyCon 2016 presentations and sort of have a conversation around it, about making Python programs faster.
3:10 Mike: Yeah. It's nice to be on the show, I listen to most of your of your podcasts, they are very interesting, so it's an honor to be here.
3:17 Michael: Thanks so much. Well, let's get started by sharing your story, how did you get into programming in Python, I know you've been doing Python for a long time, right?
3:25 Mike: I stated Python in 1999, I worked on my PhD thesis and the task was to couple a numerical model, so we had existing numerical models, one was written in Fortran, one was written in C, and I looked for a language to couple, I knew I was not going to write it in Fortran or C, I just needed to have something else, and I looked at different languages, Java, and other things and then I somehow hit Python and I asked in a mailing list would be a good language to couple things, and then I got a call from Martin Von Lewis, he is German, he is a Python co-developer now for quite a while, and he just talked me into Python. And that's how I got started, so I used it for my PhD thesis and coupled model work which was not very clear that this work because numerical models from different fields, and I put them together and made them work as one model, as one program, and it worked out pretty well.
4:19 Michael: Oh that's really cool, what was the subject of those models?
4:21 Mike: Actually my background is hydrology, there I coupled a lake model, as a ground water model, and the hydrochemical model, so you have this- after mining, you do surface mining. And then you take something out of this sub surface which is a purpose of mining, and then you have the void left and there is void typically it is filled with groundwater and it forms a lake. Now you have this what's called a pit lake and a pit lake is pretty different than a natural lake, in terms of water quality and it was the purpose, to find out the water quality of this lake. And I had to couple this lake model which kind of takes care of the lake itself, and the groundwater model which takes care of the ground water part, and the hydrochemistry which is pretty different form the lake model, typical lake models are very different systems determined by algae grows and stuff like this, and now this lake is different because you have this chemicals going in there actually you have a very acidic lake, most of the time that depends on the nature of this thing, so you have some chemical reactions going on, and they take things out of the sub surface and then a ground moves over the stuff into the lake. And you have a very acidic system which is very different than the natural system, that's what I was working on. And with this one I needed a new model, and I coupled it and I did it with Python, and Python worked out really well for this.
5:40 Michael: Was it a controversial or a big risk that you took, trying to do this with Python? 5:46 Mike: No that was pretty free, so in Academia just the end result counts, nobody will need to look into programming, pros and cons for the lakes and stuff, but the programming part was pretty much on my own and I could just decide whatever I want, and nobody else knew how I do it, as long as it works, it works.
6:03 Michael: Yeah, that's cool, yeah, I suppose probably the major alternatives were things like Matlab, or not other programming languages necessarily.
6:09 Mike: Yes, you look at different systems and of course you have to get into this how you are going to do this and then you see you can extent Python with C and then you can connect C to Fortran and that's how I did it actually, I wrote, at this time you didn't have tools yet, at least I wasn't aware of this, f2py2 which I use now regularly didn't exist yet, so I wrapped every single separating in Fortran with C and then every single C function with Python by hand which is very tedious.
6:38 Michael: I can imagine, but you probably learned a lot doing it, right?
6:41 Mike: I learned a lot, I learned a lot about C API, I tried to keep it as simple which was complicated enough because for every function I had to study this how to do it and looked at examples and this time I didn't have stack overflow anything like this, every single was just if you 6:54 if best and everything was nice. Much slower than nowadays in terms of getting help from the internet.
7:01 Michael: Yeah, absolutely, learning to program or learning the right technique was completely different back then, wasn't it?
7:08 Mike: Yeah, yeah.
7:08 Michael: Yeah, cool. So we are going to talk about making Python programs faster, and you did a really great presentation of that at PyCon and we'll kind of get to the details there but in general, how much does performance matter, like on one hand it might be great to have faster code, but on the other maybe we just get more VMs or pay a little more for a cloud or something like this?
7:34 Mike: The answer is it depends. It very depends on what you are going to do. For lot of people Python is plenty fast, I think for most cases actually Python is pretty fast, for most developers I talked to them and they are pretty happy with it because most of the time data base or the network or something is what causes the problem, most of the time Python is fast enough or this, but I also teach a lot of scientists and engineers and it depends on what they are doing if they just move data from a to b than Python might be fast enough, but if they do simulations then Python is way too slow for a lot of things. So it depends very much on what you are doing, and if they have the right case then you need to do something, to make Python faster, that's one thing, but everything that's faster is always a good thing, and sometimes it doesn't take you a lot of effort to make things faster, that's one case so it's sometimes just making things a bit nicer and as a side effect making it faster, and the other thing is you put a lot of effort into make it faster so you make it actually more difficult to understand but you make it fast because you need it, I think these are two areas here.
8:38 Michael: Yeah, I think you are right, certainly the computational stuff is really important, and I suppose with the websites it depends a little bit if you are a web developer on what is fast enough and how fast you have to be. There was a really interesting study, I think it was by Amazon, it was something around like the price of latency, and it said something like for every hundred milliseconds that our site is slower, we lose some percentage like several percent of business, maybe something like 1% or something of business, and you know, if you have a lot of traffic, that also really matters, right?
9:17 Mike: Yeah, so performance matters, it's just a question if Python is the one that is a bottleneck for the performance it's not totally clear, there can be many other things that cause your site to be slow, it doesn't have to necessarily be the programming language that be other things.
9:30 Michael: Absolutely, for example if you've got a million records and you are doing a non indexed query on your data base it probably doesn't matter what language you are using.
9:39 Mike: Yeah.
9:38 Michael: Right, cool, so let's talk about your tutorial, what was it called?
9:43 Mike: Yeah, it was Faster Python Programs- Measure, Don't Guess. So, you see, the stress is actually on the measuring part, I started out I think in 2007, that was my first two tutorials at PyCon US in Dallas Texas, my first PyCon, and I gave two tutorials right away which was amazing. And actually it was a two part, the first one was more or less the measuring and the second part was actually extending Python with other languages so like C extensions and using other tools there. And, now it's just a first part and there is stress actually on measuring, just getting the grip on your system to find out what is going on, and there are potential points to improve, I think it's very important to have something to quantify what's going on, and see where the problems are and then maybe come up with the solution. And it's very important to measure things so to get make it quantified, and if you just say your gut feeling is it's slow and you have to do something- that's not where you are going to work.
10:38 Michael: Yeah, I totally agree. When I started out doing professional programming, I did sort of scientific visualization tools, I found that lots of people including my intuition was really quite wrong often about what was fast and what was slow, maybe have like some really complicated like wavelet hour and then you think oh, this has got to be just super slow, and some other place where you are just working with the basic data structure and it turns out like the majority of the time you are fiddling with the data structure, or something like this, right. So these measurements idea is really important.
11:12 Mike: Yeah. I can confirm that I do it for quite a while and most of the time I have the kind of feeling what's going on but very often actually I am wrong, so for some reason there is something else I didn't think about it which is very clearly afterwards I say, of course, that's the reason, but you didn't think about it beforehand.
11:27 Michael: Yeah, and that's coming from somebody who's spent a lot of time doing this optimization, right? So even with the experience, sometimes it can still be hard.
11:37 Mike: Experience helps, it helps but it's no guarantee that you get it right, so you have to measure.
11:42 Michael: Right, and of course you can look at code you can say well, I am sure that this version of that code is faster and this version of the code is slower, but if it's 10 micro seconds versus 20 micro seconds like who cares, right, it really matters how you are using the code as well. So one thing I thought was interesting when you talked about your PyCon tutorial, was that you said we are going to use Python 3 and I've been on a big push to like evangelize Python 3 and so on lately as well, and what was the reason you said it?
12:10 Mike: Yeah, so of course, you have Python 3 and you have legacy Python, so I would like to use the current version of Python 3, I teach Python for living and I always use Python 3 whenever possible. Because, outside in the real world there are still a lot of the systems running 2.7, but still, I like to use Python 3 for teaching, that's a nice way to do it and if you want to do Python 2 then it's not that difficult to write programs, it's the same source code that runs in Python 2 and Python 3 if you just take a few steps. Out of all this deprecated stuff in Python 2 and you are mainly there, it pulls from future print something like this, then you are there, so most of the things you can write and that's why you are ready to run in Python 3 and you still have to support Python 2 for some reason and you still can do this. And that's very important because all of us we might redo a load of work later on when you now kind of focus on Python 2.7 even though all your colleagues are still on 2.7.
13:07 Michael: Yeah, absolutely. I agree with you, I think that's great, from futures import with print function and then maybe range=xrange, those kinds of things and then you can write your Python 3 code in a way that it's compatible with Python 2 as long as you- the other way you can get yourself more into trouble I think. Yeah, very interesting.
13:30 Mike: At the PyData Berlin I just gave it a talk about writing code that runs with Python 2 and 3 at the same time, when actually, I think the best thing is use Py 13:37 ork library, maybe you are familiar with this, this gives you a lot of whatever you said but on a much higher level, it has 1000 tests on it and instead of making it own kind of compatibility it will use this library and they take care of a lot of details including rearanging the standard library imports and stuff like this which can be very useful. So pretty much write Python 3 code, that also runs on Python 2; in Python 3 nothing changes, but on Python you get all this compatibility stuff in there automatically, which is very nice and I think it's a good solution.
14:10 Michael: Yeah, it's fantastic. And, in 2020 coming up there is going to be no more Python 2 support, and that seems like that's way in the future, that seems like there could be a science fiction show set in 2020 but that's like 3 and a half years away.
14:26 Mike: Yeah, I 14:26 ten years ago and it was like it was yesterday so it's not a long time.
14:30 Michael: Yeah, that's right. Let's dig into some of the topics of your tutorial. You started up by saying there are some general guidelines for measuring and understanding performance.
14:41 Mike: The first thing is it the question how fast is fast enough and that's, the question is do I have a case in the first place, so do I need to do something and that's a lot of things, just look at your system and say do I need the performance, what I am going to do with it, it's a one way thing and I am going to stroll 15:02 away, does it matter if it runs half an hour or one hour if I 15:01 away, so if I spent another day improving it just to be half an hour faster and never use it, like the scientists 15:05 one way just 15:10 or something, that could be the case, or the other, you have to have some realistic use cases, is it really too slow- but I am going to do with it, those kinds of questions, that seems very common sense but actually most of things are common sense, you just either think through, do I have a case, do I need to improve it and look through and then again as I said if you have an application maybe it's a data base, check how fast the data base is and if your connection is really Python, can you gain anything out of it, and how much can you potentially gain. Sometimes you can say ok, I can gain lot more than 20% anyway is it worth the effort? If you have to pay for the CPU use, and you use a lot of CPU maybe 20% is worth the effort, if you just wait over night and if it takes six hours or seven hours to calculate, the scientific calculation can really take that long, it doesn't really matter because it runs over night, it does matter if it's finished in the morning, then it's fine. So these kinds of things are very common things so those are the things that you need to maybe reiterate after a while and you do something if you have a case. That's the first thing.
16:07 Michael: Right. And then the next one you said was sort of the whole story around premature optimization, like don't optimize as you go, write your code in the most understandable way so that it works and then think about performance, right?
16:20 Mike: Yes. Firs make it right then make it fast. That's very important.
16:25 Michael: Yeah, yeah, and the make it fast part is all about the measurement, yeah?
16:28 Mike: Yeah, the first thing, focus on the measurement, how to measure, there is other tools out here, I use most of the time C profile which comes with Python which is a good tool, the other tools now actually are doing a big thing and I just had this beta stage kind of profiler which is probably quite a bit better because when you measure something you almost influence your system, there is no way out of it so the question is just how much we influence our system, if it's 1% it seems to be ok, if it's 100% it doesn't sound very right, so and you don't know, the question is you don't know much you influence your system most of the time, and then you want to have some kind of profiler that doesn't interfere too much with your things, especially in measure of time, and things that are very short then the timing might be too coarse to give you some reliable results.
17:21 Michael: Right, or the overhead to time very small function calls might be ten times the cost of the function calls, so...
17:28 Mike: Yes, and that's kind of tricky how to do this, how to measure this actually.
17:31 Michael: And you can't avoid this, right, this is sort of the Heisenberg uncertainty principle, kind of like it behaves in one way until you observe it then it behaves in a different way. So it seems really important to me to look at the difference, to measure one version change her algorithm and measure again, rather than try to just you know, poke at it and say well I ran this test and now this is slow, right.
This portion of Talk Python To Me is brought to you by Rollbar. One of the frustrating things about being a developer is dealing with errors, relying on users to report errors, digging through log files trying to debug issues, or a million alerts just flooding your inbox and ruining your day.
Rollbar has put together a special offer for Talk Python To Me listeners- visit rollbar.com/talkpythontome sign up and get the bootstrap plan for free for 90 days, that's 300 000 errors tracked for free. But hey, just between you and me, I really hope you don't encounter that many errors. Rollbar is loved by developers, awesome companies like Heroku, Twilio, Kayak, Instacart, Zendesk, Twitch and more. Give Rollbar a try today, go to rollbar.com/talkpythontome
19:29 Mike: Yes, it's very important to compare to something, ok that's this version and this version the difference is very small, but this version is twice as long by you do spend as much efforts to make it just a little bit faster, maybe it's not worth it, it's much easier to understand shorter version and longer version and gain 10% and just say how often is this called and what does that 10% mean for my whole application.
19:51 Michael: Right, absolutely. You've gone through and you've measured it, now you decided ok, it's time to make it faster and you had some really good advice that you probably shouldn't start trying to make it faster before you have good test coverage right?
20:03 Mike: Yeah, that's a big problem, especially with scientists, so even though science is supposed to usable, test coverage is not something that a lot of scientists use, I think you cannot generalize this but very often a lot of scientists, it depends on how much they program, they might not even use version control in any way or something, some people do for sure, but some don't and also they don't know that measuring means just run it and look at the results and say that's right, so when I say test you want to have automated tests or something that you can use later on. and that's a bit a problem of the scientific community, it depends, some scientists do this but some don't do it all and then if you try to increase the performance you change your code and when you change your code you might change behavior, and you don't want to change the behavior, you want to have the same result int he end, but just be faster.
20:57 Michael: Yeah, absolutely, you don't want it to be really fast and wrong, that would be terrible. But I think testing scientific results can be super tricky, right, you change the algorithm and you've got floating point cut offs and different heuristics and it might still model the thing correctly but in a slightly different way and so you can't just do like old value== new value sort of analyses, right?
21:21 Mike: No, you need some help, so you need to do something and like Numpy provides a few helpers and Numpy is package you use in scientific programming quite a bit and they have often some help to compare arrays with some tolerance so you can say I want to compare, the tolerance can be x so it doesn't have to be exactly the same, it can be small 21:39 which is totally normal if you do a numerical calculations. And you do a lot of them then there would some small differences, those kinds of things, there are some tools that make the work easier.
21:51 Michael: Yeah, I think there is a couple of really interesting speed ups that you talked about, and one of them I am sure it's obvious once you know about it, but depending on your background where you are coming from, maybe you just have no awareness or it's not on your mind in terms of thinking about performance, but alternate interpreters or runtimes, right, like under certain circumstances you might be able to switch your code from say CPython to PyPy and get pretty serious performance improvements, right?
22:17 Mike: Yes. That's true. So, PyPy can be very nice especially numerical competitions for loops and when you write a for loop in pure Python and you use only integer or floats in there typically PyPy can find this out and just make it faster, so compile it to the machine code and the background, and very often do you get close to C speed, so the range of C speed then writing to same loop in C which can be easily in fact faster even more than pure Python.
22:46 Michael; Yeah, so if you need a 20% speed up and you get your code run on PyPy maybe you are already done, right?
22:51 Mike: Yeah, yeah, very likely you are done, PyPy of course they have this benchmark and I think it's a very big benchmark, and the effect is 6.5 times faster, so that's way more than 20% for average benchmark, there might be, I think they don't have a single one slower actually, the worst thing is just to get the same thing, so as soon as you have a problem- it's not going to work for something like 23:16 get the time is in starting like the active program, so of course PyPy is slower in startup, it works for things that are computationally expensive and will be repeated many times, if you do something only twice here and there PyPy doesn't have any ways to do it, it has to be done like 10 000 times and then PyPy says ok, it's doing always the same thing I can compile this one to machine code, and then you can get the speed up, which is pretty close to C, actually they had this one contrived example, PyPy was 23:45 in C because PyPy managed to inline some function calls, we have C just static compiled and called some library functions, and PyPy was a bit faster than C which was of course pretty contrived but still, you think close to C.
24:02 Michael: Yeah, it's really cool to see those examples thought that you know, that's a possibility right and if you use it in the right circumstances, very cool. let's suppose we've decided that we need to make our code faster and just to keep the conversation a little bit simpler let's say we'll stick to C Python for whatever reason. So, you talked about a couple of tools that we can use to understand our code and a variety of them; the first thing you talked about was this thing called Pyston, what's that?
24:29 Mike: Pyston is just a benchmark, it's a simple benchmark, a benchmark is always wrong in one way, because benchmarks are designed to measure some kind of the performance, but maybe they are better than us, Pyston comes with Python, so it comes with the Python's standard installation, and you can run Pyston and this gives you feeling of because it's pure Python that would run with C Python, with PyPy, with Jython, with iron Python whatever you want to test it with, and you can see how fast the Python installation is and of course it is also connected to your hardware, but if you run it on the same machine, then you get a Pytston, you can also have this kilo Pytstones or something can gets you a big number but also gives you a time, the bigger the Pystons are better or the shorter it's fine of course, and you can see if you run this over this Pyston you can have a very rough comparison of different Python interpreters, and of course, if you run it on different hardware, the hardware will be included in this thing.
25:24 Michael: Right, for example if you are working on your dev machine but then you have some big virtual machine in the cloud that you are actually going to run your code on, you could say well if it's taking this long here and I can compare the Py stones from my dev machine versus production, then you get like a little bit of a sense for the scaling factor up or down, right?
25:42 Mike: Yes, so it's pretty controversial if Pystone is a good benchmark, so it's one of the benchmarks if you want to you can take all the benchmarks, you could go for the PyPy benchmark and see how this works out of benchmarks around, to run it, but the thing is simple, because it's there you don't have to go and get make it work because it's suppose to work it's a part of the standard library, and as far as it works with Json and it works with IronPython it works with PyPy it works with CPython from the old Python 2 and Python 3, you can get a feeling how fast your Python is.
26:14 Michael: And then the next thing you talked about is using CProfile to measure your code.
26:18 Mike: Yeah, a bunch of profilers around one of them is Profile it's written in Python which has a lot of overheads so it's not really recommended, and C profile is, so it's just written in C so the overhead is much less-
26:30 Michael: But it only works on CPython, right, it won't work on something like PyPy will it?
26:33 Mike: It works only on CPyhon, so I focused this on CPython because- it's more about the principles than about the tools particularly Ii would say, just get people kind of a workflow how to do this and if you have a different setup, you might need to use a different system, like if you work on Json you might use some profiler say Java gives you or something, I am not an expert in this field, but the procedures are the same, so you want to measure. And my caution over this is those tools can be wrong- sometimes you get strange results, and you always have to question it, but you might find a second or third way to measure a pretty much the same thing. In C look if their results correspond somehow, if you get totally different results, with different tools for the same kind of measurement, then there must be something wrong with the tool or how you applied a tool. Maybe you just used it in the wrong way.
27:25 Michael: Right, or even there is some really crazy overhead like you are calling a function a million times but the measurement of it is so much larger that it's just completely out of wack right?
27:34 Mike: Yeah, yeah.
27:35 Michael: Ok, and so if I had like some method, and I wanted to profile this, what's the steps, like what do I do with C Profile to get this rolling?
27:43 Mike: So, first I show you a slow way to do it just with the standard library, so it's just import CProfile, you have to make instance of the class profile and then you have several possibilities how to call a method, you just can put the method in this arguments, you can also use a string, evaluate a string, and then as Python code and get the results, and then you get an object that represents the results and then it called different kind of 28:10 to other evaluation methods on it and it shows you the results. The Cprofile only goes by functions, so the finest resolution you see how much time it takes to run one function call, it shows you how many times a function being called how long it took per call and how long it took in total. And you have lot of ways to sort this by the most calls, the longest times and you can also sort who called who so you can have the relationship this function called this function, so you get some kind of the graph there.
28:43 Michael: yeah ok, yeah that's really nice. And then you also use Jupyter notebooks, to do some cool stuff there?
28:48 Mike: Yeah, so if you mind it easier, so a Jupyter notebook is actually the killer application of Python, I would say, because the Jupyter notebook they have what is called %prun which is kind of a wrapper around CProfile, there is no new functionality in this case, but it makes it much more convenient, so instead of doing 3 steps importing the instance you just say prun and prun takes them like command line arguments so you can specify how many times you want to repeat or whatever you want to do, and then it runs your function call and it gives you all the results in the same way, which is very nice so it is- if you use the Jupyter notebook it was called IPython notebook nowadays it's Jupyter notebook, you should use it anyway, it comes from the scientific field and it's used a lot so if you go to your scipy or scipy conference pretty much everybody is using notebook, but it can be useful for anybody who is programming in Python just to try something out, and this profiling means you try something out, try something again and again, so the Jupyter notebook is great for this and this gets you pretty much everything you can do with Cprofile just much shorter and much more convenient and if things are shorter, than you are more inclined to do something so it makes more convenient to do something then you will do it more often and measure more often I would say.
30:06 Michael: Yeah, the easier you can make this and the more automated you can make it the more people will do it right, and with Jupyter notebooks you can go back and you see the cells that you were in before and just kind of like rerun them again if you want to retry it and yeah, that's really nice.
30:18 Mike: Yeah. And then it's, of course, you get a table output but then you say you know, the picture says more than a thousand words, there are some nice tools to actually visualize it, and I use this one called snakeviz you just run snakevizon the output, so on the Cprofile you can sore all this profiling data in a file, and then you read back with snakeviz for instance and then it gives you a nice picture so you can look in a browser and it is interactive thing so it's running this file as interactive so you can zoom in and look at different things and it gives everything a nice colorful picture which is pretty helpful, because you can see in a part of a second what's going on what function takes most time so you can look at it and then you can click and see- have all the information, it's nothing different than the table, but if you have a big table with a lot of numbers it takes you a lot of time to make sense out of it and this style gram you get there it's much more convenient to use.
31:15 Michael: Yeah, certainly when you have tons of data, almost anything like having a really fantastic way to slice and dice and visualize it, it makes all the difference and this snakeviz is really cool. So the way it works is basically you run the profiler and instead of printing out the stats to the terminal or something, you save them to a binary file and then this snakeviz can like suck that up and it runs a little local web server that then opens your browser and you cruise around in there, right?
31:41 Mike: Yes. It's very nice, so you have the table and you can also sort the tables, or have the row numbers if you want to, but you also have this picture and you have two different ones so you have one as a circle like the outer most function is inner most circle and there is going out when you see these circles getting smaller and smaller like fractions of the circle, it's very nice visualization, the other one is called Icicle, so instead of the circle you have the squares, of areas that are rectangles actually, stacked on each other which rather kind of symbolizes this function is calling this function you see that the time goes.
32:16 Michael: Yeah. That's really cool and I think you know, if you have a program that you care about performance, run this through really quick and just look at the picture, and you will probably learn something right away I would think.
32:29 Mike: Yeah, certainly. The case is if you see one big function that uses all the time then you know where to go, if it's very evenly distributed among a lot of functions, then it's much harder because where are you going to start, you have to look at all this functions, in the end, so that's a first thing, you see, you have a case, if all the time it's in this function then it's very worthwhile to look at these functions, if you have 20 functions so they all take about 5% of the time, yeah, we have a no start so it would be much more work to work through all these functions.
32:58 Mike: Right, it is not just low hanging fruit but it's something, it's something different, right. So that's CPU profiling, and one of the ways your code can be slow is just computationally expensive or you could also discover I guess external things that are slow it could be you know, accumulative time for like a disc IO or data base caller web service call, it could be really large and that would tell you that that thing is slow, right.
33:23 Mike: Yes. Actually, you can do the C profile, C profile typically measures world clock time, so the time that actually elaps from the beginning to the start, but it can also provide their own timing function, you could do something like CPU time, so CPU time is what the CPU spends doing something. So if you have something like time sleep in your code, say time sleep 2 seconds and the world clock time will be 2 seconds but the CPU time will be nearly 0 because the process is not doing anything actually, just waiting for you to just time sleep. So this is very important to see so if you do input output you wouldn't see the wait for something that happens in time sleep just lets the process rest in terms of your process, of course the process is still working but not for your process but your measuring. And that's important thing I tried to get across the most of time you measure world clock time, unfortunately, the difference is between windows and unix systems especially in Python 2 if you just use time.time which gives you a time stamp in unix which is nice, on windows it's way to coarse to do anything, therefore you should use time it default timer to something like to get across, because very often you see a lot of online tutorials that use time.time which is totally fine in unix but if somebody is trying to do the same in windows, they might not get useful results. And also there is time.clock which is much faster on windows means measuring time on windows but measuring CPU times on unix, so it's pretty messy. So you might mix things up, you might measure the wrong thing depending on your platform which is not good and therefore I give you like small helper function that gives you also the CPU time on Windows.
35:10 Michael: That's completely non obvious that the time is evaluated differently and sometimes even means something different on the different platforms.
35:17 Mike: I think that it has the reason because it's just a 35:17 around C library, the C library is different on every platform, and Python 3 is better there is 35:21 I think which you kind of 35:24 way a little bit so it's getting better, it's another reason to use Python 3 you have better extraction of this platform extraction of this measurement.
Continuous delivery isn't just a buzzword, it's a shift in productivity that will help your whole team become more efficient. With Snap Ci's continuous delivery tool you can test, debug and deploy your code quickly and reliably; get your product in the hands of your users, faster and deploy from just about anywhere at any time. And did you know that Thoughtworks literally wrote the book on continuous integration and continuous delivery? Connect Snap to your GitHub repo and they will build and run your first pipeline automagically.
Thank Snap CI for sponsoring this show by trying them for free at snap.ci/talkpython.
36:34 Michael: So that lets us measure things like web service calls and data bases as well which is really interesting. But sometimes, it's more of a memory pressure or a memory issue, like maybe the reason our code is slow is because actually we are running out of memory and it's like go in the page on memory on dist for the virtual swap files and all that kind of stuff, right, so can we profile memory as well?
36:55 Mike: Yes. Profiling memory, it's not the simplest thing, but there are some tools out there, and I used to use Hippy, which is part of this 37:04 project but as far as I know it's only Python 2 so far, if I am not mistaken. but there is another project called Pympler, which is also a mix of three different projects in the past and this supports Python 3, they do pretty much the same thing, and if you have a chance actually you can use both of them to compare their results which is always good.
37:23 Michael: Yeah, I saw Pympler and that looked really cool, that's P-Y-M-P-L-E-R right?
37:29 Mike: Yes.
37:29 Michael: Yeah, so Pympler is really easy to use actually, I mean, it is computationally expensive because traversing entire memory structure is not cheap but you just basically import this thing called tracker and you say summary tracker and then you can just later ask for a dif like what has been allocated or deleted since then, right?
37:48 Mike: Yes, so it gets you a kind of the dif what happens and it gives you a dif according to data type so many strings, so many integers, so many floats, so many other types, you can see it and if you called several times you should go to zero; you can see if you called the second time you still have a few kilobyets, if you called multiple times you would have close to zero, so I always stress measuring memory is not something you can measure, it's more about getting megabytes. So you will have a big picture where the things are not totally accurate, but if you have a lot of megabytes then the error is small. And so actually I wrote a small decorator helper so you can put a decorator on your function and it can see if your functions leaking memory so, you measure the memory usage before the function called and after, and if you have the function that kind of like appends to it and 38:36 list or something, then you will see how the memory usage increases. if you just do something to function you just return and you don't store the return value that the function shouldn't change memory so it's kind of simple things, you get the feeling of what's going on and that's always good because Python's easy to write decorators or something so you can write your own tooling that is totally tuned to what you want to do so you have this basic tools and then Python makes it so easy to write some nice special tools for your use cases.
39:05 Michael: Yeah, that was really cool and I really liked the way that you are using decorators in your tutorial, like here you have one called like you know, measure memory or something like that, so you want to measure some function, and all the functions it calls of course, you just say add measure memory in front of it right, and then you get this little summary which is really cool. Yeah, so I guess if you want to answer the question of how many bytes is this 5 or 10 byte thing I have created, like this wouldn't be the way to do it, this is a way to get like large scale pictures of Oh I have 10 million integers and I didn't expect that, what's the problem right?
39:39 Mike: Yeah.
39:40 Michael: But there is also ways to like actually get object size from this library, isn't there like - difficult to know the full like closure of an object graphs, size, right?
39:52 Mike: You can use, so this gets size of sys module which gives you the memory size of one object, but it's only the object itself, like you have a list, you get the size of the list but you don't get the size of all the objects stored inside the list.
40:08 And the objects that they store and the objects that those objects store right.
40:10 Mike: Yeah, and so on. Pympler is giving you this so you can actually measure, and actually I have a very nice example the very interesting, so I start as an empty list and then I keep appending to this list one integer after the other up to a million or ten million actually, and then every time I append I measure the size of this objects and see how it changes, and I use two different ways, I use this kind of built in sys get size of which gives you just the size of the list, and then the other one from Pympler that gives you the whole memory the list and all the integers in my case use up and you can see a very nice step function because that's how IPython actually works so you have a list, and Python always allocates a bit more roughly 50, that's a formula but roughly 50% or so more of memory, and fills this memory and then when it hits the limit, it allocates more and more, if you have ten million appends, I get like a 104 so allocations which is- allocations are pretty expensive, in terms of time, but this makes list so efficient if you do append, if you use some other structure that would need the rebuild or if you use instead of appending to list you insert zero, you inserted beginning of the list that means every time you do this you have to rebuild the whole list and you have to allocate all the memory again which is a big antipattern actually so and it's very nice, you can visualize this why it's like this and you can see a picture on it and I think that if somebody tells you that's a case that's one thing, if you do it yourself and you measure yourself it's a very big difference in terms of experience, you see, ok, I measured myself and I can play around with it and see how things change.
41:45 Michael: Yeah, I thought the graph was really cool because it made it very clear what the algorithm was, you can see that it's basically trading a little bit of memory for a lot of performance. And in the general case, right, in the general case.
41:57 Mike: You can buy memory, so buy a bit more memory it just cost you a few bucks but making a CPU a thousand times faster is pretty hard I would say.
42:06 Michael: Yeah, absolutely. So the other thing that you showed in your tutorial that I thought was really cool, that I don't think we've touched on yet, is line by line measurements. So you could do line by line CPU profiling as well allocation management, right?
42:19 Mike: Yes. You can do this so there is a line profiler, from Robert Crone, he is the author, actually he ported it to Python 3 now, of course I asked him several times to do this, and the line profiler works with Python 3 which gives you a lot of overheads so it makes your program much much slower but gives you a line by line break down because C profiler is just the smallest increment you get is a function and you can do it now a line by line profiling which is especially important if you write a function and you have like calls to Numpy, so in a function you might have 3, 4, 5 calls to Numpy and you can see which call takes the most time, for instance.
42:59 Michael: Yeah, so maybe you use CProfile and those sorts of techniques to go and figure out all right, well I know it's really this function as a problem, but it's ten- hopefully not thousand, it's ten lines long. What's actually slow about that, right, and then you can turn on this line profiler business yeah?
43:14 Mike: Exactly, because you' re only one that have one or two functions you use a decorator at profile, you put a decorator called profile there and then you run it from your profile with some options, this line profiler and then it makes it very slow, it feels very slow, it just has to go line by line and check everything what's doing, and gives you a nice break down you say ok, allocating this list or this Numpy array takes so much time and then looping over it takes so much time and doing this takes so much time, so you could see pretty much where the time goes, which just can be a way that we use for educational, so you get the feeling what these functions are doing, but also useful to make your program faster.
44:00 Michael: You also talked about some anti patterns, things that you should try to avoid- can you go through a couple of this?
44:08 Mike: Yeah, as I said, maybe the most important one is about the list, so if you have a list then you want to append at the end, and maybe when you are done you just reverse a list, you want the other way around instead of inserting at the position zero which is what you want at the end, this would be big anti pattern and this can be many orders of magnitude different in terms of performance if you do this one and this is one of the biggest anti patterns. Another anti patterns is like string concatenation which is old one it's now kind of optimized in C Python so instead of say string += new string in the loop you just use a list and append to the list, take advantage of this list behavior and then at the end you just join the list.
44:53 Michael: yeah, because the list do this pre allocation thing where strings don't.
44:56 Mike: Yeah, so this is actually, it used to be in the beginning of Python so I saw this in Python 1.5, this was my first Python version, it was pretty too, and then pretty soon they changed, they optimized it and it works with CPython but f you use PyPy which is supposed to be much faster than this anti pattern just kicks you, then if you do this for a string of like a 100 000 characters, it just kills a performance and you have to wait an hour instead of a second.
45:24 Michael: Wow.
45:28 Mike: And I remember, there is a reason they didn't put it into this optimization so you never know if CPython always is going to optimize it, because for simple cases that use string in the rows and stuff like these it should be easy if maybe it's a code a bit more complex, who knows, if it will do an optimization. So it's better not to rely on this. As long as the string is short it's fine but if it's a bit longer then...
45:52 Michael: Yeah, it's a problem, maybe you're steaming stuff out of a csv file and trying to build up a thing and maybe it can no longer optimize that, who knows, right? Another interesting example you had was looking sort of optimizing variable and function look ups, like cashing global things like square root versus math.square root for example in a function.
46:16 Mike: It depends what you are doing, it can be, it can give you a little bit speed up, so because that's just the basic thing how Python looks up names, so first it looks local names spaces and your function, then goes to the global names space which is your module and then it goes to build in name space. Whenever lookup is kind of a dictionary lookup and instead of going like to the global or even the build in name space like if you use some 46:40 in some then every time you use some Python has to go and hunt for some until it finds it, so as you say ok, my some=some and in function for instance then you make it the local variable and you avoid like two lookups for every time you use some. This can be useful.
46:55 Michael: Yeah, if that's in the tight loop than maybe that becomes a problem, right, or a loop within loop.
46:59 Mike: If it's a tight loop you don't do much else, that might be something, if you do a lot of all the heavy computations it takes a long time to 47:07 then you still get the speed up from the look up 47:17 , but the percentage rise might be just half a percent faster than might not make a lot of difference. If you don't do much else you can get several 10% faster or something like this. Though it depends, very much on your use case but at least you can try and this would be one thing so if you call a function or some built in global variable in a loop, again and again making it local might speed up things a bit.
47:36 Michael: Sure. You had a cool example where one of the points you were making wsa saying look sometimes it's an algorithm and you just need to look, you know, not optimize a function a little bit but you need to rethink how you are doing something and you had this great it was a contrived example that was a computational but you were basically computing py using the Monte Carlo method and said the naive way to do this would be to sort of generate a couple of random numbers, do some math, save some values and do this in a loop, and you said, well, look if we do this with a different algorithm like using Numpy we get dramatically different performance, right?
48:10 Mike: Yeah. So Numpy, the Monte Carlo was maybe the worst algorithm to calculate Pi, there are much better algorithms out there that give you pie with a hundred digits, with hundred decimals, so with Monte Carlo a hundred decimals would take the age of the universe to calculate I guess, but it makes a good example, because it's very slow and you can use a lot of techniques to improve it because also it's parallel so I use it later on, actually to do some parallel calculations this multiprocessing and other means, so it's a very good example, and this same example has many different kind of approaches which is useful, and it's simple enough to understand. And then you just run it in normal Python and as I said one of the things where Python is slow is when they are doing numerical computations and you use for x in range for y in range loops, something like this. This is pretty slow and if you just use Numpy and Numpy is doing this vectorize so instead of writing a loop then you vector, and you just call the function in Numpy. You should pretty much never write a loop, you should always vectorize things if you want to make it fast, and then Numpy just runs it so the function which is running is C where you get near C speed for lot of things, so it makes it much faster.
49:30 Michael: Yeah, yeah, that was really cool, I liked that example. What if people missed it, this was actually done in June, so if they were there they have already misses it, there is a couple of opportunities to still check out your presentation, right?
49:46 Mike: Yeah, the presentation, you can go to YouTube if you go to Py video, it's on You Tube if you search shortly you will find it so if you got to the PyCon Us site then it should be there.
49:57 Michael: Yeah, and I'll link to it in the show notes as well.
50:00 Mike: Yeah, you can link to it. And also I will give this tutorial again, at EuroPython, just in a few weeks, in Bilabo, in Spain, so there I will give this tutorial again, so I will talk about it.
50:12 Michael: Yeah, EuroPython is going to be very exciting, that will be a good conference.
50:17 Mike: It's a nice conference, I gave it last year there so it seems like, because there is always demand for it, and people like it, because it's I try to always make it hands on so you can follow everything so nothing is too sophisticated, which is on purpose but of course if you show too sophisticated code people won't understand so everything is pretty simple and you can use it right away, and hopefully when you understand you can apply it to your own use case, that's all purpose of the thing.
50:43 Michael; yeah, that's great. So we just have a few minutes left in the show, before we call it quit, so let's talk a little bit about what else you have going on, in the Python space.
50:53 Mike: I've been at the Python space for quite a while, since 1999, actually I spent most of my professional life in the Python space, I teach Python so I am the founder of Python Academy which is now more than ten years old actually. I teach Python at the Academy, my first Python course was in 2004, it was quite a while ago, I taught university level courses in different fields, scientific fields, so I had some experience in teaching and gave a lot of talks at conferences, I really like teaching, it seems like that it fits me and people understand most of the time what I am saying. So I started teaching Python, and meanwhile Python Academy grew, now we are about 11 teachers, so not everybody is teaching all the time but I have a lot of different teachers doing that development testing science and data base programming and have also teachers that have different native languages so I myself can teach in German which is my native and in English, but I also have people teaching in Italian and Polish and maybe other languages later on, so some people might be taught in their own native language which might help to understand.
52:04 Michael: Yeah, absolutely, congratulations on the success there, that's awesome. I've been deeply involved in training and training companies for the last ten years myself, and I know what it takes to put those together and keep them running.
52:17 Mike: Yeah, it's a lot of efforts of myself so the Python Academy be focused on everything Python, so very wide range in terms of Python but deep in there so I teach beginners, people that have barely programmed before or the programmers, so professional programmers that switched to Python, but also advanced Python, I have advanced Python course that's a Python track, and I also teach scientific tools which is a very wide field, so I tech how to use IPython, Jupyter Notebook and Numpy, and some Scipy tools and Matplotlib and Pandas, those kinds of things, which is in very high demand in terms because scientists need these tools all day long.
52:55 Michael: yeah, absolutely, what's your favorite one to teach?
52:57 Mike: It depends, so I like to have variations, I like the scientific things and actually, in the course I like to include example from the people and actually do live programming in the course, so if they have a problem and I say ok, I need the scientists have read in this file A and have to convert into file B which is a very common thing, and Python really shines on this so you can, actually in the course, ad hoc develop the small routine and read in the file, there is different tools so you can do it just standard library, you can use Pandas which is great for csv files and stuff like this, and then you say ok, now I have this file and I have the data and then I write it back, and this is very often very useful because then I can use a lot of things I taught in the course, so do I do this, how to write the function, how to write the doc string in the function, and how to make the function- refactor the function because getting too big, everything, but in the small scale so understandable for people and they see it's very useful if you do this, so you can reuse this function again and again to do something. That's mainly for scientists that very often scientists use programming as a tool that are not so deep into programming very often, as compared to professional programming there is nothing, they pretty much understand when I say something, and they understand the concept and that's pretty easy, you can go on, for scientists you have to give the example because of course just explaining it and these very kind of generic examples might not be kind of really good enough to understand what it can be useful for.
54:24 Michael: Right, because they spend most of their time working on physics or biology or something real right?
54:30 Mike: Yeah, something real, it depends, some of them tend to become programmers, very often, but many of them just use Python from time to time as a tool, as an important tool and as soon as they get their result they just forget about it and go on, they I said wait a minute, you can- it's just script works but if you spend another half an hour you can make it reusable and next time you can save a lot of time because you put it in a function and you put a string and maybe you put a test in there, so make it work and it makes much more useful even your colleague might be useful now if you write this small function or several functions that can read this file format then your colleague can use it, if you just have a script that's doing everything in one piece, then your colleague is probably not very able to use it without lot of efforts.
55:13 Michael: Right, you would have to start from scratch every single time.
55:17 Mike: Yeah. So it depends, so that's what I like, I like the variety, so I like introductory courses, even I taught them many times, but I also like the advance courses and last week I had a course with people who learned how to use meta classes, and I had to really dig deep into meta classes, there was some very hard meta class questions I had to kind of think really hard because meta classes are a bit esoteric topic. Most of the time if you don't know what you are doing you don't need them, and they you could stop the course, but sometimes they can be useful for certain type of things, these people use them to high extent which is interesting, pretty challenging course.
55:54 Michael: Yeah, cool, yeah, it's great to have that spectrum. Do you also do consulting?
55:58 Mike: We also do consulting, so actually I do scientific consulting I just have some developed some lake models, so if you do some consulting in scientific area of course we have a team of few people so we also do consulting and program something. And sometimes you also connect the consulting, so developer solution but instead of handing over black box solution we do explain how things work and how people can extend what we did, so we get really solid solution which is people probably like scientists wouldn't be able to write themselves, but they can build on it so they have this basics, this good foundation, they can build on it, they can use it, and increase it and make it more useful for their needs.
56:40 Michael: Yeah, that's great, that's really helpful. Then finally, you've done a lot with conferences, like you were involved with Euro Scipy, Euro Python, and so on, right?
56:49 Mike: So, it seems like I am pretty much into conferences so actually I saw that pretty much I was the guy behind pushing Euro Scipy so I started here in Leipzig where I am located in 2008, 2009 year were the first to be Euro Scipy happened here and I was the chair, and now Euro Scipy I didn't have as great success that we had two conferences in Paris, two conferences in Brussels, two in Cambridge, and now we are back to Germany, it will be in August in Erlangen, just a bit more than a month from now, that will be the number 9 Euro Scipy, it seems like the success people come to the Euro Scipy and it's continuing, so I've been involved in Euro Scipy and also I am involved in PyCon DE so in 2011 , 2012 PyCon DE the German PyCon was here in Leipzig and I was a chair and also I am, because PyCon DE is run by the Python software Verband which is a kind of a German software association and I happen to be the chair there also, so I am involved in the community work, and then we also did Euro Python 2014 in Berlin and I was also the chair, it was a big conference, more than 1200 people.
57:55 Michael: Yeah, that must have been a lot of work to put that together?
57:57 Mike: Yes, so we had a very great team, of course you know the chair, they just kind of oversee everything and try to delegate as much as possible which is necessary because it's just impossible to do work yourself, you have to have a very great team and you have to have a lot of people that are very enthusiastic about it and put a lot of effort in there. And it was a great conference, I had a lot of good feedback from people about the conference.
58:21 Michael: Yeah, cool. Are you involved in any upcoming ones?
58:23 Mike: Yes, the Euro Scipy, so the Python 58:26 is also taking over the legal part of the Euro Scipy so if you do the- somebody has to move the money and sign the contracts and stuff like this, so I am 58:38 to be useful PyCon and Euro Python for Euro Scipy web conferencing software. I am involved there but I am also a little bit involved, we have what's called a Python Unconference in September and our software 58:53 is sponsor and we support it a little bit, we are not the main organizer but we help. That will be likely, that will be a PyCon DE in October in Munich and we are involved there and we'll be the next year PyCon DE and the Euro Scipy next year, so and I am always involved to some degree in these conferences I am doing the main work for sure but I am on the mailing lists and I am somehow involved in organizing.
59:21 Michael: Yeah that's cool, and it sounds like there is a lot of conferences coming up in Germany around Python, that's cool.
59:25 Mike: Yeah, there is several of them we have this Python Camp which is interesting in Cologne, I myself I am just a participant other people do this, which is pretty relaxing, it's a kind of like Unconference, we have this Unconference in Hamburg, so now actually we have not this one big one but multiple smaller ones, which can also be nice so of course people don't have to choose one, they have 2, 3 more alternatives.
59:52 Michael: Right, a little bit of each is really great. Final two questions, Mike, before I let you go- when you write some Python what's your standard editor, what do you open up to code?
60:02 Mike: Typically I go with Sublime, nowadays, sometimes I use Win IDE if I have some projects which of course has a nice debugging and refactorization things, for courses I use Spyder which is kind of scientifically inclined thing so I use it for my courses.
60:21 Michael: That's the one that comes with Anaconda distribution, right?
60:22 Mike: Yes, so Anaconda has it out of the box if you don't- if you just install Anaconda you have it, so Spyder, it's not perfect it sometimes crushes but it's ok, so of course the nice thing is you don't have to tell people to install a different editor you have one, and they have debugger on it they have the objects, you can look at the objects in Python objects for debugging and stuff like this, you have the active console if you like, but most of the time in courses actually I spend in notebook anyway, so-
60:48 Michael: Right. Yeah, the Jupyter notebooks is also really nice, that's cool. All right, and the 80 000 PyPi packages, what's your one to recommend that people maybe don't know about?
60:58 Mike: The one we talked about already, the Jupyter notebook is the killer app, if you don;t know, Jupyter notebook you are missing something out in the Python community that's something you should go, so it's very interesting to work with Jupyter notebook, I always have a notebook open, to just try something out if you have an idea you can use it, it's a very nice 61:16 editor, interactive prompt. Maybe that's not very secret, the one I am looking right now is xonsh, xonsh is this interactive shell, and I know Anthony Scopatz pretty well, we've been hanging out at PyCon lately and he is a funny person and very knowledgeable on top of it and he wrote a very interesting tool which gives you a kind of a shell but it incorporates Python. It's very interesting so you get the shell that incorporates Python and then I think it works on Windows so you get the much more powerful shell on Windows because the shell on windows is typically not that great so if you need to work in windows sometimes as I do for my courses, then this would be a good alternative to go.
62:05 Michael: Yeah, that is cool. ok, great recommendation. Yeah, and you know, the story on windows is getting better right, like Steve Dower redid the Installer so now the installer is not a complete challenge to like get Python on there, the Windows ten shell is a lot nicer, they are bringing the Ubuntu binaries to it, windows 10 starting in a month or two so, it's getting better but yeah, it still is sometimes painful to work on windows.
62:30 Mike: Yeah, but in the compiling C extension still not 62:35
62:38 Michael: Let me just save vc vars bat was not found, right.
62:41 Mike: I have this message about 100 times.
62:42 Michael: All right, Mike it's been really fun to have you on the show, thanks for sharing your optimization experience.
62:51 Mike: Thanks for having me, thank you very much.
62:52 Michael: Yeah, talk to you later.
This has been another episode of Talk Python To Me.
Today's guest was Mike Mueller and this episode has been sponsored by Rollbar and Snap CI. Thank you both for supporting the show!
Rollbar takes the pain out of errors. They give you the context and insight you need to quickly locate and fix errors that might have gone unnoticed until your users complained. As Talk Python To Me listeners, track a ridiculous number of errors for free at rollbar.com/talkpythontome
Snap CI is modern continuous integration and delivery. Build, test, and deploy your code directly from github, all in your browser with debugging, docker, and parallelism included. Try them for free at snap.ci/talkpython
Are you or a colleague trying to learn Python? Have you tried books and videos that left you bored by just covering topics point-by-point? Check out my online course Python Jumpstart by Building 10 Apps at talkpython.fm/course to experience a more engaging way to learn Python. If you're looking for something a little more advanced, try my write pythonic code course at talkpython.fm/pythonic.
You can find the links from the show at talkpython.fm/episodes/show/66
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 feed at /itunes, Google Play feed at /play and direct RSS feed at /rss on talkpython.fm.
Our theme music is Developers Developers Developers by Cory Smith, who goes by Smixx. You can hear the entire song at talkpython.fm/music.
This is your host, Michael Kennedy. Thanks for listening!
Smixx, take us out of here.