Skip to content Skip to sidebar Skip to footer

Implement the Stack Family Instance Method Flip Declared as Follows (This Is a Stack):

Watch Now This tutorial has a related video course created past the Real Python team. Watch it together with the written tutorial to deepen your understanding: How to Implement a Python Stack

Accept you heard of stacks and wondered what they are? Do you have the general idea but are wondering how to implement a Python stack? Y'all've come to the right place!

In this tutorial, you lot'll learn:

  • How to recognize when a stack is a good option for information structures
  • How to decide which implementation is all-time for your program
  • What actress considerations to make about stacks in a threading or multiprocessing environment

This tutorial is for Pythonistas who are comfy running scripts, know what a list is and how to use information technology, and are wondering how to implement Python stacks.

What Is a Stack?

A stack is a information structure that stores items in an Last-In/First-Out style. This is often referred to as LIFO. This is in dissimilarity to a queue, which stores items in a Showtime-In/First-Out (FIFO) manner.

It's probably easiest to understand a stack if y'all call back of a utilize case y'all're likely familiar with: the Undo feature in your editor.

Let's imagine you're editing a Python file so we tin can wait at some of the operations y'all perform. First, you add a new office. This adds a new particular to the undo stack:

Pushing the "add function" operation to the undo stack.

You tin run into that the stack now has an Add Function operation on it. Afterwards adding the function, you delete a discussion from a comment. This as well gets added to the undo stack:

Pushing the "delete word" operation on the undo stack.

Observe how the Delete Word item is placed on top of the stack. Finally y'all indent a comment and then that it'southward lined up properly:

Pushing the "indent comment" operation on the undo stack.

You can meet that each of these commands are stored in an disengage stack, with each new command being put at the top. When you're working with stacks, calculation new items like this is called push button.

At present yous've decided to undo all iii of those changes, so you hitting the undo command. It takes the item at the top of the stack, which was indenting the annotate, and removes that from the stack:

Popping the "indent comment" function from the undo stack.

Your editor undoes the indent, and the undo stack at present contains two items. This performance is the opposite of push button and is commonly called pop.

When you hit undo again, the next detail is popped off the stack:

Popping the "delete word" operation from the undo stack.

This removes the Delete Word particular, leaving just i operation on the stack.

Finally, if you lot hitting Undo a third time, then the last item will be popped off the stack:

Popping the "add function" operation from the undo stack.

The undo stack is at present empty. Hitting Undo once more afterwards this volition take no outcome considering your undo stack is empty, at to the lowest degree in most editors. You'll see what happens when you telephone call .pop() on an empty stack in the implementation descriptions below.

Implementing a Python Stack

There are a couple of options when you lot're implementing a Python stack. This article won't cover all of them, just the bones ones that will meet nearly all of your needs. Y'all'll focus on using data structures that are role of the Python library, rather than writing your ain or using third-party packages.

You lot'll look at the post-obit Python stack implementations:

  • list
  • collections.deque
  • queue.LifoQueue

Using list to Create a Python Stack

The built-in list structure that y'all probable use frequently in your programs can be used equally a stack. Instead of .push(), you can use .append() to add together new elements to the pinnacle of your stack, while .popular() removes the elements in the LIFO order:

>>>

                                                  >>>                                    myStack                  =                  []                  >>>                                    myStack                  .                  append                  (                  'a'                  )                  >>>                                    myStack                  .                  append                  (                  'b'                  )                  >>>                                    myStack                  .                  append                  (                  'c'                  )                  >>>                                    myStack                  ['a', 'b', 'c']                  >>>                                    myStack                  .                  pop                  ()                  'c'                  >>>                                    myStack                  .                  pop                  ()                  'b'                  >>>                                    myStack                  .                  pop                  ()                  'a'                  >>>                                    myStack                  .                  pop                  ()                  Traceback (almost recent phone call last):                  File                  "<console>", line                  1, in                  <module>                  IndexError:                  pop from empty listing                              

