So in today’s topic, I’m going to be showing you five Python, bad practices that you should avoid. Now, these are things that many people do not actually know are bad practices. They seem normal or kind of usual or natural to do, but can lead to a lot of complications errors, or just messy and unreadable code. So with that said, let’s go ahead and dive into the video after a quick word from our sponsor.
Mutable Default Parameters
All right, so let’s move on to our first Python bad practice, which is immutable default parameters. So this bad practice involves using a mutable object as the default parameter for a perimeter inside of a function or a method. Now, before I go any further with the explanation, just to have a look at this code and take a guess of what you think the output is going to be.
So pause the video if you need to, I’m going to explain it now. So I’m assuming that most of you would guess that what the output of this should be is one and then inside of a list one and then two and inside of a list two. Now this is actually not what the output is, but intuitively that’s kind of what it looks like, right? So let me stop here and run the code and show you what the output actually is.
So the output is one inside of a list. One, two inside of a list, one comma two. So that’s a little bit strange. Why are we getting one comma two as the second result here? Well, the reason why we’re getting that is because we’re using a mutable default parameter.
So if this was not immutable object or this operate in the way that we thought it should operate, then what would happen is when we call this function, a new empty list would be created and stored in the parameter numbers. We would append the number that we passed here to that list. We then print the number, print that list and then return it. But since this is a mutable object, this is not being recreated. Every time we call this function. And so on the first function call, we have this list object and on the second, second function calls. So right, numbers is equal to the same list object, but now we’ve upended a one into it. And so numbers kind of looks like that.
So we’re actually modifying the same object in both of these function calls. And I’ll just do it one more time to show you that if I do another function called oops, meant to run the code here, we get the exact same thing, right? Three and then 1, 2, 3, the same pattern persists. So these are the exact same objects that we’re modifying in every single one of these function calls. Now, just to prove this to you, I’m going to show you that the return value, which is this list here is the exact same for X, Y, and Z. They are actually the exact same object. So X is Y and Y is Z. So when you use is this tells you if two objects are identical, if they’re the same object. And so assuming that X, Y, and Z are all the same object, this should print true.
So let’s run this and we see that it is indeed true. So why is this the case? Well, when you use a mutable value for the default parameter, what happens is this parameter here points to kind of a little box in memory that stores this object, and it keeps pointing to that box, even when you call the function again and again. So when I modify what’s in that box and memory, and I add a one to it, and then I add a two to it, it stays the same as the code runs. These don’t get removed. And so that’s why we’re getting 1, 2, 1, 2, 3. Hopefully that kind of makes sense, but let me show you that the same problem does not occur if we have a non mutable value here.
So let’s make a string and let’s just call this hello. And rather than number, let’s just change this to, I know S which will be some string. And if I go and do something like, okay, I need to do to kind of change the entire thing here. Let’s go S string, uh, let’s go string plus equals S like that, and then print S and print string, and then return string. And we might as well call this a pend string.
So let’s change our example here. Let’s go append underscore strength, hello. Or let’s just go H oops, and then append underscore string. Okay. So now, if I run this code, you’re going to see this works in the way that we think it should work. So we get hello, H and then, hello. I am that’s because this is not immutable object. And that means we cannot modify this object in place. So when I do string plus equals S what happens is a brand new string is created and assigned to the value string. We print out that value string, which is local to this function. And then we return that new string object we don’t modify is being stored inside of this string parameter right here.
And so when we call the function again, and string is equal to hello, it’s still equal to hello. It’s not been changed because of the fact that this created a brand new string and assigned it to the local variable string, which is inside of this function. It’s a little bit confusing, but just understand that you should not use a mutable default parameter for the reason that I just showed you, you’ll get all kinds of weird results. And it’s a very difficult thing to debug.
Not Using A Default Dict
So moving on to the second bad practice, we have not using a default dictionary. Now explain what that is in one second. But first let’s have a look at this code right here. So we have this dictionary called counts. We have a list of numbers. We’re looping through all of the numbers, checking. If the number that we’re on is in our counts data structure in our dictionary. If it’s not that we create a new key with that value, we set it equal to zero. And then we append the value of that key. What this is doing is just counting the frequency of all these numbers in the list.
Pretty straightforward. Now, this code is fine. You can write this, but technically this is considered a bad practice in Python because there exists a data structure called a default dictionary, which makes it, so you do not need to do this check right here. And that’s kind of the more pathetic way or style of doing this. So let me show that to you. So to use the default dictionary, you need to import it from a built-in module in Python called collections.
So you need to say from collections, and then instead of ordered Dick, you are going to import the default dictionary like that. All right. So from collections import default dictionary now to create a default dictionary, what you need to do is use the default Dick right here. So you’re going to say counts is equal to default Dick, and then you need to pass a callable object that returns what the default value for this dictionary should be.
So I’ll kind of explain this in one second, but let me just write this out. So Lambda and then zero like that. Now, if you’re unfamiliar with the Lambda, this is completely equivalent to this. So to find funk return zero, it just kind of a shorthand way of doing this. This is known as a one-line anonymous function.
Anyways, what this is saying is if you try to access a key that does not exist in the dictionary, it will automatically create one for you that has the value zero. That’s all it’s said. So let me now show you how we can rewrite this here, using the default dictionary. So let me copy numbers here, and let’s say four key in numbers. And now what I’m going to do is just say counts, which that should be counts at key plus equals one. And I’m going to print out counts like that. So now, if I run this code, you’re going to see everything works totally fine. We don’t get any errors. This is just functioning properly.
And the reason for that is we’re now using a default dictionary. Now you notice that there is some minor differences between a regular dictionary and a default dictionary. So you have to be a little bit careful when you’re using a default dictionary, because some of the methods might be a little bit different, but the way you use it is practically the exact same. But notice when I print out default dictionary, it’s giving me the default value, and then it’s giving me the dictionary is not just giving me the dictionary. So be careful in how you use it. You will have to kind of look it up a little bit, but it’s not very complicated. And it saves you, you know, some cleanliness and readability of your code.
If you do decide to use it now in the same way, here, there is another thing that you can use to avoid having to do this type of check when you’re kind of trying to access a key or change a key value in dictionary. But let me just get rid of this example here in show you an example, in which one I’m about to show you makes sense. So let’s say you have a dictionary. Let’s just make it an empty dictionary called D and let’s see if a key is in this dictionary.
So if list is not in D then what I want to do is go D list is equal to that. And then I want to say D and sorry, this should be at the key list dot append. And I want to add maybe the value three into this list, the list that stored as the B value for the key list. All right. So the way that you can actually shorten these three lines of code right here into one single line is by doing the following without creating a default dictionary, you can do this. You can say D dot set, default. You can pass the key value. You can pass what the default should be, and then you can perform whatever operation you want it to perform on this value. So I can say dot append, and then three.
Now what set default does is it will set the default value for a key that you were trying to access. If it doesn’t exist and then return it. But if the key does exist, it will return its value. So in this case, what will happen is if the key list exists in the dictionary, it will return the value of that key. And then it would append three to it before it returns that story. But if it doesn’t exist, it sets it equal to an empty list. And then in this case, it’s a pending three to that list.
So that is how you can avoid doing this kind of tedious, check yours by using this set default method. I know myself, I didn’t know this existed until probably a few months ago, actually, and it’s not something that I used a lot in my Python code, but definitely saves a bit of time, makes your code more readable and is a better practice doing something like this is kind of considered a bad Python practice. Just because, again, it’s not in that Python style. And if you have a method like this, you might as well use it.
Not Using A Context Manager
So now we’re moving on to the next bad practice, which is not using a context manager when opening files. Now, in this case, when I say context manager, I’m referring to the width statement, some of you may know what I’m talking about here, but let me just show you an example of what you bad practice is and then how to fix it. So if you want to work with a file specifically, or really any resource that kind of needs cleaning up, we’re closing when you’re done working with it, you really should use a context manager.
However, not using a manager will look something like this F equals open file dot TXT, and then we’re going to open it in write mode. So let’s say we want to open this new file called file dot TXT. Maybe we want to write some lines to it. So F dot, right? I don’t know.
Let’s write hello into it or something like that. Well, what we need to do after we’ve opened this file and we’ve written lines into it is we need to make sure we close the fund. So we do something like F dot clips. Now this is fine. This code will work. All right, there won’t be any issues here. However, we really need to make sure whenever we open a file that we close it. So if you forget to write this close here, that’s going to lead to some problems for you. I actually don’t think this file will save, or at least other programs won’t be able to access this file. This program that’s currently running will be kind of the owner and have access to that file.
And there’s just all kinds of issues that can occur if you forget to close a file after you open it. So that’s a really big deal. So, okay. You might be saying, all right, I’ll just remember to close the file. Well, that’s great. If you do remember to close the file, but another issue can happen if in between when you open the file and you close the file, some type of error occurs, or your program crashes or the user ends your program before you’ve closed the file. So what you need to do when you’re working with files is rather than doing it in this way, and just praying that you’re actually gonna be able to close the file after is you need to use a context manager and we context manager is with, and I’ll explain kind of what that is, but the way that this code would look in a context manager is the following open file dot TXT in write mode as F and then F dot, right?
And then you would write hello, and then you actually do not need to manually close the file when you open a file in this way. So what this does right here is ensure that no matter what happens, this file is going to be closed. So when you open the file, you open it as F you can then do all of your operations inside of this width statement. And then as soon as this with statement is done, it will automatically close the file. And if an exception occurs, it will close the file before the program terminates. So that is why you use a context manager. And really all the context manager is, is something that enforces a cleanup operation after this width statement is done, whether that be because the program crashed or because it just finished executing all the statements.
So there are many other times in which using a context manager is very, very important. If you want to avoid a bunch of potential problems, but really just think of using one, whenever you have kind of a cleanup operation that needs to occur. Now, the thing is you can’t just use this context manager anywhere. This cleanup operation needs to be implemented by something in this case, when we use open like this, uh, it implements this cleanup operation. So it knows, okay, once I’m done with this, I’m going to close the file. There’s a lot of other things in Python that have context managers built in, but just wanted to show you here. If you are working with files or any resource that needs to be cleaned up, try to use a context manager, or at least look and see if a context manager is available for the resource that you’re trying to use.
Not Using Enumerate
So moving on to the next bad practice, which is not using the enumerate function, when it’s applicable to use it. Now, the enumerate function is something that allows you to get access to the item, as well as the index of elements in a list. So if we’re looking at this example right here, we have a list. We want to loop through it and we want access to the index. So maybe we want to print the index. And then we want access to all of the different values, all of the elements in the list. Now, the traditional way to do this in most programming languages is what you see right here.
We say for I in ranch, we go through whatever the length of the list is. So loop through all of the indices, we get access to the value of each of the items by indexing it in the list. And then we print out whatever the index is and the value. So let’s have a look here. We get, you know, let’s scroll here, come on 0 1, 1, 2, 2, 3, 3, 4. So on and so forth. Now this is fine. You can do this. It’s not that bad, but the best practice in Python is to do the following four.
I comma Val in a numerate LST print. I comma Val, and now you’ve eliminated this line right here, and you’ve actually made it more readable and easier to find what variable is storing the value of the element and what variable is storing the index. So let me just erase this for a second. So, as I said, what a numerate will do is give you the index, as well as the value. The first item here, the first variable here is going to be the index. The second value here is going to be the actual value of the item. So if I run this, we get the exact same result as before. And there you go, use a numerate in a situation where it makes sense to use it.
Now, a numerate doesn’t just work with lists. It works with any Iterable object. So we’ll work with strings. It will work with dictionaries. It will work with sets and I’ll show you an example with a dictionary. So let’s say we have, hello, comma, one name, comma two, and let’s enumerate through, uh, I let’s just call it D now. Okay. And let’s run this. And now notice we had zero. Hello, one name. We can do the same with a set. So 1, 2, 3, okay. Save and run. Same thing that works. And then finally, of course, we can do this with a string. So hello. My name is Tim. Let’s run this and notice we get it working as we would expect. So that’s all for this bad practice. Just remember this enumerate function exists and you should use it if it makes sense to do so.
Overriding Built-In Keywords
All right. So the last bad practice I have for you is a, another quick one. And this is simply to not override built in names in Python. What I mean by that is, do not name variables, things that are Python keywords, for example, do not create a variable called ID or a variable called zip. You might be tempted to zip because like a zip code or something, right? Do not name a variable list. You do not want to do this. The reason why is, if you do this, you disable or kind of remove the ability to use what these built-in Python keywords actually are.
So if I name a variable ID, I can now no longer use the ID function. And the ID function gives you the memory address of a Python object. So if I do IDX now, you’re going to see that I get an error at the end. Object is not callable. Whereas if I comment this out, now, I’m still able to use the function. So if I wanted to print the ID, this works, it works as a variable as I would expect, but again, I can no longer use what the actual built-in Python function is. She just shouldn’t name stuff like this. You know, same goes with zip. Same goes with lists.
Now let’s say you really want to name your variable ID, zip, or list or any other built-in Python keyword. If you really want to do that, first of all, I’d recommend just don’t do it. But what you can do is add a trailing underscore. This is the convention. If you really need to name something, uh, a built-in keyword in Python, then you just put an underscore after you could put an underscore before when you put an underscore before this is the Python convention for make this a private attribute or make this a private variable.
So unless that’s what you’re intending, then you should actually do a trailing underscore. So that’s all for this last bad practice seems pretty intuitive and straightforward, but I cannot tell you how many people do this. And it’s really frustrating because the syntax highlighting gets all messed up for it. And then of course you deactivate the ability to actually use what this built-in keyword is.