E.g.
uv init --script foo.py
uv add --script foo.py httpx
cat foo.py
...
dependencies = ['httpx']
...
Then on another machine: uv run foo.py
# creates a virtual env, reads foo.py to see httpx is a dependency, installs in the ephemeral venv then runs the script
The above is from memory typed on a phone so maybe some minor syntax issues but the point i tried to make was we can kinda emulate the convenience of statically compiled binaries a-la Go these daysFirst, you can move that script to a different machine and do `uv run {script}`, no need to recreate a venv or provide install instructions (I believe uv will now even grab an appropriate version of Python if you don't have it?). This comes from PEP 723, and multiple tools support doing this, such as hatch.
Second, when you "add" a requirement instead of "install" a requirement it manages that with the knowledge of all requirements that were added before. For example, if I `pip install foo` and then `pip install bar` pip does not consider foo or it's dependencies as required when installing bar, so it's possible that you can break `foo` by installing completely incompatible dependencies. But when you "add foo" and then "add bar" from uv (and other tools that are declarative, like Poetry) your environment gets updated to take everything into account.
If managing Python dependencies is second nature to you then these might seem like extra concepts to keep in your head, but lots of people do find these useful because they find they can think less about Python dependencies.
Before (analogous to go mod init):
python -m venv venv
source venv/bin/activate
python -m pip install -U pip
pip install httpx
pip freeze > requirements.txt
nvim foo.py
# find a way to share foo.py and requirements.txt
On another machine (still the before scenario, this time analogous to maybe go run): python -m venv venv
source venv/bin/activate
python -m pip install -U pip
pip install -r requirements.txt
python foo.py
In the after scenario: uv run foo.py
That's it. Comparable to ./my-go-binary
Personally I can't think of anything from Go's build system I miss now - the languages are very different for sure, but I guess we're talking about the build system only.
Want to profile your go? pprof built in (to be fair python has had cProfile forever but the Go version is more convenient to read the output).
Want to run some tests, or better yet some benchmarks? A good take on the problem space is just built in. You can safely go with the default and don't need to spend mental tax credits on selecting the best benchmarking lib from the ecosystem.
Stuff like go fmt is just taken for granted but even in the python world, there are still some non-black (and compatibles like ruff) flavoured formatters floating around - probably the most common on GH even today in Python is no formatter.
Can go on and on - go generate (maybe a tiny bit less relevant with generics being available today?), go tool, go vet, ...