5 Common Python Mistakes and How to Fix Them

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey there how's it going everybody so a few weeks ago I released a video on ten Python tips and tricks for writing better code and a lot of you said that you found that video pretty helpful so in this video I've compiled together another list of topics that I thought would be beneficial and that's the five most common mistakes I see from people when using Python and how to avoid those now I get questions every day from people who follow along with my videos and a lot of the questions have to do with the mistakes that we're going to discuss in this video and it's not always obvious what the problem is so we're going to look at the cause and solution to all of these now we do have a sponsor for this video and that skill share calm so I'd like to thank them for supporting the channel and it'd be great if you all could check them out using the link in the description section below and support the sponsors and I'll talk more about their services in just a bit so with that said let's go ahead and get started okay so the first mistake that I'm going to talk about is one that I see a lot with people who are brand new to Python now if you're not new to Python then definitely stick around because we're going to talk about some more advanced issues as well but this is one that I definitely see among people who are just getting started out and that is when people mix tabs and spaces or are inconsistent with their tabs and spaces and that leads to indentation errors so I have a file open up here so let's take a look at what this looks like now the reason that I say that this is usually a mistake by people who are just starting out is because once you get your development environment set up properly then it's almost impossible to run into this problem but people who are just starting out might use some basic text editor where it's possible to mix tabs and spaces so I have my sublime text set up to convert all of my tabs to spaces but let me turn that off and show you what this does so up here in my sublime text settings I'm going to change the settings now if I have more settings here then don't worry about it but I am we can see here that I have mine that set up the translate tabs to spaces and I'm just going to set that to false and now let's see what happens when we mix these so now I just have a basic program here that just loops through a list and squares the numbers so on this line I'm going to unand int this and I'm going to use a tab for that line now for this next line I'm going to uninvent that and I'm going to use spaces for that line so I have one tab here and I have four spaces here so this program just looking at it actually looks correct there's nothing that I can see here that looks wrong but if I run this I'm going to save it and run it we can see that we get an error down here that says indentation err unand dent does not match any outer indentation level and really that exact message might not be very helpful either there's a couple of other indentation errors that give you different messages now if you're new to Python then you're not going to have any clue what that means especially whenever everything just looks fine in your programmatic clients now imagine that this module was a lot larger we just have two indentations here but imagine that we have you know five hundred or thousand lines of code it's going to be almost impossible to go through there and figure out which ones are using tabs and which ones are using spaces so instead of trying to go through and fix those manually I would just highly recommend simply upgrading your editor or IDE that you're using so any good editor for python is going to be able to convert your tabs to spaces automatically so I'm using sublime text but you can set this up in vs code PyCharm Eclipse or whatever it is that you use if you're not using an editor that can do this then I recommend getting a new editor so I'm going to go back in sublime text you do this by changing your settings here and it's just a changed setting where you can set translate tabs to spaces and I'm going to set that to true and now I think I have to make a change to resave this but let's redo this so I'm going to tab that line and I'm going to do spaces on that line now even though those were different if I save this and run it then we can see that our program still works and that is because sublime text automatically changed this tab here to 4 spaces so that works nicely now on top of having an editor that does this for you I would also recommend using a tool like pilant that catches more mistakes like this for you that are easy to miss just by looking at your program ok so now let's move on to some slightly more advanced problems so one big problem that I see is when people name their Python modules the same name as something that they're trying to import now when you do this your module with the same name takes higher priority then the modules from the standard library or the modules that you installed using pip so let's see an example of what this would look like so let's say that I have a project where I want to create a Python module that will do some mathematical calculations for me so I'm going to create a new module in my current directory so a new file here and I'm just going to call this math dot pi and now I'm going to use radians and a sine function from the math module in the standard library to make some calculations so I'm going to say from math which is a module in the standard library import radians and I'm also going to import the sine function and then I'll just grab the radians of 90 degrees so I'll say rads is equal to radians of 90 degrees and now let's print out the sine of those radians if you don't know the math here don't worry about it that's not what I'm actually that's not what the tutorial is about it's about how the imports are working here so this should print out one here because that is what the sign of these radians should be equal to so if I save this and run it then it seems like this is a nice simple script but now it's saying that we get an import error cannot import named radians for math now this is strange because the math module is in the standard library there's no reason that it shouldn't be able to find that but the reason is because we named our own module math dot pi and python is trying to import radians and sine from our own module instead of the standard library so to fix this all we have to do is rename our module so I'm going to come over here into I know that this sidebar is hard to see here but down here we can say see that our current module is named math.pi I'm just going to rename this to project dot PI and now if I save this and run it then we can see that it runs just fine because it was actually importing the radians and sine from the standard library math module instead of trying to import it from our math module now this is usually pretty easy to catch when you accidentally name something the same as a module from the standard library because if you can't import a module from the standard library then it's pretty limited as to what the problems could be and this is one of them but if this was a package that we pip installed like flask or Django then this could possibly take more time to figure out so there are a lot of times that I've tried to help people debug a problem where they're trying to write a flask application or something like that and they have flask and salt installed and they're using the right version of Python but when they go to import flask it throws an import error and sometimes it takes me a while to figure it out because they only send me their code but not their file name so my initial reaction or my initial intuition with import errors is that it's probably something with their path it's an issue with their path but then later I'll finally realize that they named their module flask dot PI and that's going to interfere with the flask that they're trying to import so if you ever get an import error then it can definitely be an issue with your path and I've made videos on that in the past but sometimes it's as simple as having your file name the same thing as the module that you're trying to import now we can also make naming mistakes when we're trying to name a variable and that's whenever we name a variable the same thing as something else that you'd like to use so there's nothing that prevents us from creating a variable with the same name as something else in Python so for example let's say that instead of calling our variable here RADS let's just say that i wasn't really thinking at the time and instead i just called that radians but radians is the same name as the function that we're importing here so if I change that variable there and I also change the print statement there to use those radians if I save that and run it then the code still runs and it looks like it works fine but now let's try to use the radians function again further down so I'm going to comment out this print statement and I'm going to say you know rad 45 is equal to radians of 45 degrees and now let's print out rad 45 if I save that and run it then now it's giving us an issue here and this might not make sense immediately it's saying float object is not callable now the reason is because we created a variable up here called radians that is equal to radians of 90 degrees which is some float value so anytime we reference radians after that assignment it's going to use that radians variable and not the radians function that we imported so that's why when we say that we want the radians of 45 degrees Python is telling us that radians isn't a function it's a float value and the float value isn't callable like we're trying to call it here so a lot of people get frustrated with Python when things like this happen to them for the first time but Python isn't a compiled language in the sense where it's going to pick these things up before we run the code and it also doesn't hold your hand and give the developer those types of restrictions it gives you a lot of freedom but sometimes that freedom allows us to do things like this where we don't think that we should actually be able to do this like overriding a function like this but it's just how it works so that freedom allows us to do a lot of cool things with Python and allows us to write code very quickly but we can also step on our own toes if we aren't careful so we can see if I simply named this something else like rad 90 or rads or something like that and run that then we can see that now it works fine okay so the next thing that I've seen some people get tripped up on is mutable default arguments and I had an example of this in my object-oriented series where I had a function that added employees to a list and a lot of people ask me why I just didn't pass in an empty list as a default argument and I told them it was because of this problem with mutable default arguments and we'll see why in an example here that's similar to the one that I had in that video so let me close down my output here and also close my sidebar so here we have a function called add employee so let me explain what this function is meant to do so it takes in a single employee and also an employee list as arguments and it's simply going to add that employee to this employee list and then print that list but we can see here that the employee list has a default value equal to an empty list so if we don't pass an employee list to the function then it should just create a new list for us from scratch so let's see what this does so I have an existing list of employees down here so let me add a new employee to that list using that add employee function so I'm just going to say add employee and I'll add Cory as the employee and the list that we want to add this to is just going to be this emps list here so if I run this then it should print out this employee list here with this new employee added on so if I save that and run it then we can see that that looks good we have our existing list and that employee was appended to that list okay but now let's add a couple of employees without providing an existing list so I'm going to take away our existing list and now it should just use this empty list as a default so now let me add a couple here so I'll add Cory and I'll also add John so we would think that both times we run this that we'll get a new list of one person because we're not passing in an existing list so it should use an empty list by default for both of these each time the function is called but if I run this we can see that our first value created a new list but our second add employee here it got added on to that list well which is kind of strange and this will actually keep going so if I add a another employee here and I'm still not providing an existing list it should be creating a new list every time but each time the list just gets longer and longer and keeps appending to the same list even though we should have that empty list by default so what's going on here is that in Python default arguments are evaluated once at the time it creates the function so it's not actually creating a new empty list each time we run the function now you won't notice this with immutable types like strings and things like that but with mutable data types like a list and it's using the same list that it created when the function was defined so what do what do we do here if we want to be sure that we get an empty list each time so to do this instead we're going to want to do something like this so instead of passing in an immutable default type and lists are mutable we just want to pass in Employee List is equal to none and now down here within the function we can say if employee list is none or you can say if not employee list either one then we can create an employee list equal to a new empty list so now that this is actually within the function this will get run every time the function is run because like I said these only get evaluated once when we initialize the function so now if I run this that we can see that it works as expected it creates a new empty list each time we add an employee without an existing employee list and this should still work the same as before as well if we do and provide an employee list already then it just gets tacked on to that existing list so this is how you do mutable default arguments now this doesn't only give us unexpected problems with lists when I said that default arguments are executed once when the function is created and not each time the function is called then you can probably think of some other examples where this might not give us what you think is the desired behavior so for example let's say that I have a function like I have commented out down here let me just get rid of our current example here and I will uncomment this other example that I've created here so here I have a function called display time and it will print out a time in a specific format that I have specified here now it takes time as an argument and time has a default value here set to date/time dot now and that is if we don't provide a time then it will use date/time now as the default time so you might expect that every time we run this function it gets the current time if we don't provide one but I'm running this a few times down here at the bottom and sleeping between each function call for one second so if I run this then we might expect this second would be incrementing by one each time because we're sleeping a second between each function call here but we can see that each time it ran it didn't update the time like you might expect now the reason just like before is because it only executes those default arguments once when the function is declared and not each time the function is run so again in order to do this we would instead just need to move this into the function itself so I could do something like this I could just say time is equal to none and if time is none then let's just set the time equal to date/time dot now so now if I run this then we can see that it sleeps one second between the function calls but it actually got the current time since we didn't provide it one so actually knowing how those default arguments work is one thing that I see that trips up a lot of people okay so moving on another question that I get asked a lot and a common mistake that I see is when people don't fully understand how iterators work and how they're exhausted so this is especially true with a lot of people moving from Python to over to Python 3 because more things within Python 3 now behave like generators because those are more efficient but it does cause people some confusion so let's take a look at what I mean here so let me close down the output down here so within this file I'm using an example that I've used in videos before I have a list of regular names from comic book characters and I have another list of their superhero names and the two lists are related so the first item of the names list goes with the first item of the superheroes list and they have corresponding indexes that we can use the zip function for like I'm doing here so once I use that zip function then I'm going to print out the result here so first let me show you what this used to print out in Python 2 so let me go up here and change my build system and I'm gonna switch over to Python 2 so now I'm using Python 2 so if I run this then by using Python 2 we can see that we get a of those paired items and that's what zip does it zipped up the first item of the names list with the first item of the superhero list so we have Peter Parker and spider-man then Clark Kent and Superman and so on so what if I wanted to loop over these one at a time and print them out if I wanted to do that then I could just simply loop over them and that's what I'm doing in this commented section here so let me uncomment out this here and I'm actually using the format method here because I'm using Python 2 and F strings won't work in Python 2 so we can see that we have a placeholder here with the first value of the identity which should be Peter Parker and then we have another placeholder for the second value which is spider-man and we're looping over all of these here so it should print those out one at a time so they make this a little larger here and we can see that that is what it does okay so that seems pretty standard for how we would expect this stuff to work but now let me switch over to Python 3 a lot of people just try to directly run their code from Python 2 in Python 3 and expect the same results but with things like zip they might behave a bit differently so now I've switched over to using Python 3 and now let me run this same code so it kind of looks the same we still are looping through the values here but now whenever we print it out these identities we instead get this zip object instead of that entire list of those zip titles so what's going on here is that python 3 no longer returns all of those values at once and that's good for efficiency because if this was a huge list of you know millions of values then we're going to save memory but it might not be what you expect now if you watch my videos on generators and in raters then you know that we can get all of those values at once but we'll have to cast them to a list so let me create a list of our zip object here so I'm just going to pass that into a list here so now if I save that and run it then now we get that full list of our zip items but now it's no longer looping through and print these items here within our loop so this is where a lot of people usually get frustrated if they don't know what's going on now I have a lot of older videos on Python too where people try to follow along in Python 3 and they run into issue issues just like this and you know leave comments and send me emails asking me what's going on so what's happening here is that zip is an iterator like I said and iterators can be exhausted and that means that we can loop through and access that our values one time but then we can't do it again so that might not make sense but like I said it all comes down to performance and efficiency and really once you know that it really isn't a big deal you can still do everything that you used to be able to do but you just have to do it in a slightly different way so here we're converting our zip object to a list and then trying to loop over that same zip object again but we've already exhausted the zip the zip object when we converted it to a list at this line here when we did this it looped through all those values and converted them to a list and then we printed them out so now when we're trying to loop over that here it's not working because this has been exhausted and there's no more values left here but if you wanted to print the values out and also loop over them then we could simply convert it to a list from the start and then print that list and then loop over it just like we would with any other list so instead of printing out this list of identities here and not capturing that value instead I'm just going to convert this to a list from the start and now we've captured that into a list here so now I can print out those identities and also loop over them because now this is a list and lists are not exhausted like other iterators or generators so now if we run this then we can see that we get the same result that we got in Python 2 now if you'd like more details on how generators and iterators work then I do have videos on both of those topics in this video I just really wanted to touch on the confusion that I see from some people on not understanding how iterators can be exhausted and when they are why you can no longer access those values again a second time through ok so now the last thing that I want to discuss is imports and a bad practice that I see sometimes that can cause some errors and even if the code doesn't cause errors it can definitely make it harder to debug your code so the bad practice that I'm talking about is using an asterisks when doing imports now if you don't know what using an asterisks on imports does basically it just imports everything from a given module so for example I could import a module by doing something like this I could do import OS and then if I wanted to rename a file then I could do something like OS dot rename and then we could just pass in a file name here so for every function from the OS module I would have to say OS dot and then the function name like we're doing here Oh s dot meaning but we can also import functions one out of time to where we don't need to use OS dot so for example if I just wanted to use rename a file name then instead I could say from OS import rename and now we no longer need to say oh s dot rename we can simply just use the rename function but for each additional function that I wanted to use I would have to add that on to the import so if I wanted to use the remove function to remove a file then I would have to add that to my imports here so from OS import rename and import remove and then I'm also going to be able to use that remove function now we can also use an asterisk on the import to just simply import everything but this is a bad practice most of the time unless you really know what you're doing but sometimes people just want to be able to use everything and not think about it so they'll just come up here and say from OS import asterisk import star and that will allow us to use rename and remove and anything else that is in the OS module without using OS dot ok but why is this a bad practice so first of all it can make your code hard to debug so if our module was 500 lines of code here and halfway down I used this rename function then other people reading our code or even us in the future when we come back to read our code we're gonna wonder you know where is this rename function come from I need to go read that and see where its declared so that I can understand what it's doing but they're not going to know where it was declared because it's hidden within this asterisks and it isn't it's explicit if we were to actually say from OS import rename then we could come up to the top and say all okay there is where that rename function is coming from we imported it from the OS module now not only does it make it hard to debug but it can also introduce errors into our code whenever there are two functions with the same name so for example let's say I did something like this what if I said from HTML import star and then from glob import star both of these are standard library modules and I'm importing everything from both of those modules but the HTML and the glob modules both have an escape function and one escapes HTML special characters from the HTML module and the other escapes special characters in a path and that's from the glob module so in this case which escape module is actually getting imported so the HTML xscape function will be overwritten by the glob escape function so if I was to say print help on escape if I save that and run it then we can see that our output down here says help on function escape in the module glob so by importing using these asterisks it's just extremely easy to confuse people reading your code and it's a pain to debug and also it can cause issues like this so anytime you need to actually import from a module then it's better to instead just import it explicitly so if I wanted to import both of these then I could just say import escape and import escape now those are still going to be overwritten so we have to rename these so I could say import as h underscore escape and as g underscore escape and now when we use the HTML escape we would use this one and when we use the glove escape we would use this one or if you wanted to just import the entire module then you could just say you know import HTML and import glob and then when you use those you could just use HTML that escape and use glob dot escape so that is the best way to do it definitely you're just going to confuse people and opt you skate your code if you use those asterisks imports okay so before we in this video I want to mention the sponsor for this video and that is Skillshare Skillshare is an online learning community with more than 25,000 classes in tech business design and a lot of other topics they have over 7 million students so far and they have new courses coming out on a regular basis now my audience would most likely be interested in their programming courses and you can see here that they have classes in data science data visualization they have some courses in introduction to programming and computer science deep learning and neural networks using Python they have some SQL courses and all kinds of different popular series that you can find it useful now I'm also frequently asked how I make youtube videos and if I have any tips for any of you who would like to start a channel now I may do some videos like these in the future but Skillshare is really the place to go to learn about something like this they have courses specifically on YouTube and how to grow that as a business and if you're more focused on film production rather than YouTube itself then they also have a wide variety of courses on videography and photography as well so I want to thank Skillshare for sponsoring this video and it would be great if you could go and check them out and support the sponsors for this channel and they've provided me with a sign-up link that I'll post in the description section below and the first 500 people to sign up using that link will get two free months of Skillshare premium so that you can check it out and see how you like it ok so I think that it's going to do it for this video I hope that you found it useful to go over this overview of some of the most common mistakes that I usually see and also I'm interested if there are any problems that I didn't cover here that you run into in your daily coding so if you want be sure to comment those in the description section below now if anyone has any questions about what we covered here then feel free to ask in the comment section below and I'll do my best to answer those and if you enjoy these tutorials and would like to support them then there are several ways you can do that the easiest ways to simply like the video and give it a thumbs up and also it's a huge help to share these video with anyone who you think wouldn't find them useful and if you have the means you can contribute through patreon and there's a link to that page in the description section below be sure to subscribe for future videos and thank you all for watching you
Info
Channel: Corey Schafer
Views: 210,866
Rating: 4.9554892 out of 5
Keywords: python, IndentationError, python indentation, python indentation error, python file naming, python variable naming, python import error, python importerror, mutable default arguments, mutable default args, python common errors, python common mistakes, python exhaust, python generator, python iterator, python import *, import *, from import *, python from import, python gotchas, python exceptions, python tutorial, corey schafer, python programming
Id: zdJEYhA2AZQ
Channel Id: undefined
Length: 29min 19sec (1759 seconds)
Published: Mon Apr 22 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.