惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
爱范儿
爱范儿
人人都是产品经理
人人都是产品经理
博客园 - 司徒正美
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
量子位
罗磊的独立博客
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
小众软件
小众软件
C
Cybersecurity and Infrastructure Security Agency CISA
Cyberwarzone
Cyberwarzone
大猫的无限游戏
大猫的无限游戏
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
雷峰网
雷峰网
Simon Willison's Weblog
Simon Willison's Weblog
The Cloudflare Blog
博客园 - 三生石上(FineUI控件)
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cyber Attacks, Cyber Crime and Cyber Security
博客园_首页
博客园 - 叶小钗
V
Vulnerabilities – Threatpost
T
The Exploit Database - CXSecurity.com
T
Tailwind CSS Blog
IT之家
IT之家
博客园 - 聂微东
Spread Privacy
Spread Privacy
V2EX - 技术
V2EX - 技术
S
Security Affairs
宝玉的分享
宝玉的分享
V
V2EX
C
Cisco Blogs
博客园 - Franky
美团技术团队
酷 壳 – CoolShell
酷 壳 – CoolShell
月光博客
月光博客
S
Securelist
J
Java Code Geeks
Webroot Blog
Webroot Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
P
Proofpoint News Feed
Last Week in AI
Last Week in AI
L
LINUX DO - 热门话题
NISL@THU
NISL@THU
WordPress大学
WordPress大学
W
WeLiveSecurity
T
Threatpost
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
腾讯CDC
阮一峰的网络日志
阮一峰的网络日志

ashishb.net

A day in Luxembourg - the richest country in the world I was asked to install malware during a fake interview Book summary: Breakneck - China's quest to engineer the future by Dan Wang Book summary: How to Teach Your Baby to Read Book Summary: The Discontented Little Baby Book by Pamela Douglas Introducing Amazing Sandbox - run third-party tools and AI agents securely on your machine Why software outsourcing gets a bad reputation? Book summary: The Natural Baby Sleep Solution by Polly Moore A day in Antwerp, Belgium Journey of online influencers Two days in Brussels, Belgium Shortcuts - when we love them and when we don't A visit to Rakhigarhi Three days in overhyped Paris Empty Japan, crowded Tokyo The real lock-in in GitHub is not the code, but the stars 11-day Norwegian Breakaway East Caribbean cruise Sanskrit and Sri Lankan Air Force Use REST with Open API The Achilles heel of American capitalism Costa Rica in 4 days At a juice stall in Sri Lanka A short stay at Warsaw, Poland Best practices for using Python & uv inside Docker Two days in Vilnius, Lithuania How IntelliJ IDEs waste disk space Pregnancy Why there aren't many digital nomads from India Two days in Riga, Latvia To keep your machine secure, run third-party tools inside Docker Family Ties in Your DNA: Some relatives are closer than others Doctors per capita Two days in Tallinn, Estonia Ship tools as standalone static binaries Made in America Two days in Helsinki, Finland Maintaining an Android app is a lot of work The land of good deals Two days in Oslo, Norway FastAPI vs Flask performance comparison Google Search is losing to Perplexity Two days in Dublin, Ireland Continuous integration ≠ Continuous delivery World's simplest project success heuristic London in 5 days It is hard to recommend Python in production Inflation, IRS, Credit cards, and Vendors Temu and the Chinese approach Things to do in Miami Florida Revenue vs Cost Axis Language learning as an adult The unanchored babies of the green card limbo Price variance in the United States A day in Louisville, Kentucky A surprisingly positive experience with Air India Unhospitable Airports Android: Don't use stale views USA = Union of Sales and Advertisement A day in Nashville, Tennessee Minimize Javascript in your codebase A day in Birmingham, Alabama In defense of ad-supported products Real vs artificial world The science behind Punjabi singers Hiking Mt. Fuji The Indian startup bubble is insane Repairing database on the fly for millions of users Book Summary: One up on Wall Street by Peter Lynch It is hard to recommend Google Cloud At the Prague airport Kyoto in three days Migrating from WordPress to Hugo Book summary: Sick Societies by Robert B. Edgerton Statistical outcomes require statistical games Illegal immigrants to Europe via Cairo Tokyo in three days Mobs are Status Games Writing Script matters as much as the spoken language Sri Lanka in 5 days LLMs: great for business but bad business Book Summary: Safe Haven by Mark Spitznagel Mac shortcut for typing Avagraha symbol On a bus with an asylum seeker Nicaragua in 5 days When to commit Generated code to version control Why I always buy a local SIM in a foreign country Use Makefile for Android Four days in Guadalajara, Mexico Android Navigation: Up vs Back Hotels vs Airbnb vs Hostels Currency issues in Argentina Abstractions should be deep not wide Some data on podcasting Always support compressed response in an API service A day in El Calafate - Patagonia, Argentina Hermetic docker images with Hugging Face machine learning models American Elections The sound of "ch" API services should always have usage Limits Hiking in El Chaltén - trekking capital of Argentina
How to run Python in production
Ashish Bhatia · 2025-04-19 · via ashishb.net

