Image

Trey Hunner: Handy Python REPL Modifications

I find myself in the Python REPLa lot.

I open up the REPL to play with an idea, to use Python as a calculator or quick and dirty text parsing tool, to record a screencast, to come up with a code example for an article, and (most importantly for me) to teach Python. My Python courses and workshops are based largely around writing code together to guess how something works, try it out, and repeat.

As I’ve written about before, you canadd custom keyboard shortcutsto the new Python REPL (since 3.13) andcustomize the REPL syntax highlighting(since 3.14). If you spend time in the Python REPL and wish it behaved a little morelike your favorite editor, these tricks can come in handy.

I have addedcustom keyboard shortcutsto my REPL and other modifications to help memore quickly write and edit code in my REPL. I’d like to share some of the modifications that I’ve found helpful in my own Python REPL.

Creating a PYTHONSTARTUP file

If you want to run Python code every time an interactive prompt (a REPL) starts, you can make a PYTHONSTARTUP file.

When Python launches an interactive prompt, it checks for aPYTHONSTARTUPenvironment variable. If it finds one, it treats it as a filename that contains Python code and itruns all the code in that file, as if you had copy-pasted the code into the REPL.

So all of the modifications I have made to my Python REPL rely on thisPYTHONSTARTUPvariable in my~/.zshenvfile:

If you use bash, you’ll put that in your~/.bashrcfile. If you’re on Windowsyou’ll need to set an environment variable the Windows way.

With that variable set, I can now create a~/.startup.pyfile that has Python code in it. That code will automatically run every time I launch a new Python REPL, whether within a virtual environment or outside of one.

My REPL keyboard shortcuts

The quick summary of mycurrentmodifications are:

  • PressingHomemoves to thefirst character in the code block
  • PressingEndmoves to thelast character in the code block
  • PressingAlt+Mmoves to thefirst characteron the current line
  • PressingShift+Tabremovescommon indentationfrom the code block
  • PressingAlt+Upswaps the current line withthe line above it
  • PressingAlt+Downswaps the current line withthe line below it
  • PressingCtrl+Ninsertsa specific list of numbers
  • PressingCtrl+Finsertsa specific list of strings

If you’ve readmy Python REPL shortcutsarticle, you know that we can useCtrl+Ato move to the beginning of the line andCtrl+Eto move to the end of the line. I already use those instead of the Home and End keys, so I decided to rebind Home and End to do something different.

TheAlt+Mkey combination is essentially the same asAlt+Min Emacs or^in Vim. I usually prefer to move to the beginning of the non-whitespace in a line rather than to the beginning of theentireline.

TheShift+Tabfunctionality is basically a fancy wrapper aroundusingtextwrap.dedent: it dedents the current code block while keeping the cursor over the same character it was at before.

TheCtrl+NandCtrl+Fshortcuts make it easier for me to grab an example data structure to work with when teaching.

In addition to the above changes, I also modify my color scheme to work nicely with my Solarized Light color scheme in Vim.

I created a pyrepl-hacks library for this

My PYTHONSTARTUP file became so messy that I ended up creating apyrepl-hacks libraryto help me with these modifications.

My PYTHONSTARTUP filenow looks pretty much like this:

That’s pretty short!

But wait… won’t this fail unless pyrepl-hacks is installed in every virtual environmentandinstalled globally for every Python version on my machine?

That’s where thatsys.path.appendtrick comes in handy…

Wait… let’s acknowledge the dragons 🐲

At this point I’d like to pause to note that all of this relies on using an implementation detail of Python that is deliberately undocumented because itis not designedto be used by end users.

The above code all relies on the_pyreplmodule that was added in Python 3.13 (and optionally the_colorizemodule that was added in Python 3.14).

When I run a new future version of Python (for example Python 3.15) this solution may break. I’m willing to take that risk, as I know that I can always unset my shell’sPYTHONSTARTUPvariable or clear out my startup file.

So, just be aware… here be (private undocumented implementation detail) dragons.

Monkey patchingsys.pathto allow importingpyrepl_hacks

I didn’t install pyrepl-hacksthe usual way. Instead, I installed it in a very specific location.

I created a~/.pyhacksdirectory and then installedpyrepl-hacksintothat directory:

In order for thepyrepl_hacksPython package to work, it needs to available within every Python REPL I might launch. Normally that would mean that it needs to be installed in every virtual environment that Python runs within. This trick avoids that constraint.

When Python tries to import a module, it iterates through thesys.pathdirectory list. Any Python packages foundwithinany of thesys.pathdirectories may be imported.

So monkey patchingsys.pathwithin my PYTHONSTARTUP file allowspyrepl_hacksto be imported in every Python interpreter I launch:

With those 3 lines (or something like them) placed in my PYTHONSTARTUP file, all interactive Python interpreters I launch will be able to import modules that are located in my~/.pyhacksdirectory.

Creating your own custom REPL commands

That’s pretty neat. But what if you want to invent your own REPL commands?

Well, thebindutility I’ve created in thepyrepl_hacksmodule can be used as a decorator for that.

This will make Ctrl+X followed by Ctrl+R insertimport subprocessfollowed bysubprocess.run("", shell=True)with the cursor positioned in between the double quotes after it’s all inserted:

You can read more about the ins and outs of the pyrepl-hacks packagein the readme file.

pyrepl-hacks is just a fancy wrapper

The pyrepl-hacks package is really just a fancy wrapper around Python’s_pyrepland_colorizemodules.

Why did I make a whole package and then modify mysys.pathto use it, when I could have just used_pyrepldirectly?

Three reasons:

  1. To make creating new commandsa biteasier (functions can be used instead of classes)
  2. To make the key bindings look a bit nicer (I prefer"Ctrl+M"overr"\C-M")
  3. To hide my hairy hacks behind a shiny API ✨

Before I made pyrepl-hacks, I implemented these commands directly within my PYTHONSTARTUP file by reaching into the internals of_pyrepldirectly.

My PYTHONSTARTUP file before pyrepl-hacks wasover 100 lines longer.

Try pyrepl-hacks and leave feedback

My hope is that thepyrepl-hackslibrary will be obsolete one day. Eventually the_pyreplmodule might be renamed topyrepl(or maybe justrepl?) and it will have a well-documented friendly-ish public interface.

In the meantime, I plan to maintain pyrepl-hacks. As Python 3.15 is developed, I’ll make sure it continues to work. And I may add more useful commands if I think of any.

If you hack your own REPL, I’d love to hear what modifications you come up with. And if you have thoughts on how to improve pyrepl-hacks, please open an issue or get in touch.

Also,if you use Windows,please help meconfirmwhether certain keys work on Windows. Thanks!

Contributions and ideas welcome!

https://treyhunner.com/2025/10/handy-python-repl-modifications/