In response to the recent one-off proposals for adding CLI functionality to modules, another possiblitity would be adding a startup switch to the interpreter that would:
- Scan the command line for text of the form x.y and automatically try to import “x”
- Print the return value of the last statement if not None
The switch could be -ai or -am (auto import, auto module). Or (since this is Python), Something Completely DIfferent.
Demo:
python -am 'random.randrange(1,10)'
4
python -am 3 + 8
11
python -am '3 + 8; 2 + 2'
4
python -am 'zipfile.is_zipfile("demo.zip")'
True
python -am zipfile.ZIP_STORED
0
python -am zipfile.ZIP_DEFLATED
8
python -am 'math.sin(3)'
0.1411200080598672
python -am 'datetime.datetime.now()'
2025-03-14 06:33:33.730365
I had ChatGPT gen up a demo implementation:
#!/usr/bin/env python3
import sys
import re
import importlib
import ast
def try_import(module_name):
"""Attempt to import the module and add it to globals() without raising an error."""
try:
mod = importlib.import_module(module_name)
globals()[module_name] = mod
except ImportError:
pass # Ignore import errors
def wrap_last_expr(source_code):
"""
Parse the source code; if the last statement is an expression,
replace it with an assignment to __result and an if-statement that
prints __result if it is not None.
"""
try:
tree = ast.parse(source_code, mode="exec")
except Exception:
# If parsing fails, compile normally
return compile(source_code, filename="<string>", mode="exec")
if tree.body and isinstance(tree.body[-1], ast.Expr):
last_expr = tree.body.pop()
# Create assignment: __result = (last_expr)
assign = ast.Assign(
targets=[ast.Name(id="__result", ctx=ast.Store())],
value=last_expr.value
)
# Create if statement:
# if __result is not None:
# print(__result)
if_stmt = ast.If(
test=ast.Compare(
left=ast.Name(id="__result", ctx=ast.Load()),
ops=[ast.IsNot()],
comparators=[ast.Constant(value=None)]
),
body=[ast.Expr(
value=ast.Call(
func=ast.Name(id="print", ctx=ast.Load()),
args=[ast.Name(id="__result", ctx=ast.Load())],
keywords=[]
)
)],
orelse=[]
)
tree.body.append(assign)
tree.body.append(if_stmt)
ast.fix_missing_locations(tree)
return compile(tree, filename="<ast>", mode="exec")
else:
return compile(tree, filename="<ast>", mode="exec")
def main():
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} '<python_command>' '<python_command>' ...")
sys.exit(1)
# Join all arguments as a single string of Python commands.
commands = " ".join(sys.argv[1:])
# Find all occurrences of x.y and attempt to import module x.
matches = re.findall(r'\b([a-zA-Z_][a-zA-Z0-9_]*)\.', commands)
for mod in set(matches):
try_import(mod)
# Transform the code to capture and print the last expression's result.
code = wrap_last_expr(commands)
# Execute the compiled code.
exec(code, globals(), locals())
if __name__ == "__main__":
main()