Python Tips and Gotchas #3 - Be more effecient with the REPL

The REPL is certainly one of Python’s most unique features. While there are other languages that also provides some kind of interactive prompt, none is as fleshed out as in Python. And while it is easy to get started with, there a few tips that will help you work faster.

Interactive execution of modules and packages

Probably the most useful feature of the REPL is the ability to load modules and packages in interactive mode. This is essentially the same as just doing import module_name while in the REPL, but this can also be done when launching the REPL. Simply use the -i flag and provide the name of the module or package (the package most be executable, in other words contain a main.py file):

python3 -i filename.py
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10e02c630>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__cached__': None, 'lst': [1, 2, 3, 4, 5]}
>>> lst # imported from provided module at start
[1, 2, 3, 4, 5]

If the module/package relies on a venv you obviosly need to activate that venv before launching the REPL. Also note that you can only provide one module or package with the -i flag, any futher arguments following the first will be ignored.

Passing arguments to the REPL

Another sometimes useful feature is the ability to pass regular arguments to the REPL, just as is possible when executing Python-files. This allows you to for example pipe information from bash in to your REPL-session. These arguments become available through sys.argv just as when executing a file:

python3 - arg1 arg2 arg3
Python 3.7.2 (v3.7.2:9a3ffc0492, Dec 24 2018, 0243) 
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys; sys.argv
['-', 'arg1', 'arg2', 'arg3']

Or if you prefer argparse just configure it like:

>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('args', metavar='N', type=str, nargs='+', help='arguments')
_StoreAction(option_strings=[], dest='args', nargs='+', const=None, default=None, type=<class 'str'>, choices=None, help='arguments', metavar='N')
>>> args = vars(parser.parse_args())
>>> args
{'args': ['arg1', 'arg2', 'arg3']}

One useful example is if you need the contents of a SSH-key in the REPL:

python3 - $(cat ~/.ssh/id_rsa.pub)
Python 3.7.2 (v3.7.2:9a3ffc0492, Dec 24 2018, 0243) 
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys;sys.argv
['-', 'ssh-rsa', 'AAAAB3NzaC1yc2EAAAADAQABA...

Use underscore instead of temporary variables

Often when the REPL is used to experiment you will need to juggle values back and forth. In those scenarios it is common to create a lot of temporary variables just to keep the result of the last command around. But there is actually an easy way to do that without creating variables left and right.

All expressions evaluated in the REPL return a value, and if that value is not None it will actually automatically be stored in a built-in variable. If you have done Python programming for some time you might have come across the best-practice of using _ for throw-away variables, most commonly in for-loops with ranges. In the REPL _ serves a different purpose:

>>> 1 + 2
3
>>> _
3
>>> _ + 3
6
>>> _
6
>>> a = 1 + 2
>>> _
6

Pay attention to the last lines, where the result of an addition operation is assigned to a but _ still contains 6 since the assignment expression returned None.

You can still use _ as a variable name and assign it normally, but that will cancel its default behaviour. To reset it, just run del _:

>>> 1 + 1
2
>>> _
2
>>> _ = 'test'
>>> 1 + 2
3
>>> _
'test'
>>> del _
>>> 5 + 5
10
>>> _
10