As a result of going back to school for a CS grad degree, I've been using Python a ton for the first time in like 5 years. Over the weekend I was hacking away on a very debugging-heavy assignment, and I found some useful tricks for improving my Python REPL for debugging work, so I thought I'd share.
As I was doing my debugging in the REPL, I started to build up a few functions that were very useful for that purpose. But every time I exited the REPL and started it up again, or opened up another REPL in a separate terminal, I had to copy and paste all those methods in again. What I realized I wanted was a Python equivalent of a
.bashrc, a script that runs every time I start the REPL to define my functions and set up my environment.
As far as I can tell (though correct me in a comment if I'm wrong), Python doesn't look for any specific setup files by default. However, it does check for a special environment variable, called
PYTHONSTARTUP, and if that variable is set to a path, it runs the file at that path. Perfect!
I'm using Bash, so I added this line to my
If you're in Windows land, you can add "PYTHONSTARTUP" to your account's environment variables by hitting the Start button, searching for "environment", and selecting "Edit environment variables for your account", then adding a new variable.
Note: You don't necessarily have to put the file in your home directory, or name it
.pythonrc.py; you're telling Python where to look, so do what you want! Just make sure the variable points to your file, wherever you put it.
~/.pythonrc.py file is a work in progress, but here's the contents so far:
### enable tab completion import rlcompleter, readline readline.parse_and_bind("tab: complete") ### import custom python utilities import sys from os.path import expanduser sys.path.append(expanduser('~')) from custom_utils import *
I've got two things in there:
- I manually enable tab-completion, since it doesn't seem to work by default.
- I import a custom module of handy functions. I decided to define them separately from this config file so that I could use them elsewhere (back to that in a sec). To do this, I have to add my home directory (where I keep the module) to the path, then
import *from my module.
Note: Again, this module can be named anything and go anywhere, just make sure you're pointing to it correctly!
Here's the contents of my
custom_utils.py file. Again, it's a work in progress and I'm just starting with it, but I've found these methods handy for exploring the libraries I'm using for my coursework, and for debugging sessions (that's next!).
from math import ceil def chunk(size, _iter): """ split an iterable into chunks of the given size """ _num_groups = range(int(ceil(len(_iter)/float(size)))) return (_iter[n*size:(n+1)*size] for n in _num_groups) def P(obj, key=None): """ List the public properties of an object, optionally filtered by a `key` function """ props = [p for p in dir(obj) if p is not '_'] if key is not None: props = [p for p in props if key(p)] return props def PT(obj, key=None): """ List an object's public properties in a 4-col table, optionally filtered by a `key` function """ _p = P(obj, key=key) if filter is not None: _max_w = max(len(p) for p in _p) print('\n'.join(''.join(n.ljust(ceil((_max_w/4 + 2)*4)) for n in c) for c in chunk(4, P(obj))))
These functions are all centered around a problem I had during my coursework. The instructors gave us starter code, and we had to add on to it to complete the assignment. The starter code used a library I hadn't encountered before, and that library's documentation was less than thorough, so I used these methods to do a lot of manual digging into the objects it created and passed around.
The cool part about this file, though, is that you can add whatever you find useful to it, build it up over the years, sync it to a Git repo, whatever!
Another tool I used a lot over this weekend was
pdb, the debugger built into Python. It has its own REPL, and I was frustrated to find that the
pdb REPL doesn't pay any attention to the PYTHONSTARTUP variable. However, I was very happy to find that it actually does have a default config file,
Since I had my custom functions in a separate module, all I had to do was import that module in my
.pdbrc, and I was set!
### enable tab completion import rlcompleter import pdb pdb.Pdb.complete = rlcompleter.Completer(locals()).complete ### import custom python utilities import sys from os.path import expanduser sys.path.append(expanduser('~')) from custom_utils import *
Note that enabling tab-completion in
pdb is slightly different from the standard REPL, but StackOverflow came to my rescue!
That's my setup and my little utilities, but I'd love to see yours! Leave any handy Python utility functions you use all the time in the comments!