You tin run into in the final command that a list will heighten an IndexError if you lot call .pop() on an empty stack.

list has the advantage of being familiar. You know how it works and likely have used it in your programs already.

Unfortunately, list has a few shortcomings compared to other data structures you'll look at. The biggest event is that it tin run into speed issues equally it grows. The items in a list are stored with the goal of providing fast admission to random elements in the list. At a loftier level, this ways that the items are stored next to each other in memory.

If your stack grows bigger than the block of memory that currently holds it, then Python needs to do some memory allocations. This tin can lead to some .append() calls taking much longer than other ones.

In that location is a less serious problem every bit well. If yous employ .insert() to add an element to your stack at a position other than the end, information technology tin take much longer. This is not normally something you would do to a stack, however.

The next information structure will help you get around the reallocation problem you lot saw with list.

Using collections.deque to Create a Python Stack

The collections module contains deque, which is useful for creating Python stacks. deque is pronounced "deck" and stands for "double-ended queue."

You tin apply the same methods on deque every bit y'all saw above for list, .suspend(), and .pop():

>>>

                                                  >>>                                    from                  collections                  import                  deque                  >>>                                    myStack                  =                  deque                  ()                  >>>                                    myStack                  .                  append                  (                  'a'                  )                  >>>                                    myStack                  .                  suspend                  (                  'b'                  )                  >>>                                    myStack                  .                  suspend                  (                  'c'                  )                  >>>                                    myStack                  deque(['a', 'b', 'c'])                  >>>                                    myStack                  .                  pop                  ()                  'c'                  >>>                                    myStack                  .                  pop                  ()                  'b'                  >>>                                    myStack                  .                  pop                  ()                  'a'                  >>>                                    myStack                  .                  pop                  ()                  Traceback (well-nigh recent telephone call terminal):                  File                  "<panel>", line                  1, in                  <module>                  IndexError:                  popular from an empty deque                              

This looks almost identical to the listing case to a higher place. At this point, y'all might be wondering why the Python core developers would create ii information structures that look the aforementioned.

Why Have deque and list?

Equally y'all saw in the give-and-take almost listing above, it was built upon blocks of contiguous retentivity, significant that the items in the listing are stored right side by side to each other:

Memory structure of a list implementing a stack

This works cracking for several operations, like indexing into the list. Getting myList[3] is fast, as Python knows exactly where to wait in retentiveness to find it. This memory layout as well allows slices to work well on lists.

The contiguous memory layout is the reason that list might need to accept more than time to .suspend() some objects than others. If the block of contiguous memory is total, then information technology will demand to go some other block, which tin take much longer than a normal .append():

Memory structure of a list pushing a new element

deque, on the other hand, is congenital upon a doubly linked list. In a linked list structure, each entry is stored in its own memory block and has a reference to the next entry in the list.

A doubly linked list is only the same, except that each entry has references to both the previous and the next entry in the list. This allows y'all to easily add together nodes to either end of the listing.

Adding a new entry into a linked list structure only requires setting the new entry'due south reference to point to the current top of the stack and and so pointing the top of the stack to the new entry:

Memory structure of a deque pushing a new element

This constant-fourth dimension add-on and removal of entries onto a stack comes with a trade-off, however. Getting myDeque[3] is slower than it was for a list, because Python needs to walk through each node of the list to become to the third element.

Fortunately, yous rarely desire to exercise random indexing or slicing on a stack. Most operations on a stack are either push or pop.

The constant time .suspend() and .pop() operations make deque an splendid choice for implementing a Python stack if your code doesn't utilise threading.

Python Stacks and Threading

Python stacks can be useful in multi-threaded programs besides, but if y'all're not interested in threading, then you lot can safely skip this department and jump to the summary.

The two options yous've seen so far, list and deque, conduct differently if your program has threads.

To outset with the simpler 1, you should never apply list for any data structure that tin can be accessed past multiple threads. list is not thread-safety.

