DEV Community

Cover image for Your Own Python REPL in Twenty Lines or Less
Ryan Palo
Ryan Palo

Posted on • Edited on • Originally published at assertnotmagic.com

Your Own Python REPL in Twenty Lines or Less

Have you ever been in a Python interactive REPL and said to yourself, "You know, this is nice and all, but... it's missing something. There's not enough me!" Well, worry no more! I'll show you how to do it in twenty lines or less! Let me introduce the main attraction:

Code

As unhelpful as that sounds, it's true. Python has a module in the standard library called Code. You can check out the code module documentation if you don't believe me. The documentation is maybe a little tough to understand on first pass-through, so I thought I'd create a few examples to show it off. There are a few objects in the code module, but only one that I'm going to talk about this time: interact.

Interact

Let's dive in. I'll show you. Let's create a new file in our directory called shell.py.

#!/usr/bin/env python
# I'll be using Python 3, for reference.

import code  # seems silly, but works great

def custom_repl():
    pie = "delicious"
    pi = 3.14159
    homonyms = (pie != pi)
    code.interact(
        banner="Hello!  My name is Jeeves!  I am fancy.  🎩",
        local=locals(),
        exitmsg="Ta-ta!"
    )

if __name__ == "__main__":
    custom_repl()
Enter fullscreen mode Exit fullscreen mode

Try running it and watch the magic work.

$ python3 shell.py
Hello!  My name is Jeeves!  I am fancy.  🎩
>>> pi
3.1415
>>> pie
'delicious'
>>> homonyms
True
>>> 4 + 3
7
>>> import math
>>> math.sqrt(pi)
1.7724531023414978
<Ctrl-D>
Ta-ta!
Enter fullscreen mode Exit fullscreen mode

As you can see, the banner message we specified shows, the exit message we specified shows (although it didn't work for me if I used the built-in exit() or quit() commands), and we had access to the local variables when interact was called. And we can use anything to act as our local state! Go back in and create shell2.py.

#!/usr/bin/env python
# shell2.py

import code

class Car:
    def __init__(self, color, mileage):
        self.color = color
        self.mileage = mileage

    def honk(self):
        return "Beep!"

    def __repr__(self):
        return "<Car - color: {}, mileage: {}>".format(self.color, self.mileage)

if __name__ == "__main__":
    c = Car("red", 20000)
    code.interact(
        banner="Now interactively inspecting {}".format(c),
        local={"car": c},
    )
Enter fullscreen mode Exit fullscreen mode

Back in the shell... python3 shell2.py

Now interactively inspecting <Car - color: red, mileage: 20000>
>>> car
<Car - color: red, mileage: 20000>
>>> car.honk()
'Beep!'
Enter fullscreen mode Exit fullscreen mode

Keep in mind that the local parameter to interact has to be a Dict -- such as the one returned by local() and global().

Wrap Up

You can use this to provide a nice interactive aspect to your app to help you do shell things, inspect objects, debug, and much more. This is roughly how pdb works too! Django and Flask both use a variation on this for their "shell" commands too. I think I'm going to try to use it to generate an automated quiz or homework for a python intro class (similar to the swirl package in R). Have any other cool ways you've used this? Let me know!


Originally posted on my blog

Top comments (2)

Collapse
 
debugloop profile image
Daniel Nägele

Check out IPython's embed too, it's basically the same thing but with all the additional fancy stuff.

See here.

Collapse
 
rpalo profile image
Ryan Palo

Also, this post provided the groundbreaking discovery that you can use GIFs (#GIFnotGIF) in your cover images. 237 bonus points for dev.to!