{"id":4584,"date":"2026-02-10T21:43:28","date_gmt":"2026-02-10T16:13:28","guid":{"rendered":"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/"},"modified":"2026-02-10T21:43:28","modified_gmt":"2026-02-10T16:13:28","slug":"python-best-practices-write-clean-and-efficient-code","status":"publish","type":"post","link":"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/","title":{"rendered":"Python Best Practices: Write Clean and Efficient Code"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_80 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-69e20428cf3ec\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-69e20428cf3ec\"  aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#Python_in_Production_Why_Your_%E2%80%9CBest_Practices%E2%80%9D_Are_Killing_My_On-Call_Rotation\" >Python in Production: Why Your &#8220;Best Practices&#8221; Are Killing My On-Call Rotation<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#The_Dependency_Lie_Stop_Using_requirementstxt\" >The Dependency Lie: Stop Using requirements.txt<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#Typing_is_Not_Optional_If_You_Value_Your_Sanity\" >Typing is Not Optional (If You Value Your Sanity)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#The_Asyncio_Foot-Gun\" >The Asyncio Foot-Gun<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#Logging_is_Not_for_Humans\" >Logging is Not for Humans<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#The_Docker_Trap_Alpine_is_Not_Your_Friend\" >The Docker Trap: Alpine is Not Your Friend<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#The_Real_World_Managing_State_and_Connections\" >The Real World: Managing State and Connections<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#The_%E2%80%9CGotcha%E2%80%9D_Circular_Imports_and_the_Global_Scope\" >The &#8220;Gotcha&#8221;: Circular Imports and the Global Scope<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#The_Wrap-up\" >The Wrap-up<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#Related_Articles\" >Related Articles<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"Python_in_Production_Why_Your_%E2%80%9CBest_Practices%E2%80%9D_Are_Killing_My_On-Call_Rotation\"><\/span>Python in Production: Why Your &#8220;Best Practices&#8221; Are Killing My On-Call Rotation<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>It was 3:15 AM on a Tuesday in 2019. I was staring at a Grafana dashboard that looked like a heart attack. Our main API, a Python service handling checkout flows for a major e-commerce client, was throwing 504s across three availability zones. The CPU usage was flatlined at 12%, but the memory was climbing in a perfect, terrifying 45-degree angle. We were being OOM-killed every six minutes. The culprit? A &#8220;senior&#8221; dev had implemented a custom caching decorator using a global dictionary without a TTL or a maximum size. They thought they were being clever. They thought they were following &#8220;Python best&#8221; practices for performance. They were wrong. I spent four hours manually killing pods and scaling the replica set to 50 just to keep the site alive while we reverted the commit. That was the day I stopped trusting &#8220;clean code&#8221; tutorials and started caring about how Python actually behaves when the hits the fan.<\/p>\n<p>Most &#8220;Python best&#8221; lists are written by people who have never had to debug a race condition in a production environment at scale. They talk about list comprehensions and PEP 8. I don&#8217;t care about your trailing commas. I care about your signal handling, your dependency resolution, and why your Docker image is 1.2GB. If you want to write Python that survives a traffic spike on a Friday afternoon, you need to stop thinking like a coder and start thinking like a systems engineer. Python is a beautiful, high-level language that hides a lot of complexity. That complexity is exactly what will bite you in the ass when you&#8217;re running 500 nodes in a Kubernetes cluster.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Dependency_Lie_Stop_Using_requirementstxt\"><\/span>The Dependency Lie: Stop Using requirements.txt<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>If I see a <code>requirements.txt<\/code> file in a root directory without a corresponding lockfile, I assume the project is broken. It\u2019s just a matter of time. <code>pip install -r requirements.txt<\/code> is non-deterministic. You might get <code>requests==2.31.0<\/code> today, but if a sub-dependency releases a breaking change tomorrow, your CI\/CD pipeline will explode. Or worse, it will pass, and your production environment will start behaving erratically because of a transitive dependency conflict.<\/p>\n<p>The &#8220;Python best&#8221; approach here isn&#8217;t just &#8220;use a tool.&#8221; It&#8217;s &#8220;use a tool that generates a cryptographic lockfile.&#8221; I used to advocate for Poetry, but it\u2019s become bloated and slow. These days, I\u2019m all in on <code>uv<\/code>. It\u2019s written in Rust, it\u2019s insanely fast, and it handles virtual environments without making me want to throw my laptop out the window. If you aren&#8217;t using <code>uv<\/code> or at least <code>pip-compile<\/code> from <code>pip-tools<\/code>, you aren&#8217;t doing production Python.<\/p>\n<ul>\n<li><strong>Deterministic Builds:<\/strong> Your lockfile must include hashes. If the hash of the downloaded wheel doesn&#8217;t match the lockfile, the build should fail. This prevents supply-chain attacks and ensures that what you tested in staging is exactly what runs in prod.<\/li>\n<li><strong>Separation of Concerns:<\/strong> Keep your development dependencies (like <code>pytest<\/code>, <code>black<\/code>, and <code>mypy<\/code>) separate from your runtime dependencies. Your production Docker image should not contain a test runner.<\/li>\n<li><strong>The <code>pyproject.toml<\/code> Standard:<\/strong> Stop using <code>setup.py<\/code>. It\u2019s 2024. Use the PEP 621 standard. It\u2019s declarative, readable, and doesn&#8217;t require executing arbitrary Python code just to install a package.<\/li>\n<li><strong>Avoid &#8220;Latest&#8221;:<\/strong> Never, ever use <code>package&gt;=1.0.0<\/code> in a production environment without a lockfile. You are begging for a breaking change to ruin your weekend.<\/li>\n<\/ul>\n<pre><code># Example of a modern pyproject.toml using uv\n[project]\nname = \"payment-processor\"\nversion = \"0.1.0\"\ndependencies = [\n    \"fastapi==0.110.0\",\n    \"pydantic==2.6.3\",\n    \"sqlalchemy[asyncio]==2.0.28\",\n    \"structlog==24.1.0\",\n    \"uvicorn[standard]==0.27.1\",\n]\n\n[tool.uv]\ndev-dependencies = [\n    \"pytest==8.0.2\",\n    \"mypy==1.8.0\",\n    \"httpx==0.27.0\",\n]\n<\/code><\/pre>\n<blockquote>\n<p><strong>Pro-tip:<\/strong> When using <code>uv<\/code>, you can run <code>uv pip compile pyproject.toml -o requirements.txt<\/code> to generate a pinned, hashed file if your legacy deployment scripts still require a <code>requirements.txt<\/code>. It gives you the speed of modern tools with the compatibility of the old ones.<\/p>\n<\/blockquote>\n<h2><span class=\"ez-toc-section\" id=\"Typing_is_Not_Optional_If_You_Value_Your_Sanity\"><\/span>Typing is Not Optional (If You Value Your Sanity)<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>I\u2019ve heard the argument a thousand times: &#8220;Python is dynamic, adding types just makes it Java.&#8221; This is a lazy take. In a large codebase, types are documentation that the compiler (or in this case, <code>mypy<\/code>) can actually verify. I once spent two days chasing a bug where a function expected a <code>UUID<\/code> object but received a <code>str<\/code>. In a dynamic world, it failed five layers deep inside a database driver with a cryptic <code>AttributeError<\/code>. With <code>mypy<\/code>, that\u2019s a 2-second fix during local development.<\/p>\n<p>But don&#8217;t just add types for the sake of it. Use <code>Pydantic<\/code> for data validation at the boundaries. If you&#8217;re ingesting JSON from an external API like Stripe or GitHub, you cannot trust that data. <code>Pydantic<\/code> forces you to define a schema and validates it at runtime. If the data is wrong, it fails early and loudly, rather than letting a <code>NoneType<\/code> error propagate into your business logic.<\/p>\n<pre><code>from pydantic import BaseModel, Field, field_validator\nfrom uuid import UUID\nfrom datetime import datetime\n\nclass StripeWebhook(BaseModel):\n    event_id: str = Field(..., alias=\"id\")\n    created_at: datetime = Field(..., alias=\"created\")\n    user_id: UUID\n    amount_cents: int\n\n    @field_validator(\"amount_cents\")\n    @classmethod\n    def must_be_positive(cls, v: int) -> int:\n        if v &lt;= 0:\n            raise ValueError(\"We aren't giving money away.\")\n        return v\n\ndef process_payment(data: dict):\n    # This is where the magic happens. If data is malformed, \n    # Pydantic raises a ValidationError immediately.\n    payment = StripeWebhook(**data)\n    print(f\"Processing {payment.amount_cents} for {payment.user_id}\")\n<\/code><\/pre>\n<p>Notice I used <code>UUID<\/code> and <code>datetime<\/code>. These aren&#8217;t just strings. Pydantic handles the conversion for you. This is &#8220;Python best&#8221; practice because it reduces the cognitive load on the next developer. They don&#8217;t have to guess what <code>data<\/code> contains; the code tells them exactly what to expect.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Asyncio_Foot-Gun\"><\/span>The Asyncio Foot-Gun<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Everyone wants to use <code>asyncio<\/code> because it sounds fast. &#8220;It&#8217;s non-blocking!&#8221; they shout. Sure, it&#8217;s non-blocking until you accidentally call a synchronous library like <code>requests<\/code> inside an <code>async def<\/code> function. Now you\u2019ve blocked the entire event loop, and your &#8220;high-performance&#8221; service is processing exactly one request at a time while the others time out. I&#8217;ve seen entire clusters grind to a halt because someone used <code>time.sleep()<\/code> instead of <code>await asyncio.sleep()<\/code>.<\/p>\n<p>If you are doing heavy CPU work\u2014image processing, heavy math, or even just massive JSON parsing\u2014<code>asyncio<\/code> is the wrong tool. Python&#8217;s Global Interpreter Lock (GIL) still exists (mostly, until 3.13&#8217;s free-threading matures). For CPU-bound tasks, you need <code>multiprocessing<\/code>. For I\/O-bound tasks, <code>asyncio<\/code> is great, but you have to be disciplined. You need to audit every single library you use to ensure it&#8217;s async-compatible. Using <code>psycopg2<\/code>? Stop. Use <code>psycopg<\/code> (version 3) or <code>asyncpg<\/code>. Using <code>requests<\/code>? Switch to <code>httpx<\/code> or <code>aiohttp<\/code>.<\/p>\n<p>One of the biggest &#8220;gotchas&#8221; in <code>asyncio<\/code> is task management. People love <code>asyncio.gather(*tasks)<\/code>, but it\u2019s dangerous. If one task fails, the others keep running, often in a &#8220;zombie&#8221; state, leaking resources. In Python 3.11+, we finally got <code>TaskGroup<\/code>, which handles this properly. If one task in a group fails, the others are cancelled. This is how you write resilient code.<\/p>\n<pre><code>import asyncio\nimport httpx\n\nasync def fetch_service_status(client: httpx.AsyncClient, url: str):\n    response = await client.get(url, timeout=5.0)\n    response.raise_for_status()\n    return response.json()\n\nasync def monitor_system():\n    urls = [\n        \"https:\/\/api.stripe.com\/health\",\n        \"https:\/\/api.github.com\/status\",\n        \"http:\/\/localhost:8080\/health\"\n    ]\n\n    async with httpx.AsyncClient() as client:\n        try:\n            async with asyncio.TaskGroup() as tg:\n                tasks = [tg.create_task(fetch_service_status(client, url)) for url in urls]\n\n            results = [t.result() for t in tasks]\n            print(f\"All systems operational: {results}\")\n        except ExceptionGroup as eg:\n            # Handle multiple failures gracefully\n            print(f\"System failures detected: {eg.exceptions}\")\n\n# Pro-tip: Use uvloop for a faster event loop implementation in production.\n# import uvloop\n# asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())\n<\/code><\/pre>\n<p>If you&#8217;re still on Python 3.9 or 3.10, you&#8217;re living in the past. Upgrade. The performance improvements in 3.11 and 3.12 alone are worth the migration effort. We saw a 15% drop in p99 latency just by bumping the runtime version without changing a single line of code.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Logging_is_Not_for_Humans\"><\/span>Logging is Not for Humans<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>If your logs look like this: <code>INFO: User 12345 logged in<\/code>, you are making my life miserable. When I&#8217;m trying to aggregate logs from 50 different microservices in an ELK stack or Datadog, I don&#8217;t want to write complex regex patterns to extract a user ID. I want JSON. Structured logging is the only way to maintain observability in a distributed system.<\/p>\n<p>The standard <code>logging<\/code> module in Python is a nightmare of global state and confusing configurations. I prefer <code>structlog<\/code>. It allows you to attach context to a logger. For example, when a request comes in, you can bind a <code>request_id<\/code> to the logger. Every subsequent log message\u2014even those deep in your business logic\u2014will automatically include that <code>request_id<\/code>. This makes tracing a single request across your entire stack trivial.<\/p>\n<ul>\n<li><strong>Contextual Binding:<\/strong> Bind <code>user_id<\/code>, <code>correlation_id<\/code>, and <code>environment<\/code> at the top level.<\/li>\n<li><strong>Level Discipline:<\/strong> <code>DEBUG<\/code> is for local dev. <code>INFO<\/code> is for high-level flow. <code>WARNING<\/code> is for &#8220;this is weird but we can recover.&#8221; <code>ERROR<\/code> is for &#8220;someone needs to look at this.&#8221; <code>CRITICAL<\/code> is for &#8220;the database is gone.&#8221;<\/li>\n<li><strong>No PII:<\/strong> Never, ever log passwords, credit card numbers, or PII. I once had to scrub 4TB of logs because a dev logged the entire <code>kwargs<\/code> of a <code>create_user<\/code> function.<\/li>\n<\/ul>\n<pre><code>import structlog\nfrom uuid import uuid4\n\n# Configure structlog to output JSON for production\nstructlog.configure(\n    processors=[\n        structlog.processors.add_log_level,\n        structlog.processors.TimeStamper(fmt=\"iso\"),\n        structlog.processors.JSONRenderer()\n    ]\n)\n\nlogger = structlog.get_logger()\n\ndef handle_request(user_id: str):\n    # Bind request-specific context\n    log = logger.bind(request_id=str(uuid4()), user_id=user_id)\n\n    log.info(\"processing_request\", action=\"payment_initiate\")\n\n    try:\n        # Simulate business logic\n        1 \/ 0\n    except Exception as e:\n        log.error(\"request_failed\", error=str(e), exc_info=True)\n\nhandle_request(\"user_8821\")\n<\/code><\/pre>\n<p>The output is a clean JSON object. My log aggregator can index <code>user_id<\/code> and <code>request_id<\/code> automatically. I can now query for all errors associated with <code>user_8821<\/code> in seconds. That\u2019s how you reduce Mean Time To Resolution (MTTR).<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Docker_Trap_Alpine_is_Not_Your_Friend\"><\/span>The Docker Trap: Alpine is Not Your Friend<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>There is a common &#8220;Python best&#8221; tip that says you should use Alpine Linux for your Docker images to keep them small. This is terrible advice for Python. Python relies heavily on <code>glibc<\/code>. Alpine uses <code>musl<\/code>. Most pre-compiled Python wheels (the stuff you download from PyPI) are built for <code>glibc<\/code>. When you try to install them on Alpine, <code>pip<\/code> can&#8217;t find a compatible wheel, so it tries to compile the package from source.<\/p>\n<p>Now your &#8220;small&#8221; image needs <code>gcc<\/code>, <code>make<\/code>, and a bunch of system headers just to install <code>pandas<\/code> or <code>cryptography<\/code>. Your build time goes from 30 seconds to 15 minutes, and your final image is actually *larger* than if you had just used a slim Debian-based image. Use <code>python:3.12-slim-bookworm<\/code>. It\u2019s stable, it\u2019s compatible with almost everything, and it\u2019s maintained by people who know what they\u2019re doing.<\/p>\n<p>Also, stop running your containers as root. It&#8217;s a massive security risk. If someone finds an exploit in your web framework, they have root access to the container. Use a non-privileged user.<\/p>\n<pre><code># Use a specific version, never 'latest'\nFROM python:3.12-slim-bookworm AS builder\n\n# Set environment variables to make Python behave in Docker\nENV PYTHONDONTWRITEBYTECODE=1 \\\n    PYTHONUNBUFFERED=1 \\\n    UV_PROJECT_ENVIRONMENT=\/venv\n\n# Install uv\nCOPY --from=ghcr.io\/astral-sh\/uv:latest \/uv \/bin\/uv\n\nWORKDIR \/app\nCOPY pyproject.toml uv.lock .\/\n\n# Install dependencies into a virtualenv\nRUN uv sync --frozen --no-dev\n\n# Final stage\nFROM python:3.12-slim-bookworm\n\nWORKDIR \/app\nCOPY --from=builder \/venv \/venv\nCOPY .\/src .\/src\n\n# Create a non-root user\nRUN groupadd -g 999 python && \\\n    useradd -r -u 999 -g python python\nUSER python\n\nENV PATH=\"\/venv\/bin:$PATH\"\n\n# Use exec form for CMD to handle signals correctly\nCMD [\"uvicorn\", \"src.main:app\", \"--host\", \"0.0.0.0\", \"--port\", \"8000\"]\n<\/code><\/pre>\n<p>Using the <code>exec<\/code> form (<code>[\"executable\", \"param1\"]<\/code>) for your <code>CMD<\/code> is crucial. If you use the shell form (<code>CMD uvicorn src.main:app<\/code>), Python runs as a child of <code>\/bin\/sh<\/code>. When Kubernetes sends a <code>SIGTERM<\/code> to stop the pod, the shell doesn&#8217;t forward it to Python. Your app will just sit there until K8s loses patience and <code>SIGKILL<\/code>s it after 30 seconds. This means no graceful shutdowns, no closing DB connections, and potentially corrupted data.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Real_World_Managing_State_and_Connections\"><\/span>The Real World: Managing State and Connections<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>In a production environment, your Python app is rarely a standalone entity. It\u2019s a node in a graph. It talks to Postgres, Redis, RabbitMQ, and third-party APIs. The way you manage these connections determines whether your app is resilient or brittle.<\/p>\n<p>One of the most common mistakes is not setting timeouts on *everything*. If you use the <code>requests<\/code> library, the default timeout is <code>None<\/code>. This means if a third-party API hangs, your worker thread will hang forever. Eventually, all your workers are stuck waiting for a response that will never come, and your service goes down. Always set a connect timeout and a read timeout.<\/p>\n<p>Database connection pooling is another area where &#8220;Python best&#8221; practices often fail. People either open too many connections and crash Postgres, or they don&#8217;t use a pool and spend half their request time doing TCP handshakes. If you&#8217;re using SQLAlchemy, use the <code>QueuePool<\/code>. If you&#8217;re in a serverless environment like AWS Lambda, you need a proxy like RDS Proxy or PgBouncer because Lambda will exhaust your connection limit in seconds.<\/p>\n<pre><code>from sqlalchemy.ext.asyncio import create_async_engine\n\n# Production-ready engine configuration\nengine = create_async_engine(\n    \"postgresql+asyncpg:\/\/user:pass@localhost\/dbname\",\n    pool_size=20,          # Maximum number of permanent connections\n    max_overflow=10,       # Allow 10 extra connections during spikes\n    pool_timeout=30,       # Give up after 30 seconds of waiting for a connection\n    pool_recycle=1800,     # Close connections after 30 mins to avoid stale links\n    pool_pre_ping=True     # Check if the connection is alive before using it\n)\n<\/code><\/pre>\n<p>The <code>pool_pre_ping=True<\/code> is a lifesaver. It handles the &#8220;The network went away for a second&#8221; scenario by transparently reconnecting if the connection is dead. Without it, your first few requests after a DB restart will all fail with a <code>BrokenPipeError<\/code>.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_%E2%80%9CGotcha%E2%80%9D_Circular_Imports_and_the_Global_Scope\"><\/span>The &#8220;Gotcha&#8221;: Circular Imports and the Global Scope<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>As your project grows, you will eventually hit a circular import. You have <code>models.py<\/code> that needs <code>utils.py<\/code>, and <code>utils.py<\/code> that needs <code>models.py<\/code>. The &#8220;Python best&#8221; way to fix this isn&#8217;t to put the import inside a function (though that works in a pinch). It&#8217;s to refactor. Circular imports are a sign of tight coupling. Move the shared logic to a third module, or use type hinting strings (<code>\"ModelName\"<\/code>) to avoid importing the class at runtime.<\/p>\n<p>Also, be extremely careful with what you put in the global scope. Anything at the top level of a module is executed when the module is imported. If you have a <code>db_connection = connect_to_db()<\/code> at the top of a file, that connection will be created during the build process or when your unit tests run. This is a nightmare for testing. Use dependency injection or a factory pattern. Keep your side effects inside functions or classes that are instantiated at runtime.<\/p>\n<p>I once saw a codebase where a global variable was used to store a configuration fetched from an AWS Parameter Store. Every time a developer ran a unit test, the test suite would try to connect to AWS. If they were on a plane without Wi-Fi, the tests wouldn&#8217;t even start. Don&#8217;t be that person. Use <code>pydantic-settings<\/code> to manage your config and load it explicitly.<\/p>\n<pre><code>from pydantic_settings import BaseSettings, SettingsConfigDict\n\nclass Settings(BaseSettings):\n    db_url: str\n    api_key: str\n    debug: bool = False\n\n    model_config = SettingsConfigDict(env_file=\".env\")\n\n# Instantiate once at the entry point of your app\nsettings = Settings()\n<\/code><\/pre>\n<h2><span class=\"ez-toc-section\" id=\"The_Wrap-up\"><\/span>The Wrap-up<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Stop chasing the latest &#8220;clean code&#8221; trends and start looking at your telemetry. Python is a tool, and like any tool, it has failure modes that only appear under pressure. Focus on deterministic dependencies, strict typing at the boundaries, disciplined concurrency, and structured observability. If you can&#8217;t explain how your app handles a <code>SIGTERM<\/code> or what happens when your database latency triples, you haven&#8217;t followed &#8220;Python best&#8221; practices; you&#8217;ve just written code that works on your machine. Build for the failure, not the happy path.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Related_Articles\"><\/span>Related Articles<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Explore more insights and best practices:<\/p>\n<ul>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/install-and-secure-phpmyadmin-with-nginx-on-ubuntu-18-04\/\">Install And Secure Phpmyadmin With Nginx On Ubuntu 18 04<\/a><\/li>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/install-php-in-ubuntu-18-04\/\">Install Php In Ubuntu 18 04<\/a><\/li>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/adding-custom-pins-and-thumbs-to-openstreetmap-in-android\/\">Adding Custom Pins And Thumbs To Openstreetmap In Android<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Python in Production: Why Your &#8220;Best Practices&#8221; Are Killing My On-Call Rotation It was 3:15 AM on a Tuesday in 2019. I was staring at a Grafana dashboard that looked like a heart attack. Our main API, a Python service handling checkout flows for a major e-commerce client, was throwing 504s across three availability zones. &#8230; <a title=\"Python Best Practices: Write Clean and Efficient Code\" class=\"read-more\" href=\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/\" aria-label=\"Read more  on Python Best Practices: Write Clean and Efficient Code\">Read more<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4584","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Python Best Practices: Write Clean and Efficient Code - ITSupportWale<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Python Best Practices: Write Clean and Efficient Code - ITSupportWale\" \/>\n<meta property=\"og:description\" content=\"Python in Production: Why Your &#8220;Best Practices&#8221; Are Killing My On-Call Rotation It was 3:15 AM on a Tuesday in 2019. I was staring at a Grafana dashboard that looked like a heart attack. Our main API, a Python service handling checkout flows for a major e-commerce client, was throwing 504s across three availability zones. ... Read more\" \/>\n<meta property=\"og:url\" content=\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/\" \/>\n<meta property=\"og:site_name\" content=\"ITSupportWale\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Itsupportwale-298547177495978\" \/>\n<meta property=\"article:published_time\" content=\"2026-02-10T16:13:28+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2021\/05\/android-chrome-512x512-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"512\" \/>\n\t<meta property=\"og:image:height\" content=\"512\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Techie\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Techie\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"14 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/\"},\"author\":{\"name\":\"Techie\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d\"},\"headline\":\"Python Best Practices: Write Clean and Efficient Code\",\"datePublished\":\"2026-02-10T16:13:28+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/\"},\"wordCount\":2074,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/\",\"url\":\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/\",\"name\":\"Python Best Practices: Write Clean and Efficient Code - ITSupportWale\",\"isPartOf\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#website\"},\"datePublished\":\"2026-02-10T16:13:28+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/itsupportwale.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Python Best Practices: Write Clean and Efficient Code\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#website\",\"url\":\"https:\/\/itsupportwale.com\/blog\/\",\"name\":\"ITSupportWale\",\"description\":\"Tips, Tricks, Fixed-Errors, Tutorials &amp; Guides\",\"publisher\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/itsupportwale.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\",\"name\":\"itsupportwale\",\"url\":\"https:\/\/itsupportwale.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png\",\"contentUrl\":\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png\",\"width\":1119,\"height\":144,\"caption\":\"itsupportwale\"},\"image\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/Itsupportwale-298547177495978\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d\",\"name\":\"Techie\",\"sameAs\":[\"https:\/\/itsupportwale.com\",\"iswblogadmin\"],\"url\":\"https:\/\/itsupportwale.com\/blog\/author\/iswblogadmin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Python Best Practices: Write Clean and Efficient Code - ITSupportWale","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/","og_locale":"en_US","og_type":"article","og_title":"Python Best Practices: Write Clean and Efficient Code - ITSupportWale","og_description":"Python in Production: Why Your &#8220;Best Practices&#8221; Are Killing My On-Call Rotation It was 3:15 AM on a Tuesday in 2019. I was staring at a Grafana dashboard that looked like a heart attack. Our main API, a Python service handling checkout flows for a major e-commerce client, was throwing 504s across three availability zones. ... Read more","og_url":"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/","og_site_name":"ITSupportWale","article_publisher":"https:\/\/www.facebook.com\/Itsupportwale-298547177495978","article_published_time":"2026-02-10T16:13:28+00:00","og_image":[{"width":512,"height":512,"url":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2021\/05\/android-chrome-512x512-1.png","type":"image\/png"}],"author":"Techie","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Techie","Est. reading time":"14 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#article","isPartOf":{"@id":"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/"},"author":{"name":"Techie","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d"},"headline":"Python Best Practices: Write Clean and Efficient Code","datePublished":"2026-02-10T16:13:28+00:00","mainEntityOfPage":{"@id":"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/"},"wordCount":2074,"commentCount":0,"publisher":{"@id":"https:\/\/itsupportwale.com\/blog\/#organization"},"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/","url":"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/","name":"Python Best Practices: Write Clean and Efficient Code - ITSupportWale","isPartOf":{"@id":"https:\/\/itsupportwale.com\/blog\/#website"},"datePublished":"2026-02-10T16:13:28+00:00","breadcrumb":{"@id":"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/itsupportwale.com\/blog\/python-best-practices-write-clean-and-efficient-code\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/itsupportwale.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Python Best Practices: Write Clean and Efficient Code"}]},{"@type":"WebSite","@id":"https:\/\/itsupportwale.com\/blog\/#website","url":"https:\/\/itsupportwale.com\/blog\/","name":"ITSupportWale","description":"Tips, Tricks, Fixed-Errors, Tutorials &amp; Guides","publisher":{"@id":"https:\/\/itsupportwale.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/itsupportwale.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/itsupportwale.com\/blog\/#organization","name":"itsupportwale","url":"https:\/\/itsupportwale.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png","contentUrl":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png","width":1119,"height":144,"caption":"itsupportwale"},"image":{"@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Itsupportwale-298547177495978"]},{"@type":"Person","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d","name":"Techie","sameAs":["https:\/\/itsupportwale.com","iswblogadmin"],"url":"https:\/\/itsupportwale.com\/blog\/author\/iswblogadmin\/"}]}},"_links":{"self":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts\/4584","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/comments?post=4584"}],"version-history":[{"count":0,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts\/4584\/revisions"}],"wp:attachment":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/media?parent=4584"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/categories?post=4584"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/tags?post=4584"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}