From the course: Python Data Structures and Algorithms

Build a stack class in Python - Python Tutorial

From the course: Python Data Structures and Algorithms

Build a stack class in Python

- [Instructor] In this video, we're going to write a stack class in Python. If you are unfamiliar with Python classes, then don't worry, I will explain everything you need to know as we go along. We are using a class to represent a stack for learning purposes because the abstraction is helpful for gaining a deep understanding of how the data structure works, including using the appropriate terminology, such as push and pop. In practical situations, you might just use a list. There is another reason to use a class though. If your code needed a stack and you provide a list, there's nothing to stop another programmer from coding insert, remove, and other list functions that will affect the order of your stack. This fundamentally ruins the point of defining a stack, as it no longer functions the way it should. The existing list methods make it very easy to use a list as a stack. Remember, the last element added is the first element retrieved, Last In, First Out or LIFO. To add an item to the top of the stack, we use append(). To retrieve an item from the top of the stack, we use pop(), without an explicit index. The top of the stack is at the right hand end, that is to say that both addition and removals will happen from the right. Let's see what that looks like in Python. In our project, I'm going to open 02_02, and I'm going to open stack.py 'cause that's the file that we're working in. And you'll see there's just a tiny bit of boiler plate code that we've provided. Now, pass is there on line nine because if you don't put pass inside of an empty class definition or function definition, then you get an error when you run the code. Whereas now with pass, I can run the code and there won't be an error. However, it doesn't do much, so let's start coding. So, like I say, if you haven't used classes before, don't worry, I'm going to tell you everything you need to know. So, we're going to start off of a function called underscore underscore init. And, PyCharm automatically fills in self as an argument for that. Now init is what we call the constructor So, just to give you a tiny bit of context for that, we're going to be creating objects called stacks, or in this case, just one object called a stack. And that object is going to be based on the template, which is the stack class. So when we code this init method, this is the code that gets to run when we create the object from the template. And that will all make more sense as we go along. So inside the constructor, we're going to create self.items and set this equal to an empty list, okay? So self.items means, the items property of the object that we're creating. So self is always referring to, this specific instance of the class that we're talking about at the moment. And again, if that isn't quite clear, it will become clear as we go along. So that's all we need to do in our constructor, now we're going to have a method called is empty for checking. If our stack easy empty, def is, is_ empty, and again, PyCharm nicely fills that in for me, and here, I'm going to return, whether or not the length of self.items. So I'm going to return whether or not the length of self.items is equal to zero, because in that case, it would be empty. Now that isn't actually the most pythonic way of doing this, there is another way which would be to return not self.items which works because an empty list actually evaluates as false. So if that's confusing, then there's no need to use that version. I'm just giving you the most pythonic version if you're interested. So I'm actually going to use that second version, but leave the first one there as a comment so you can choose whichever one you prefer, then onto push, so def push. Now I should mention that inside of a class definition functions are actually referred to as methods there's no difference, but a method is a function inside of a class, so this is actually the push method, So push, and it gives me self by default, and then item, because there's an item that I'm going to push onto my stack. So what I do, is self.items.append. Now, this is the standard list method append. So we push the item onto ourselves.items and then pop Def pop self, we return self.items.pop. Again, this is the standard list pop operation, okay. So basically we're just taking a list and all of the methods that you're probably familiar with we've lists and we wrapping them in our own abstraction in our own stack class so that we can use the terminology we want and we can control how we interface with the list. And now we have Def peak. And what this does is it returns the last item in our list. It returns self.items at index zero one. Now Python and some other languages. You can access the end of a list by using negative indices. So the item at index negative one is the last item in the list, then quite useful to have size so we can find out the size of our stack. And here we're going to return Len of self.items fairly straight forward. And then finally we have double underscore str. Now what this does, it's very useful. Enables us to use the print statement to inspect our stack, to see what's inside our stack. So we can return str of self.items. And you're going to see how old these messages work in a moment. So that's the basic class definition. Now I'm going to do, if name, double underscore name is equal to now this little code snippet is quite famous in Python. You may or may not have seen it before, or know what it does, but I'm just going to quickly talk you through it. So the idea is if we wanted to import this stack class into another file, then it would be a problem. If we had code that was defined here, because that would also run in our imported file. okay. And that would ruin what we wanted to happen properly. So what we can do is we can say, if this is the main file that is being run, then execute the following code that I'm about to write from line 33 onwards. If not, then you can just use the class and not worry about this code being run. So that's how that works. So let's go ahead and create a stack. So S equals K so the convention for class definitions is we use a capital letter. So lowercase S is my object, my instance of the stack class. And it's coding stack with a capital S with two parentheses. That means called the constructor. Okay, so this is going to create self.items for this particular stack that we're creating S, okay, now let's print S and see what we get. Okay, so you can see down in the terminal, we have an empty list, which is what we would expect, because all we've done with our stack is create self.items, which is set to an empty list. Let me just show you what happens if we don't have this string methods, if I just comment that out. So how you understand better what it does. So now you can see my terminal, when I run out, I get this double underscore main.stack object. So using print gives me some information about my objects, but not much that's very useful to me as a programmer. So that's why we use this double underscore string method so that we can choose the kind of information we want to see about our object when we use the print statement. So let's do print, let's see if it's empty. So we print s.is and it should be empty. That's what we'd expect, we haven't put anything in it. And you can see in the terminal that it is true, that it's empty. So that's all looking good so far. Now let's do S.push and we need to push an actual item. Okay, it wouldn't make much sense to push something onto the stack that wasn't anything. So let me push an item onto the stack, and then we can print it. So print and see if that went on correctly. And you can see down in the terminal that we now have a list containing just the three. So we have a stack with one item on it. Let's push a couple more items. So we'll do s.push.seven and s.push And you can in theory push any data type you want onto your stack. Anything that our list will hold this object will also hold, but I'm just using integers. So I've pushed those, so now when I print my stack, There should be three items on it. Okay so hopefully this is all making sense now onto pop. So if we do print S.pop and we run it. You can see that we get five, so what is done? Pop does two things, it returns the value. Okay, so it returns, whatever item is at the right hand side at the end of our list. And as well as returning it also removes it. So now, if we were to print, You'd see that that five had actually been removed, okay. So they're in the terminal, there was a five at the end of our stack or our list. And then we returned that five and it also got removed. And then let's just check the last two methods, make sure they're working. So it will print s.peak. So just have a think about what you think that should return at this point. So remember it returns the last item of the stack. So the stack currently has three and seven on it. So because we're using the right hand end of our list as our stack, it should return seven. Let's check that by the way, I'm using control S every time I make a change to save my fault before using control shift F 10 to run, it could just use control F 10 as well, but I'm just in the habit, because if you use control shift F 10, then it will run this specific file rather than the last file that you chose to run. But don't worry too much about that. Getting used to keyboard shortcuts for your particular idea is a great idea, but it's very specific to your use case and then print S.size finally. And we should see that it's of length. What have I done that? so I didn't code it so it's printed the method because I didn't put the parentheses to actually code that method. Okay, so there it is. Let's just recap what we did. And before I do that, I'm just going to show you a really useful feature that I'm going to make a lot of use of. So at the end of writing code, it's possible that I've not used exactly the right number of lines between functions, or I've not got spaces after my commerce and little details like that, that all help you to write good clean code. So what you can do in PyCharm, you can get up to code and reformat code. And actually it looks like there was nothing that needed changing, but sometimes there is, it's always worth doing that. So let's talk through what we did. We wrote the constructor. So that's the method that gets called when we create an instance of our class. And all that does is it creates self.items, which is the list that's going to contain our items. Then we had a method to check with our stack was empty. We had a method to push items onto the top of our stack. Remember the top in this case, being the right hand, end of our list, we had a pop method to remove items, and then we could check what was on the top of our stack without actually removing it. We could find the size. And also we had a way of printing out what our stack looked like at any given stage by defining this double underscore string method. And we talked about why we would use this if double underscore name equals main and that's so that we can actually use the class definition itself in other files, without worrying about this code, getting run out of context. So now you've implemented a stack class in Python. In the next video, we will give you a challenge where you can use this class to solve an algorithmic problem, which the use of a stack provides an elegant solution for.

Contents