MVPy: Minimum Viable Python

Over 32 posts spanning well over 2 years, this is the final post in my blog series on Python's syntactic sugar. I had set out to find all of the Python 3.8 syntax that could be rewritten if you were to run a tool over a single Python source file in isolation and still end up with reasonably similar semantics (i.e., no whole-program analysis, globals() having different keys was okay, don't care about performance). Surprisingly, it turns out to be easier to list what syntax you can't rewrite than re-iterate all the syntax that you can rewrite!

  1. Integers (as the base for other literals like bytes)
  2. Function calls
  3. =
  4. Function definitions
  5. nonlocal
  6. return
  7. yield
  8. try/except
  9. raise
  10. while

All other syntax can devolve to this core set of syntax. I call this subset of syntax the Minimum Viable Python (MVPy) you need to make Python function as a whole. If you can implement this subset of the language, then you can do a syntactic translation to support the rest of Python's syntax (although admittedly it might be a bit faster if you directly implemented all the syntax 😉).

If you look at what syntax is left, it pretty much aligns to what is required to implement a Turing machine:

  1. Read/write data (= and integers)
  2. Make decisions about data (while and try)
  3. Do things to that data (everything involving defining and using functions)

You might not be as productive in this subset of the language as you would be with all the syntax available in Python 3.8 (and later), but you should still be able to accomplish the same things given enough time and patience.


Since the initial publication of this post on 2022-08-14, I was able to unravel even more syntax than I initially thought. This post has been perpetually updated to reflect those later realizations.