deque is a fiddling more complex, however. If you read the documentation for deque, it conspicuously states that both the .append() and .popular() operations are atomic, meaning that they won't be interrupted by a different thread.

Then if you restrict yourself to using merely .append() and .pop(), then you will be thread condom.

The concern with using deque in a threaded environs is that there are other methods in that class, and those are not specifically designed to be diminutive, nor are they thread prophylactic.

So, while it's possible to build a thread-safe Python stack using a deque, doing so exposes yourself to someone misusing it in the time to come and causing race conditions.

Okay, if y'all're threading, you can't use list for a stack and you probably don't want to utilize deque for a stack, so how tin you build a Python stack for a threaded programme?

The answer is in the queue module, queue.LifoQueue. Remember how yous learned that stacks operate on the Last-In/Offset-Out principle? Well, that'due south what the "Lifo" portion of LifoQueue stands for.

While the interface for list and deque were similar, LifoQueue uses .put() and .get() to add and remove data from the stack:

>>>

                                            >>>                                from                queue                import                LifoQueue                >>>                                myStack                =                LifoQueue                ()                >>>                                myStack                .                put                (                'a'                )                >>>                                myStack                .                put                (                'b'                )                >>>                                myStack                .                put                (                'c'                )                >>>                                myStack                <queue.LifoQueue object at 0x7f408885e2b0>                >>>                                myStack                .                get                ()                'c'                >>>                                myStack                .                get                ()                'b'                >>>                                myStack                .                get                ()                'a'                >>>                                # myStack.get() <--- waits forever                >>>                                myStack                .                get_nowait                ()                Traceback (most recent call final):                File                "<panel>", line                1, in                <module>                File                "/usr/lib/python3.vii/queue.py", line                198, in                get_nowait                return                self                .                get                (                cake                =                False                )                File                "/usr/lib/python3.7/queue.py", line                167, in                get                enhance                Empty                _queue.Empty                          

Dissimilar deque, LifoQueue is designed to be fully thread-safe. All of its methods are safe to use in a threaded environs. It likewise adds optional time-outs to its operations which tin can frequently be a must-take characteristic in threaded programs.

This full thread safety comes at a price, however. To accomplish this thread-safety, LifoQueue has to do a picayune actress work on each performance, meaning that information technology will take a little longer.

Oft, this slight slow down will not matter to your overall program speed, but if you've measured your performance and discovered that your stack operations are the clogging, then carefully switching to a deque might be worth doing.

I'd similar to stress once again that switching from LifoQueue to deque because information technology's faster without having measurements showing that your stack operations are a clogging is an instance of premature optimization. Don't do that.

Python Stacks: Which Implementation Should You Apply?

In full general, you should use a deque if you're non using threading. If you are using threading, then you should use a LifoQueue unless you've measured your performance and found that a small boost in speed for pushing and popping will make enough difference to warrant the maintenance risks.

list may be familiar, but it should be avoided because it tin potentially have retentivity reallocation bug. The interfaces for deque and list are identical, and deque doesn't have these issues, which makes deque the best option for your non-threaded Python stack.

Conclusion

You now know what a stack is and accept seen situations where they can be used in real-life programs. You've evaluated three different options for implementing stacks and seen that deque is a keen option for non-threaded programs. If you're implementing a stack in a threading environment, then it's likely a good thought to utilize a LifoQueue.

You are now able to:

  • Recognize when a stack would exist a good data structure
  • Select which implementation is correct for your problem

If you still have questions, feel gratis to achieve out in the comments sections beneath. Now, go write some code since you gained another tool to aid y'all solve your programming problems!

Watch Now This tutorial has a related video class created past the Real Python team. Watch it together with the written tutorial to deepen your understanding: How to Implement a Python Stack

swanaccultoo.blogspot.com

Source: https://realpython.com/how-to-implement-python-stack/

Postar um comentário for "Implement the Stack Family Instance Method Flip Declared as Follows (This Is a Stack):"