Featured on Hacker News

RedditFeatured in Pycoder’s WeeklyAwesome Python Weekly NewsletterFeatured in CNET Japan

My previous article recommended that one should reconsider using Python in production. However, there’s one category of use case where Python is the dominant option for running production workloads. And that’s data analysis and machine learning.

Almost all bleeding-edge work in data analysis and machine learning, especially around LLMs, happens in Python.

So, here are some of my learnings on how to run Python in production.

Project quality

Package manager

Python has a fragmented ecosystem of package managers. The only ones I can recommend are poetry and uv. After learning about uv on Hacker News, I decided to give it a try. uv is blazingly fast and manages the Python binary as well. It even supports migrations from other package managers. The only downside is that uv is still not on a stable release yet.

1
2
3
# uv is really fast for both fresh and incremental package updates
$ uv sync --all-groups
Resolved 193 packages in 9ms

Linters

Since Python is a dynamically typed language, it is very easy to write code that is either outright broken or breaks along certain code paths.

Linters are the first line of defense against such code. There is a plethora of linters available for Python. None seems to be sufficient on its own. My current stack consists of ruff, autoflake, flake8, isort, and pylint.

1
2
3
4
5
6
7
format:
	# I enable a lot of linters including isort, flake8, autoflake, pylint equivalent and others
	uv run ruff check --config pyproject.toml --fix .

lint:
	# Config file is specified for brevity
	uv run ruff check --config pyproject.toml .

Microsoft’s pyright might be good but, in my experience, produces too many false positives.

mypy is even worse, see this detailed discussion.

I haven’t yet found a good way to enforce type hints or type checking in Python.

Update (May 2025)

Prevent secret leaks

Use gitguardian, gitleaks, or noseyparker to prevent secrets from being committed to the repository.

In my experience, GitGuardian is the best, but it is a closed-source tool, while Gitleaks and Noseyparker are open-source.

This advice isn’t specific to Python, but something that engineers who have spent a lot of time writing non-production code in Python Notebooks, do make the mistake of.

Use git commit hook

Pre-commit hooks are good for enforcing code quality. This is not specific to Python either but is a good practice that’s useful when you are working with data engineers and data scientists who excel at data analysis more than writing production-ready code.

Project maintainability

FastAPI

If you are writing a web service, then go for a combination of fastapi and gunicorn. In my benchmarking, everything else being equal, FastAPI+gunicorn has 3X the throughput of Flask+gunicorn.

1
2
3
4
5
$ h2load --h1 -n1000 -c40 <Flask+gunicorn>
...
                      min         max         mean         sd        +/- sd
time for request:      406us     83.37ms     12.56ms     22.46ms    86.70%
req/s           :      75.98       83.04       79.36        2.08    60.00%
1
2
3
4
5
6
$ h2load --h1 -n1000 -c40 <Fastapi+gunicorn>
...
                      min         max         mean         sd        +/- sd
 time for request:      825us     29.78ms      4.07ms      6.13ms    91.70%
 req/s           :     231.07      256.41      241.98        8.86    52.50%
...

Data classes

Use data-classes or more advanced pydantic for holding data and use helper classes to group pure functions that operate on those data classes. I was planning to write more, but then I came across this recently written elaborate article on this topic.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from typing import List
import uuid
import dataclasses


@dataclasses.dataclass
class Person:
    id: uuid.UUID
    name: str
    degrees: List[str]

Avoid multi-threading

Python’s GIL is a mess. Multi-threading in Python codebases is not well tested and is a source of bugs.

It is best to avoid any concurrency in Python codebases. If you need performance, use multiple processes instead.

Edit: After this article went viral on Reddit, I updated to clarify my opinion. asyncio is a great way to write concurrent code in Python. Using libraries like fastapi that use asyncio underneath is good. However, writing async functions (async def ...) should be done only at one’s discretion.

Here’s another great article on why async Python is not popular.

Dependency management

pip-audit could be useful for dependencies with known vulnerabilities. I have never found anything useful, primarily because I use dependabot for automatic dependency updates.

1
2
3
4
5
6
7
8
# Sample dependabot config
version: 2
updates:
- package-ecosystem: "pip"
  directory: "/<path-to-directory-containing-requirements-or-pyproject.toml>"
  schedule:
    interval: "daily"
  open-pull-requests-limit: 1

Further, deptry is a useful tool for finding unused dependencies in Python projects. The results do contain false positives, but it is a good starting point for cleaning up unused dependencies.

1
2
$ pipx run deptry .  # or uv add --group dev deptry && uv run deptry .
...

Keep code legally compliant

Python has a lot of libraries with licenses that could be troublesome for the codebase. E.g., libraries with GPL licenses that could make the whole codebase GPL. To avoid it, use licensecheck on CI.

1
2
3
4
5
6
$ uv run licensecheck --format ansi \
  --only-licenses apache bsd isc mit mpl python unlicense \
  --fail-licenses gpl \
  --show-only-failing \
  --zero
...

Deployments

Docker

Use docker for deployments. Even if you are using GPU-enabled VMs, use Docker and expose the GPU to the container with the following parameter.

1
docker run --gpus all ...

Further, use multi-stage builds where you use poetry/uv to build the package and then copy the built package to a smaller base image on top of python:3.XX-slim.

I have tried Python’s Alpine-based images (python:alpine) and for any non-trivial project, it is very hard to use it due to Debian’s glibc vs Alpine’s musl differences. So, I would recommend against using Alpine-based images for Python.

Nore that while there have been attempts at making Python faster like PyPy, and Codon, they are really difficult to use for any non-trivial project. So, stick to the standard Python interpreter.

Use CPU-only libraries for non-GPU deployments

PyTorch is huge. If you are going to be using pytorch in a non-GPU deployment, then use the CPU-only version. It is significantly smaller with no loss of accuracy.

You can configure this with multi-stage Docker builds or uv has a detailed explanation on how to do this using pyproject.toml.

1
2
$ pip3 install torch --index-url https://download.pytorch.org/whl/cpu
...

Compile code during build

Compile code during Docker builds. This ensures that the .pyc files exist. It is especially useful for faster boot times during container auto-scaling.

1
RUN python -m compileall <code_dir>

Download external dependencies at build time

Many libraries like spacy and transformers download large chunks of data on the first use. This not only slows down the container boot time but also makes the Docker build non-hermetic. This was exposed during a HuggingFace outage last year.

Further, prevent downloads during execution with additional library-specific guards.

1
2
3
4
5
6
# First, Download models
...
# And then disable access to HuggingFace completely
ENV TRANSFORMERS_OFFLINE=1
ENV HF_HUB_OFFLINE=1
ENTRYPOINT ...

Alternatively, you can place these models in cloud/VM storage (PVC on Kubernetes) and mount them as Docker volumes during runtime. For larger models, usually, this is the only choice as building and deploying 5 GiB+ docker images is noticeably slower.

Run Docker containers as a non-root user

The Python docker images have a much larger attack surface than my favorite scratch image for Go deployments.

One should run Python-based containers as a non-root user to reduce the attack surface.

1
2
3
4
5
6
# In the final build stage
RUN groupadd -r appuser && useradd -r -g appuser appuser
COPY --chown=appuser:appuser --from=previous-step /app /app
USER appuser
# Rest of the build steps
ENTRYPOINT ...

Updates after going viral on Reddit & Hacker News