<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: DigitalOcean</title>
    <description>The latest articles on DEV Community by DigitalOcean (@digitalocean_staff).</description>
    <link>https://dev.to/digitalocean_staff</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F64516%2Fa0c9989b-6d18-46c7-bc66-4c2c1580534e.jpg</url>
      <title>DEV Community: DigitalOcean</title>
      <link>https://dev.to/digitalocean_staff</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/digitalocean_staff"/>
    <language>en</language>
    <item>
      <title>How do I cap inference billing to avoid surprise costs from idle GPUs or runaway agents?</title>
      <dc:creator>DigitalOcean</dc:creator>
      <pubDate>Wed, 14 Oct 2026 16:31:01 +0000</pubDate>
      <link>https://dev.to/digitalocean/how-do-i-cap-inference-billing-to-avoid-surprise-costs-from-idle-gpus-or-runaway-agents-1cbd</link>
      <guid>https://dev.to/digitalocean/how-do-i-cap-inference-billing-to-avoid-surprise-costs-from-idle-gpus-or-runaway-agents-1cbd</guid>
      <description>&lt;p&gt;You cap inference billing by layering controls, not by flipping one switch. On DigitalOcean, Serverless Inference is prepaid, so your balance is a real ceiling, and scoped keys, alerts, and cleanup jobs cover the rest. Spend alerts alone won't stop anything: they email you when spending crosses a threshold, but your usage keeps running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serverless Inference stops when funds run out, so fund a dedicated balance with only what you plan to spend.
&lt;/li&gt;
&lt;li&gt;Dedicated Inference and GPU Droplets bill by the hour until destroyed, so automate cleanup.
&lt;/li&gt;
&lt;li&gt;Agents need caps in your own code, because rate limits slow spending but don't cap it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use prepaid balances as a ceiling
&lt;/h2&gt;

&lt;p&gt;Serverless usage draws from promotional credits, then the Inference and Agents balance, then your account prepayment balance. Only Serverless Inference and Managed Agents draw from the first, so it works as a separate AI budget. Auto-reload is on by default, so turn it off for a hard stop. A zero balance is also an outage, so reserve this for experiments and non-critical workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add alerts and scope your keys
&lt;/h2&gt;

&lt;p&gt;Spend alerts email you at percentage thresholds of your monthly budget, within an hour of each threshold being crossed. Their sole purpose is notification. Give each service its own model access key, scoped to specific models and a VPC, so one leak or loop has a small blast radius. Regenerating a key takes effect immediately, which is how you want it to work during an incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cap agents in code
&lt;/h2&gt;

&lt;p&gt;Rate limits (up to 120 requests and 1.5M tokens per minute at the lowest serverless tier) limit speed, not total spend. Harness Runtime has no per-session or per-product spend limit, so an agent stuck in an unintended loop can quickly drain balances. Set a max output token count per call, a max step count per task, and a running spend counter that stops the run. You should also pause idle sessions, since paused sessions incur no compute charges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop paying for idle GPUs
&lt;/h2&gt;

&lt;p&gt;Dedicated Inference bills per GPU-hour, and GPU Droplets bill per second until destroyed. Powering off doesn't stop the meter. At \$30.32 per hour for 8x H100, an idle Dedicated Inference endpoint costs roughly \$728 a day. &lt;/p&gt;

&lt;p&gt;To cap inference billing and avoid surprise costs, tag experimental GPU Droplets and destroy them nightly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;doctl compute droplet delete &lt;span class="nt"&gt;--tag-name&lt;/span&gt; ephemeral-gpu &lt;span class="nt"&gt;--force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Inference billing cap FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can I get usage alerts or hard spending caps on a managed AI platform before bills run away?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
DigitalOcean spend alerts notify you at budget thresholds but don't limit usage. The closest hard cap is Serverless Inference's prepaid model, where access is suspended when credits and balances run out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does powering off a GPU Droplet stop billing?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No. The GPU stays reserved, so billing continues until you destroy the Droplet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which inference option doesn't penalize variable workloads?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Serverless Inference, which bills per token instead of reserving GPUs, is a solid choice for variable workloads. Dedicated Inference bills per GPU-hour, whether or not anyone calls it, so it suits steady traffic better than spiky traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  References &amp;amp; further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.digitalocean.com/platform/billing/spend-alerts/" rel="noopener noreferrer"&gt;Spend alerts&lt;/a&gt;: worth setting up first.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.digitalocean.com/products/inference/how-to/manage-serverless-inference-prepayment/" rel="noopener noreferrer"&gt;Manage Serverless Inference prepayment&lt;/a&gt;: explains the order balances are drawn down.
&lt;/li&gt;
&lt;li&gt;Learn more about &lt;a href="https://docs.digitalocean.com/products/inference/how-to/manage-model-access-keys/" rel="noopener noreferrer"&gt;model access keys&lt;/a&gt; and &lt;a href="https://docs.digitalocean.com/products/inference/details/limits/" rel="noopener noreferrer"&gt;inference limits&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.digitalocean.com/products/inference/details/pricing/" rel="noopener noreferrer"&gt;Inference pricing&lt;/a&gt;: worth checking directly before you build.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.digitalocean.com/products/droplets/details/pricing/" rel="noopener noreferrer"&gt;Droplet pricing and billing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.digitalocean.com/products/managed-agents/agent-harness-runtime/details/pricing/" rel="noopener noreferrer"&gt;Harness Runtime pricing&lt;/a&gt;: worth bookmarking before you run agents at scale.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>developers</category>
      <category>cloud</category>
      <category>startup</category>
    </item>
    <item>
      <title>We moved a production backend from a phone</title>
      <dc:creator>DigitalOcean</dc:creator>
      <pubDate>Tue, 13 Oct 2026 13:19:33 +0000</pubDate>
      <link>https://dev.to/digitalocean/we-moved-a-production-backend-from-a-phone-1k36</link>
      <guid>https://dev.to/digitalocean/we-moved-a-production-backend-from-a-phone-1k36</guid>
      <description>&lt;p&gt;&lt;strong&gt;Published by Vinay Kumar, Chief Product and Technology Officer at DigitalOcean&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Every era of the cloud has a unit of work. For agents, it’s a human who directs, a controller who runs the operation, and a worker who does the heavy lifting. Last week we watched all three move a production backend, from a phone.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I’ve spent fifteen years building cloud services: S3 and EBS in the early days of AWS, Oracle Cloud Infrastructure from inception, and now the agentic cloud at DigitalOcean. In every era, moving a backend meant the same thing: a project plan, a maintenance window, and a team working late into the night.&lt;/p&gt;

&lt;p&gt;Last week, Rohit Bhattacharjee on our team moved an entire production backend from his phone. Database, APIs, file storage, and about 31,000 AI search embeddings. He never opened a laptop. A message while waiting for coffee. A decision between meetings. By the end of the week, it was done.&lt;/p&gt;

&lt;p&gt;This wasn’t a demo. It was a real workload with a bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three parties, three jobs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The worker&lt;/strong&gt; was a &lt;a href="https://www.digitalocean.com/products/managed-agents" rel="noopener noreferrer"&gt;DigitalOcean Managed Agent&lt;/a&gt;, an AI that does real work in the cloud, not just chat. It ran in our &lt;a href="https://docs.digitalocean.com/products/managed-agents/agent-harness-runtime/" rel="noopener noreferrer"&gt;Harness Runtime&lt;/a&gt;: a private, isolated computer that spins up for each session, with a workspace that persists when the agent pauses. Through our &lt;a href="https://docs.digitalocean.com/products/managed-agents/action-gateway/" rel="noopener noreferrer"&gt;Action Gateway&lt;/a&gt;, a single connection to 20,000+ tools, it could use GitHub, Supabase, a web browser, and the whole DigitalOcean API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The agent never saw a password.&lt;/strong&gt; The gateway applies credentials at the moment of use, so they never reach the model.&lt;/p&gt;

&lt;p&gt;It provisioned the database, loaded all 40 access policies, and mapped every Supabase feature to its DigitalOcean counterpart. It wasn’t advising on a migration. It was performing one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The controller&lt;/strong&gt; was a personal agent running on his phone, the agent Rohit actually talked to. He ran the migration in plain chat, and the personal agent turned his messages into work: tasking the worker, tracking the run, and reporting back. When he asked it to check a claim, it did. The worker said 145,432 rows had been loaded, so the controller counted them. Validation was the side job. The main job was holding the whole operation together in one conversation, so a person never had to leave the flow of his day.&lt;/p&gt;

&lt;p&gt;The worker and controller come from different model families. That’s the point of an open platform: you choose the right model for each job.&lt;/p&gt;

&lt;p&gt;Rohit provided the credentials, his judgment, and a credit card. He reviewed a $180 proposed plan and saved almost 80% on a revision with just a few taps. Everything else, the two agents handled between themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  What moved
&lt;/h2&gt;

&lt;p&gt;The workload was &lt;a href="http://huffl.ai/" rel="noopener noreferrer"&gt;huffl.ai&lt;/a&gt;, an agentic canvas that puts docs, spreadsheets, whiteboard, presentations, and search in one place. Underneath: 31 tables, 145,432 rows, three storage buckets, 24 functions, and 30,650 embeddings, the numeric fingerprints that make search work.&lt;/p&gt;

&lt;p&gt;Before moving anything, the worker read all of it and caught two problems that would have poisoned the migration. Two overloaded functions that looked like duplicates. A “vector count” that was really measuring string lengths.&lt;/p&gt;

&lt;p&gt;The new home: managed Postgres ($15), one App Platform app running four services ($20), and one object store ($5). About $40 a month. The data moved with per-table parity checks, and every one of the 30,650 embeddings verified non-null.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pay for the work, not the wait
&lt;/h2&gt;

&lt;p&gt;An agent spends most of its session waiting: on a model, a tool, or a person. The runtime paused the worker whenever it waited and resumed it in about 300 milliseconds. While it slept, the meter stopped. We bill for active CPU, not provisioned capacity. The agent runtime for the entire run cost a few dollars.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this changes
&lt;/h2&gt;

&lt;p&gt;Moving a backend used to mean a team, a plan, a maintenance window, and a war room. Last week it meant chat bubbles. The human says what needs to happen, the controller runs the operation, the worker does the work, and every claim gets checked along the way.&lt;/p&gt;

&lt;p&gt;The work didn’t get smaller. What one person can accomplish got bigger. See it in action: watch the video:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/z2nO7f-7ZGE" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Try DigitalOcean Managed Agents today. Bring your preferred harness, connect your tools, and give your agents a complete environment with our Cuttlefish mobile application coming soon. &lt;a href="https://cloud.digitalocean.com/managed-agents/harness-runtime?i=e0fda3" rel="noopener noreferrer"&gt;Get started today&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What would you trust an agent to move for you, and what would you want checking its work?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>cloud</category>
      <category>database</category>
    </item>
    <item>
      <title>Jev: an AI model that can’t write a sentence</title>
      <dc:creator>DigitalOcean</dc:creator>
      <pubDate>Fri, 09 Oct 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/digitalocean/jev-an-ai-model-that-cant-write-a-sentence-3cj</link>
      <guid>https://dev.to/digitalocean/jev-an-ai-model-that-cant-write-a-sentence-3cj</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frl0ka9ms5vgx3bap4qwe.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frl0ka9ms5vgx3bap4qwe.jpg" alt="Jev: an AI model that can’t write a sentence" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ICYMI AI: The latest AI trends, delivered to you on Dev.to&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tech Talk: TypeSafe’s Jev is a model that only returns probabilities
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://typesafe.ai/blog/introducing-system-one-models-and-jev" rel="noopener noreferrer"&gt;TypeSafe's Jev&lt;/a&gt;, released into early access on September 15, is a general-purpose classification model. It reads up to 32K tokens of input (such as a support ticket, a customer record, or a row of data). It answers any number of typed questions about it in a single parallel pass, and returns probabilities rather than prose.&lt;/p&gt;

&lt;p&gt;Outputs are limited to three options: Choice, Score, and Noul (yes or no), so structured-output errors and bad tool calls drop to zero by construction. A valid answer isn't always the right one, and Jev doesn't claim otherwise. &lt;/p&gt;

&lt;p&gt;What it does is tell you how sure it is. TypeSafe trains it for calibration, so its probabilities match real-world frequencies. When Jev says it's 80% confident, it's right about 80% of the time. That lets you set a threshold, automatically acting on high-confidence calls and routing the rest to a human or a larger model.&lt;/p&gt;

&lt;p&gt;The pricing is what makes Jev worth a look. At \$0.042 per million input tokens with free output, TypeSafe estimates about \$0.0004 per decision, roughly 1/76th the cost of GPT-5.6 Terra on its benchmark. Within days, imitators appeared: Laya, Bespoke Nimble, and Kev, several of them open-weight fine-tunes of Qwen 3.5 you can run locally. OpenAI likewise followed with a Decisions API of its own.&lt;/p&gt;

&lt;p&gt;For developers, the change is in how you structure the call. Instead of sending an LLM one broad question like "is this spam?" and parsing a paragraph back, you pass Jev the email once, along with a set of narrower typed questions, such as: Does the sender domain match the claimed company? Does it ask for credentials? How urgent is the language? Each comes back as a probability. Your own code then applies the thresholds and makes the call, so the routing policy lives in your repo, versioned and auditable, and the model only scores the inputs.&lt;/p&gt;

&lt;p&gt;Jev is available today on Serverless Inference through the &lt;a href="https://www.digitalocean.com/products/model-library" rel="noopener noreferrer"&gt;DigitalOcean Model Library&lt;/a&gt;, at Typesafe’s list price—no separate TypeSafe account needed. Pair it with the DigitalOcean Inference Router to send routing and classification traffic to Jev while keeping frontier models in reserve for the calls that need them.&lt;/p&gt;




&lt;h3&gt;
  
  
  Event calendar
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/open-intelligence-summit" rel="noopener noreferrer"&gt;&lt;strong&gt;Open Intelligence Summit&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;October 12-13th, San Francisco&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The argument is no longer “Is open source AI cheaper?” It’s now “Who owns intelligence?” A movement is forming around open intelligence and generating the belief that the intelligence powering our AI products and companies should be more open, portable, and controllable.&lt;/p&gt;

&lt;p&gt;Join DigitalOcean, NVIDIA, RadixArk, Inferact, and more for deep dives, demos, and discussions about the technologies that keep intelligence portable, interoperable, and in the hands of builders. &lt;/p&gt;




&lt;h3&gt;
  
  
  Industry news
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Near-flagship intelligence at a fifth of the price was the headline at OpenAI DevDay, but the bigger shift is the stack forming around the model&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
&lt;a href="https://openai.com/index/introducing-gpt-6-1-sol/" rel="noopener noreferrer"&gt;OpenAI announced&lt;/a&gt; GPT-6.1 Sol, which it says delivers near-Astra intelligence at a fifth of Astra's token prices, plus an Ultrafast tier with up to 6x faster generation in the API. It also added computer use to its Agents API and opened ChatGPT, which it puts at 1.2B weekly users, to developer-built plugins and partners like Devin, Notion, and Vercel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent safety is moving below the application layer&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
&lt;a href="https://nvidianews.nvidia.com/news/open-agent-safety-platform" rel="noopener noreferrer"&gt;NVIDIA's Open Agent Safety Platform&lt;/a&gt; pairs OpenShell, an open-source runtime that traces agent actions and enforces policy, with Sentry, an out-of-band watchdog on BlueField-4 DPUs that NVIDIA says can quarantine an agent that leaves its boundaries within milliseconds. NVIDIA says more than 100 organizations, including Anthropic and CrowdStrike, are working with the technology, and DigitalOcean is among the companies supporting the platform.&lt;/p&gt;




&lt;h2&gt;
  
  
  New models available on DigitalOcean Inference Engine
&lt;/h2&gt;

&lt;p&gt;We recently launched models from TypeSafeAI, DeepSeek, Z.ai, NVIDIA, OpenAI, and Anthropic, all with different strengths and use cases. Learn more about the models in our &lt;a href="https://www.digitalocean.com/blog/whats-new-on-inference-engine" rel="noopener noreferrer"&gt;What’s New blog&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Start using them through the &lt;a href="https://docs.digitalocean.com/products/inference/how-to/si-endpoints/" rel="noopener noreferrer"&gt;DigitalOcean API&lt;/a&gt; or directly in the &lt;a href="https://cloud.digitalocean.com/model-studio/explore-models/model-catalog?i=b69464" rel="noopener noreferrer"&gt;Cloud Console&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DeepSeek-V4.1-Flash&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
DeepSeek-V4.1-Flash cuts the KV cache footprint to 1/4 of V4-Flash while outperforming DeepSeek's own V4-Pro flagship on coding and agentic benchmarks, addressing the cache-hit charges that often dominate agent costs. The 552B MoE model activates just 8B parameters on input, delivering frontier performance with infrastructure economics that improve as you scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GLM-5.3 and GLM-5.3-Flash from Z.ai&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Z.ai's post-training translates to significant performance improvements for GLM-5.3, achieving a 50% lower cost per completed coding task than GLM-5.2 while jumping to 28.3 on Terminal-Bench 3.0. GLM-5.3-Flash adds native image and video input with the same agentic strength, giving teams both reasoning-heavy and efficient multimodal paths on a single platform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nemotron™ 3 Diarization from NVIDIA&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
NVIDIA's Nemotron™ 3 Diarization replaces the multi-stage speaker attribution pipeline (VAD, embeddings, clustering, post-processing) with a single 100M-parameter model, keeping audio within DigitalOcean's infrastructure rather than routing it to third-party APIs. It identifies up to 8 speakers (double the previous limit) with a 14.72% error rate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GPT-6.1 Sol, GPT-6 Astra, Sol, and Luna from OpenAI&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
One week after GPT-6 Sol’s launch, OpenAI releases GPT-6.1 Sol, which offers near-Astra-level coding and substantial improvements in document understanding, computer use, and scientific work. OpenAI's three-tier GPT-6 family also debuts on DigitalOcean: Astra for computer use and coding, Sol for frontier reasoning at 90% lower cost than Opus 5, and Luna for high-volume tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Fable 5.1, Opus 5.5, and Sonnet 5.5 from Anthropic&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Anthropic's latest point releases deliver focused gains: Fable 5.1 reaches 55.8% on Terminal-Bench 4.0 with 75% cheaper cache reads, while Opus 5.5 matches high-effort results at default effort using half the tokens and 20% lower per-token cost. Sonnet 5.5 runs 30% faster with equivalent cost savings, with a shift toward better token efficiency and lower verification burden.&lt;/p&gt;




&lt;h3&gt;
  
  
  Community tutorials
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/conceptual-articles/how-naive-failover-between-inference-providers-makes-outages-worse" rel="noopener noreferrer"&gt;&lt;strong&gt;How naive failover between inference providers makes outages worse&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
In a six-hour fault-injection run on an H200 GPU Droplet, the standard retry-with-backoff policy pushed 3.54x normal load onto a degraded provider, while a retry budget plus circuit breaker held it to 1.02x, and naive retries left 3,743 zombie requests generating 959,232 output tokens for clients that had already disconnected. Learn how to classify inference errors before failing over, replace fixed retry counts with a budget, and verify whether your provider actually stops billing when you cancel a stream.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/the-real-cost-of-multimodal-inference" rel="noopener noreferrer"&gt;&lt;strong&gt;What vision-language models cost to serve at production scale&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
A single uploaded photo can add more than a thousand input tokens before the model writes a word, and at 500,000 requests a month, that gap is the difference between \$155 on serverless Nemotron Nano 12B VL and \$3,175.20 for a dedicated H100 running 24/7. Walk through the per-request cost math, the roughly 10.2 million-request breakeven, where dedicated wins, and six levers for cutting image-token spend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/speculative-decoding-kv-cache-capacity" rel="noopener noreferrer"&gt;&lt;strong&gt;Speculative decoding's hidden cost: the KV cache capacity you give up, and where throughput turns negative&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
On a 141 GB H200 serving Qwen3-14B with vLLM, a separate Qwen3-0.6B draft model consumed about 43.8 percent of baseline batch slots, and even n-gram speculation, predicted to cost nothing, measured a 2.8 percent capacity tax. See where each method's throughput crosses below baseline as concurrency rises, and get the config.json arithmetic to predict a draft model's KV cost before spending GPU hours.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/conceptual-articles/deepseek-v4-1-flash-cache-reliability" rel="noopener noreferrer"&gt;&lt;strong&gt;Cache reliability is a pricing term: what I learned measuring DeepSeek-V4.1-Flash on DigitalOcean Serverless Inference&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
DeepSeek-V4.1-Flash has the deepest cache discount in the Serverless Inference catalog at \$0.006 per million cached tokens, yet across 844 API calls it hit the cache on only 78.6% of warm turns, and with a miss priced at 50x a hit, it cost 2.2x what GLM-5.3-Flash did for the same 15-turn, 200K-token sessions. Discover how DigitalOcean's 64-token-block prefix cache works, how to log your own hit rate from the usage object, and why reasoning_effort: max cost up to 1.88x more without improving accuracy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/deepseek-v41-flash-ced-article" rel="noopener noreferrer"&gt;&lt;strong&gt;Why DeepSeek-V4.1-Flash splits reading from writing&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
DeepSeek-V4.1-Flash's Causal Encoder-Decoder splits a 40-layer model into a 20-layer encoder that runs prefill at 8B active parameters and a full stack that decodes at 16B, shrinking the global KV cache to about 890 bytes per token, roughly a quarter of V4-Flash's. Learn why that asymmetry, not the 74.2 versus 62.7 DeepSWE score against V4-Pro, is what lowers the bill for read-heavy coding agents.&lt;/p&gt;




&lt;h3&gt;
  
  
  Product updates
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/blog/managed-agents-public-preview" rel="noopener noreferrer"&gt;&lt;strong&gt;Introducing DigitalOcean Managed Agents, now in Public Preview&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
AI agents are ready to take on more, and we built the infrastructure to match. &lt;a href="https://www.digitalocean.com/products/managed-agents" rel="noopener noreferrer"&gt;DigitalOcean Managed Agents&lt;/a&gt; brings together &lt;a href="https://cloud.digitalocean.com/managed-agents/harness-runtime?i=e0fda3" rel="noopener noreferrer"&gt;Harness Runtime&lt;/a&gt;, a purpose-built runtime for running agent sessions at scale, and &lt;a href="https://cloud.digitalocean.com/managed-agents/action-gateway/getting-started?i=e0fda3" rel="noopener noreferrer"&gt;Action Gateway&lt;/a&gt;, governed access to the tools agents need to get real work done, all in one platform.&lt;/p&gt;

&lt;p&gt;Deploy your preferred agent harness, Claude Code, Codex CLI, OpenCode, and more, or bring your own, and connect to 16,000+ tools across 500+ providers through a single managed endpoint. Sessions are ready in under a second, resume in about 300 milliseconds with full context intact, and you only pay for the compute you actually use.&lt;/p&gt;

&lt;p&gt;Whether you're automating support workflows, refactoring code across repositories, or building the next agent-powered product, Managed Agents gives you the infrastructure to do it, without building it yourself. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/blog/microvms-for-agents" rel="noopener noreferrer"&gt;&lt;strong&gt;DigitalOcean MicroVMs now in private preview&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Isolated, Firecracker-based VMs that pause when idle and resume with state intact, built for agent workloads that run in bursts. The same layer that powers Managed Agents is now available directly to teams building their own agent platforms, sandboxes, and short-lived jobs. &lt;/p&gt;

</description>
      <category>ai</category>
      <category>startup</category>
      <category>infrastructure</category>
      <category>developers</category>
    </item>
    <item>
      <title>What is disaggregated prefill and decode in LLM inference?</title>
      <dc:creator>DigitalOcean</dc:creator>
      <pubDate>Tue, 06 Oct 2026 18:03:00 +0000</pubDate>
      <link>https://dev.to/digitalocean/what-is-disaggregated-prefill-and-decode-in-llm-inference-4m0n</link>
      <guid>https://dev.to/digitalocean/what-is-disaggregated-prefill-and-decode-in-llm-inference-4m0n</guid>
      <description>&lt;p&gt;What is disaggregated prefill and decode in LLM inference?&lt;/p&gt;

&lt;p&gt;Prefill is compute-bound, decode is memory-bound. Learn why colocating them hurts TTFT and ITL, and when disaggregated serving pays off.&lt;/p&gt;

&lt;p&gt;Every LLM request runs through two phases with effectively opposite hardware profiles. Understanding the split explains most of the latency and cost behavior you see in production, and why disaggregated prefill and decode has become a standard serving pattern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prefill is compute-bound and sets TTFT; decode is memory-bandwidth-bound and sets ITL/TPOT.
&lt;/li&gt;
&lt;li&gt;Running both on the same GPUs creates prefill/decode interference, visible as TTFT spikes and ITL jitter.
&lt;/li&gt;
&lt;li&gt;Chunked prefill and continuous batching reduce interference; disaggregating the phases onto separate pools removes it, at the cost of a KV cache transfer.
&lt;/li&gt;
&lt;li&gt;Disaggregation is worth it for long prompts, high concurrency, and strict streaming SLOs. A managed option like DigitalOcean Serverless Inference gives you it without the setup; for small self-hosted deployments, a well-tuned single pool on a &lt;a href="https://www.digitalocean.com/products/gpu-droplets" rel="noopener noreferrer"&gt;GPU Droplet&lt;/a&gt; running vLLM is often enough.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The two phases of LLM inference
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Prefill&lt;/strong&gt; processes the entire prompt in one forward pass and builds the KV cache, the attention state every later token reads from. It is compute-bound: arithmetic intensity is high and the GPU spends its time doing math, not waiting on memory. Prefill governs time to first token (TTFT), and its attention cost grows quadratically with prompt length.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decode&lt;/strong&gt; generates output one token at a time. Each step reloads the model weights and the growing KV cache from HBM to produce a single token, so it is memory-bandwidth-bound. Decode governs inter-token latency (ITL) and time per output token (TPOT). A GPU with higher memory bandwidth streams tokens faster even if its FLOPs are unchanged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why colocating prefill and decode causes latency problems
&lt;/h2&gt;

&lt;p&gt;Most serving engines batch prefill and decode on the same GPUs. That is where the interference shows up: a long prompt's prefill can monopolize compute while dozens of in-flight decode requests stall, and users see ITL jitter or a TTFT spike. The two phases also want different batch sizes and parallelism strategies, but colocated they must share one configuration. &lt;/p&gt;

&lt;p&gt;Chunked prefill and continuous batching soften this by interleaving prompt chunks with decode steps, which is why our &lt;a href="https://www.digitalocean.com/blog/llm-inference-tradeoffs" rel="noopener noreferrer"&gt;inference trilemma&lt;/a&gt; guide recommends them for latency-sensitive deployments.&lt;/p&gt;

&lt;h2&gt;
  
  
  What disaggregation changes
&lt;/h2&gt;

&lt;p&gt;Disaggregated serving, formalized in the &lt;a href="https://arxiv.org/abs/2401.09670" rel="noopener noreferrer"&gt;DistServe paper&lt;/a&gt;, runs prefill and decode on separate GPU pools. A prefill worker computes the KV cache, ships it over a fast interconnect (RDMA, RoCE, or a transfer library like NIXL or LMCache) to a decode worker, and the decode pool streams tokens without prefill interference. Because each pool is sized and tuned independently, you can hit TTFT and ITL targets at the same time rather than trading one for the other. The cost is added complexity plus a KV transfer step; that transfer can land on second-token latency rather than TTFT depending on how orchestration is done.&lt;/p&gt;

&lt;p&gt;This is the architecture DigitalOcean already runs in production: &lt;a href="https://www.digitalocean.com/blog/reduce-llm-inference-costs-prefix-caching" rel="noopener noreferrer"&gt;Serverless Inference&lt;/a&gt; uses disaggregated serving over a RoCE network, paired with prefix-aware routing so shared system prompts skip redundant prefill entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  References &amp;amp; further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2401.09670" rel="noopener noreferrer"&gt;DistServe: Disaggregating Prefill and Decoding for Goodput-optimized LLM Serving&lt;/a&gt;: the primary source for the pattern, worth reading before you build.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.digitalocean.com/blog/llm-inference-benchmarking" rel="noopener noreferrer"&gt;LLM inference benchmarking: measure what matters&lt;/a&gt;: a clear walkthrough of TTFT, TPOT, ITL, and how each maps to prefill or decode.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.digitalocean.com/blog/llm-inference-tradeoffs" rel="noopener noreferrer"&gt;The LLM inference trilemma&lt;/a&gt;: practical tuning advice, including when to reach for chunked prefill.
&lt;/li&gt;
&lt;li&gt;Learn more about &lt;a href="https://www.digitalocean.com/community/tutorials/debugging-p99-ttft-llm-inference" rel="noopener noreferrer"&gt;debugging p99 TTFT&lt;/a&gt; and &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-deploy-nvidia-dynamo-for-llm-inference" rel="noopener noreferrer"&gt;deploying NVIDIA Dynamo on GPU Droplets&lt;/a&gt;, a framework built around disaggregated serving.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.digitalocean.com/products/gpu-droplets" rel="noopener noreferrer"&gt;GPU Droplets&lt;/a&gt;: current hardware and regions, worth checking directly since availability changes.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>developers</category>
      <category>startup</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>How to route LLM requests by cost vs. latency</title>
      <dc:creator>DigitalOcean</dc:creator>
      <pubDate>Fri, 02 Oct 2026 18:33:17 +0000</pubDate>
      <link>https://dev.to/digitalocean/how-to-route-llm-requests-by-cost-vs-latency-463j</link>
      <guid>https://dev.to/digitalocean/how-to-route-llm-requests-by-cost-vs-latency-463j</guid>
      <description>&lt;p&gt;Routing LLM requests by cost and latency means sending each request to the cheapest or fastest model that still meets the quality bar, rather than hardcoding a single model for everything. Production traffic isn't uniform: routine lookups, complex troubleshooting, and background jobs have different cost and latency requirements, even within a single app. &lt;/p&gt;

&lt;p&gt;Using an inference router like DigitalOcean Inference Router involves defining request categories, assigning each a selection policy (cost, latency, or a benchmarked best fit), and setting fallback models so an unavailable model doesn't break the request. Cost is the price per token (which can vary by up to 100x across a model catalog); latency is mainly the time to first token (TTFT). The two don't move together, so route per task rather than using a single blended score.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routing is a per-workload policy, not a search for "the best model."
&lt;/li&gt;
&lt;li&gt;Cost and latency usually need separate, explicit priorities.
&lt;/li&gt;
&lt;li&gt;Fallback and cache-aware routing protect the savings that routing is meant to deliver.
&lt;/li&gt;
&lt;li&gt;The DigitalOcean Inference Router implements this as configuration, not custom infrastructure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  LLM routing strategies
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static rules&lt;/strong&gt;: Hardcode model per request type. Simple, but brittle.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy-based routing&lt;/strong&gt;: A model pool per task with a cost/latency/optimal policy. Most production systems land here.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic routing&lt;/strong&gt;: A classifier infers the task and policy automatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Routing LLM requests: A quick decision framework
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workload&lt;/th&gt;
&lt;th&gt;Priority&lt;/th&gt;
&lt;th&gt;Policy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Real-time chat&lt;/td&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;Speed-optimized (TTFT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Routine lookups&lt;/td&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Cost-optimized&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex reasoning&lt;/td&gt;
&lt;td&gt;Quality&lt;/td&gt;
&lt;td&gt;Benchmarked "optimal"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Batch/background&lt;/td&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Cost-optimized&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Fallback models&lt;/strong&gt; keep requests completing when the preferred model is down or rate-limited. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache-aware routing&lt;/strong&gt; matters too: switching models to save a fraction of a cent can break a cached prompt and cost more overall.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the DigitalOcean Inference Router routes LLM requests
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.digitalocean.com/products/inference/how-to/use-inference-router/" rel="noopener noreferrer"&gt;Inference Router&lt;/a&gt; tasks pair a model pool with a selection policy: preset tasks default to a benchmarked &lt;strong&gt;Optimal&lt;/strong&gt; policy; custom tasks choose &lt;strong&gt;Cost Efficiency&lt;/strong&gt;, &lt;strong&gt;Speed Optimization&lt;/strong&gt; (TTFT), or &lt;strong&gt;Manual Ranking&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Fallback models handle unmatched traffic. &lt;code&gt;X-Model-Affinity&lt;/code&gt; preserves cache reuse, and &lt;code&gt;X-Routing-Max-Switch-Spend-Pct&lt;/code&gt; (default 20%) caps the cost of switching mid-session. &lt;/p&gt;

&lt;p&gt;It's a drop-in change. Set &lt;code&gt;"model": "router:your-router-name"&lt;/code&gt;. Routing decisions typically resolve in about 200ms, billed at the serving model's &lt;a href="https://docs.digitalocean.com/products/inference/details/pricing/" rel="noopener noreferrer"&gt;standard rate&lt;/a&gt; with no separate router charge during public preview.&lt;/p&gt;

&lt;h2&gt;
  
  
  LLM routing FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is LLM routing?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
LLM routing is the practice of directing each request to the model best suited to it—by cost, latency, or task fit—instead of sending every request through one model regardless of what it needs. The DigitalOcean Inference Router implements this as a managed feature, so teams get task-aware routing and fallback handling without building it themselves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you &lt;a href="https://www.digitalocean.com/resources/articles/llm-cost-calculation-guide" rel="noopener noreferrer"&gt;model cost-per-token&lt;/a&gt; for LLM inference?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Multiply input tokens by the model's input rate and output tokens by its output rate, then sum the two, since the rates are usually very different. Because rates vary widely across a model catalog, this is best tracked per task rather than as one blended number. The DigitalOcean Inference Router reports token usage and cost-relevant metrics per model and per task in its Analyze view.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What metrics matter for LLM inference observability?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Time to first token (TTFT), time per output token (TPOT), and inter-token latency (ITL) are the core metrics for judging responsiveness. A latency-optimized routing policy should be measured against these, not just overall request time. The DigitalOcean Inference Router uses TTFT specifically as the basis for its Speed Optimization selection policy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What causes cold start latency in GPU inference, and how do you avoid it?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Cold starts happen when a model has to load onto available GPU capacity before it can serve a request, rather than running on an already-warm instance. Pooled serverless capacity and routing policies that keep related traffic on one model reduce how often this happens. The DigitalOcean Inference Router uses model affinity to keep a session's requests on the same warm model, rather than triggering repeated cold starts across models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I route by both cost and latency at the same time?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes—typically by defining separate tasks or policies for different request types rather than one blended score. For example, cost-first for background work and latency-first for real-time chat. The DigitalOcean Inference Router supports this directly. Each task in a router can have its own model pool and its own Cost Efficiency, Speed Optimization, or Manual Ranking policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  References &amp;amp; further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.digitalocean.com/products/inference/how-to/use-inference-router/" rel="noopener noreferrer"&gt;How to use Inference Router&lt;/a&gt;: The full documentation on tasks, selection policies, fallback models, and the cache-aware router referenced throughout this piece. Worth reading directly before you configure a router for production traffic.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.digitalocean.com/products/inference/details/pricing/" rel="noopener noreferrer"&gt;Inference pricing&lt;/a&gt;: Current per-model Serverless Inference rates, since routing decisions are only as good as the pricing data behind them.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.digitalocean.com/blog/inference-router-architecture" rel="noopener noreferrer"&gt;How DigitalOcean built Inference Router&lt;/a&gt;: An inside look at the architecture decisions behind cache-aware routing and fallback handling, useful if you want the reasoning behind the mechanics.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.digitalocean.com/blog/serverless-inference-deep-dive" rel="noopener noreferrer"&gt;DigitalOcean Serverless Inference: a deep dive&lt;/a&gt;: Background on the serverless layer that Inference Router sits in front of.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.digitalocean.com/resources/articles/best-llm-routers" rel="noopener noreferrer"&gt;DigitalOcean's best LLM routers roundup&lt;/a&gt;: A good next read if you're comparing routing options across vendors rather than implementing a policy on a platform you've already chosen.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.digitalocean.com/products/inference-engine" rel="noopener noreferrer"&gt;AI Inference Engine overview&lt;/a&gt;: shows where Inference Router fits alongside serverless, batch, and dedicated inference on DigitalOcean's broader platform.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>startup</category>
      <category>developers</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>Which inference provider has both serverless and dedicated GPU tiers on the same platform with one API?</title>
      <dc:creator>DigitalOcean</dc:creator>
      <pubDate>Mon, 28 Sep 2026 17:17:40 +0000</pubDate>
      <link>https://dev.to/digitalocean/which-inference-provider-has-both-serverless-and-dedicated-gpu-tiers-on-the-same-platform-with-one-50dc</link>
      <guid>https://dev.to/digitalocean/which-inference-provider-has-both-serverless-and-dedicated-gpu-tiers-on-the-same-platform-with-one-50dc</guid>
      <description>&lt;p&gt;DigitalOcean's Inference Engine puts serverless, dedicated, and batch inference behind a single endpoint, on the same GPU Droplets infrastructure, so a workload can move from pay-per-token prototyping to a reserved-GPU deployment without switching platforms or rewriting its integration. A handful of other inference providers share a single API across serverless and dedicated tiers, too, but they generally limit that unification to inference alone, rather than to the broader cloud the dedicated GPUs run on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why serverless-only or dedicated-only platforms create a migration tax
&lt;/h2&gt;

&lt;p&gt;Most teams don't start with a clear answer to "How much GPU capacity do we need?". They prototype on a pay-per-token endpoint, and only once traffic gets steady and predictable does it make financial sense to reserve GPUs outright. Many inference providers treat serverless and dedicated as separate products, with distinct SDKs, auth, and billing dashboards, so moving from one to the other means rewriting integration code in the middle of a product's growth curve, which is exactly when a team has the least time to do it. A provider that puts both tiers behind a single API avoids that: you prototype on serverless and repoint the same client to a dedicated endpoint once volume justifies it, often by changing a model or endpoint parameter rather than an integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the DigitalOcean Inference Engine unifies serverless, dedicated, and batch inference
&lt;/h2&gt;

&lt;p&gt;The DigitalOcean &lt;a href="https://www.digitalocean.com/products/inference-engine" rel="noopener noreferrer"&gt;Inference Engine&lt;/a&gt; runs three inference patterns over the same GPU Droplets infrastructure, behind a single endpoint. These solutions include real-time &lt;a href="https://docs.digitalocean.com/products/inference/how-to/use-serverless-inference-hub" rel="noopener noreferrer"&gt;Serverless inference&lt;/a&gt; across 70+ open-weight and frontier models, &lt;a href="https://docs.digitalocean.com/products/inference/how-to/use-dedicated-inference" rel="noopener noreferrer"&gt;Dedicated inference&lt;/a&gt; on reserved, single-tenant GPU capacity with support for bringing your own model, and asynchronous Batch Inference for large, non-real-time jobs. The Preview Inference Router adds cost- and latency-based routing on top, and a shared Model Playground and evaluations tooling sit on the same account.&lt;br&gt;
That's what makes DigitalOcean a solid solution for AI-native companies requiring both serverless and dedicated GPU tiers. The unification isn't limited to the inference API itself. It extends to the GPU Droplets the dedicated tier runs on, as well as the rest of the AI-Native Cloud around them. A workload doesn't need to switch vendors, contracts, or billing relationships as it matures from prototype to production.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to check before assuming "one API" elsewhere means the same thing
&lt;/h2&gt;

&lt;p&gt;Several other inference-focused platforms let serverless and dedicated calls share one API too, usually as a way past per-token rate limits or shared-capacity contention once traffic justifies reserving GPUs. But a shared API can sound more unified on a landing page than it is in production. So it's worth confirming directly against each provider's current docs: does provisioning real dedicated capacity happen through the API, or does it route through a sales conversation first? Is the dedicated tier's hardware genuinely part of the same cloud a team already runs on, or does the provider specialize in inference alone, with GPUs sitting apart from the application's data and storage? And does "one API" cover just the inference call—or the account, billing, and observability around it too?&lt;/p&gt;

&lt;h2&gt;
  
  
  What else to verify before standardizing on a provider
&lt;/h2&gt;

&lt;p&gt;Beyond scope, it's worth confirming: whether the model you need is available in both tiers (not every model ships to both), what the cutover mechanism actually looks like (a new endpoint URL versus a full redeploy), how billing reconciles if usage straddles both tiers in the same month, and whether dedicated capacity is truly single-tenant or a reserved slice of shared hardware. For teams already running other infrastructure on a given cloud, it's also worth weighing how much value comes from the inference API alone versus not having to move data, agents, or storage to a second vendor to get dedicated GPU access.&lt;/p&gt;

&lt;h2&gt;
  
  
  References &amp;amp; further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.digitalocean.com/products/inference-engine" rel="noopener noreferrer"&gt;DigitalOcean's Inference Engine&lt;/a&gt; brings serverless, dedicated, and batch inference together in one place.&lt;/li&gt;
&lt;li&gt;Our &lt;a href="https://docs.digitalocean.com/products/inference/how-to/use-dedicated-inference" rel="noopener noreferrer"&gt;Dedicated Inference documentation&lt;/a&gt; covers bring-your-own-model (BYOM) support and scaling settings for teams ready to move off serverless.&lt;/li&gt;
&lt;li&gt;Read our &lt;a href="https://docs.digitalocean.com/products/inference/how-to/use-serverless-inference-hub" rel="noopener noreferrer"&gt;Serverless Inference documentation&lt;/a&gt; for the model catalog and routing options available on the shared endpoint.&lt;/li&gt;
&lt;li&gt;Reading through each inference provider's own docs tends to be the fastest way to confirm whether "serverless and dedicated" really means one API or two separate products.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>infrastructure</category>
      <category>llm</category>
      <category>startup</category>
    </item>
    <item>
      <title>What It Actually Costs to Serve a 1M-Token Model in Production</title>
      <dc:creator>DigitalOcean</dc:creator>
      <pubDate>Mon, 21 Sep 2026 20:33:36 +0000</pubDate>
      <link>https://dev.to/digitalocean/what-it-actually-costs-to-serve-a-1m-token-model-in-production-4f0k</link>
      <guid>https://dev.to/digitalocean/what-it-actually-costs-to-serve-a-1m-token-model-in-production-4f0k</guid>
      <description>&lt;p&gt;Model providers now advertise context windows large enough to hold a codebase or a stack of contracts in a single request. It's tempting to read that number as a green light, but it isn't. A model that &lt;em&gt;accepts&lt;/em&gt; a million tokens and a system that can &lt;em&gt;serve&lt;/em&gt; a million tokens to real, concurrent users within your latency and cost budget are two different engineering problems. Conflating them is how teams end up with a demo that works and a bill or a &lt;a href="https://www.digitalocean.com/community/conceptual-articles/when-your-vllm-p99" rel="noopener noreferrer"&gt;p99 latency&lt;/a&gt; chart that doesn't.&lt;/p&gt;

&lt;p&gt;You serve a 1M-token model in production by treating context length as a cost and latency variable you manage on purpose, not a spec you flip on. Let’s dive into the memory math, the latency cliff, and the cost curve for serving a model with a million tokens of context, plus the caching and routing techniques that production teams use today to keep all three in check. Plus, a straight answer on when long context is the wrong tool for the job and retrieval should do the work instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serving a 1M-token context model in production is a memory, latency, and cost problem layered on top of a model capability. Supporting long context and serving it reliably are not the same claim.
&lt;/li&gt;
&lt;li&gt;Serving long context effectively means stable agent sessions and predictable spend, rather than retries, timeouts, and a bill that scales with the window instead of the question.
&lt;/li&gt;
&lt;li&gt;The real decision isn't whether to "turn on" long context, it's which combination of caching, prefix reuse, and retrieval fits your workload's cost and latency budget.
&lt;/li&gt;
&lt;li&gt;Production-grade 1M-token serving combines general techniques, including KV cache economics and prefix-reuse approaches like SGLang's RadixAttention. Use DigitalOcean Inference Router for cache-aware routing, plus retrieval-augmented generation (RAG) as the alternative and complement.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What "serving" a long-context model actually means
&lt;/h2&gt;

&lt;p&gt;Context is everything you send to a model in a single request, measured in tokens: the prompt, the documents, the conversation history. A 128K-token window is roughly a novel's worth of text, and frontier closed models now advertise up to 1M tokens (roughly, ten novels). That number describes what the model can read in isolation, but not what happens to time-to-first-token, batch size, or your GPU bill once dozens of those requests land on the same cluster at once.&lt;/p&gt;

&lt;p&gt;Support is a model capability, and performance is a serving question. The two come apart the moment real traffic shows up.&lt;/p&gt;

&lt;p&gt;Two mechanics decide whether a long-context request is slow to start or slow to finish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.digitalocean.com/community/tutorials/prefill-decode-disaggregation" rel="noopener noreferrer"&gt;Prefill&lt;/a&gt;: The compute-bound pass where the model reads your entire input before writing anything.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.digitalocean.com/community/conceptual-articles/how-kv-caching-slashes-llm-inference-costs-at-scale" rel="noopener noreferrer"&gt;KV cache&lt;/a&gt;: The memory that stores each token's key and value vectors so the model doesn't reread the input on every step.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dig in to how &lt;a href="https://www.digitalocean.com/community/tutorials/prefill-decode-disaggregation" rel="noopener noreferrer"&gt;prefill/decode disaggregation&lt;/a&gt; works: the two-phase split behind every long-context serving decision below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why its worth optimizing for long-context
&lt;/h2&gt;

&lt;p&gt;Getting long-context serving right pays off in multiple ways.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Here's what's actually at stake once you're running this in production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stable agent and document workloads&lt;/strong&gt;: A correctly cached long-context session makes it possible for a coding agent or a multi-turn document review to hold state across dozens of turns without resending the same 100K-token context on every message.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Costs you can forecast&lt;/strong&gt;: Once you know whether traffic is cache-friendly or retrieval-shaped, it's easier to accurately predict spend.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No silent accuracy loss&lt;/strong&gt;: Long-context serving done well accounts for the fact that models answer less reliably as input grows. This happens by routing precision lookups to retrieval instead of trusting long-context recall, and by testing accuracy at the context lengths you'll actually run rather than assuming a bigger model or window is automatically more reliable.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency you can put in an SLA&lt;/strong&gt;: Understanding the prefill/decode split lets you set a time-to-first-token target you can actually hit, instead of promising an interactive response time a long-context request can't deliver.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Room to scale without a rebuild&lt;/strong&gt;: Architectures built around caching and routing from the start absorb growth in context length and concurrent users without the rewrite that a "just resend everything" approach eventually forces.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What to evaluate before you commit to a long-context approach
&lt;/h2&gt;

&lt;p&gt;Long-context serving isn't a single decision, but rather a set of infrastructure and architecture choices considered together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache-awareness&lt;/strong&gt;: Check whether the serving layer reuses the KV cache across requests that share a common prefix, rather than recomputing it each time. The DigitalOcean &lt;a href="https://www.digitalocean.com/products/inference-engine" rel="noopener noreferrer"&gt;Inference Router&lt;/a&gt;, for example, pins a session to the same model so that a warm cache isn't discarded mid-task when switching to a different, cheaper model.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batching under long-context load&lt;/strong&gt;: Confirm the system maintains healthy batch sizes as the average context length grows, using techniques like chunked prefill and paged memory allocation, rather than letting a single long request starve everything queued behind it.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation from noisy neighbors&lt;/strong&gt;: Ask whether long-context and interactive traffic run in separate pools. &lt;a href="https://docs.digitalocean.com/products/inference/how-to/use-dedicated-inference/" rel="noopener noreferrer"&gt;Dedicated Inference&lt;/a&gt; on DigitalOcean exists specifically so a large document-processing job doesn't blow up latency for interactive users on the same infrastructure.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pricing that reflects the real cost curve&lt;/strong&gt;: Look for tiered, per-token pricing that acknowledges long-context requests cost more proportionally, plus a prompt-caching rate that's meaningfully cheaper than a full rewrite.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability into cache health, not just request counts&lt;/strong&gt;: Make sure you can see KV-cache occupancy, eviction, and preemption counts—not just average latency—since that's what actually explains a p99 problem caused by long-context traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resend, cache, retrieve, or both: what each costs per session
&lt;/h2&gt;

&lt;p&gt;The cleanest way to understand the cost of each approach is to price a full session rather than a single token.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;These examples take a 10-turn agent conversation carrying a stable 128K-token context—a codebase or a document set—where each turn adds a short question and gets a short answer:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Cost per 10-turn session (128K context)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Resend the full context every turn&lt;/td&gt;
&lt;td&gt;Short, one-off sessions where simplicity matters more than cost&lt;/td&gt;
&lt;td&gt;Full context re-sent as input tokens on every turn&lt;/td&gt;
&lt;td&gt;$3.93&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache the context; reuse it&lt;/td&gt;
&lt;td&gt;Stable, reused context — a codebase, a document set, a long agent session&lt;/td&gt;
&lt;td&gt;Prefill cost paid once; later turns reuse the cached KV state&lt;/td&gt;
&lt;td&gt;$0.95&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retrieve a relevant slice (RAG)&lt;/td&gt;
&lt;td&gt;Large or changing corpora where each query touches a small fraction of the data&lt;/td&gt;
&lt;td&gt;Only the relevant slice enters context; the rest of the corpus stays out&lt;/td&gt;
&lt;td&gt;$0.33&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Figures per DigitalOcean's &lt;a href="https://www.digitalocean.com/community/tutorials/long-context-llm-serving-tradeoffs-2026" rel="noopener noreferrer"&gt;long-context serving tradeoffs analysis&lt;/a&gt;, priced at Claude Sonnet's published rates ($3.00/M input tokens, $3.75/M to write the cache, $0.30/M to read it).&lt;/p&gt;

&lt;p&gt;Caching cuts the bill roughly 4x against resending; retrieval cuts it roughly 12x. At thousands of sessions a day, that architecture choice matters more than any provider's per-token rate.&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  The four tradeoffs that decide whether long-context works in production
&lt;/h2&gt;

&lt;p&gt;A 1M-token context window is a spec, not a guarantee that serving it will work. Memory, latency, throughput, and accuracy each break in their own way as context grows, and "supports 1M tokens" and "serves 1M tokens well" can be very different claims.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory: the KV cache doesn't scale the way people expect
&lt;/h3&gt;

&lt;p&gt;For every token a model reads, it stores a key and a value vector so it doesn't have to reprocess the input on each new token. That cache grows in direct proportion to context length: &lt;a href="https://www.digitalocean.com/community/tutorials/long-context-inference-production-cost" rel="noopener noreferrer"&gt;the math&lt;/a&gt; works out to roughly 43GB for a single 128K-token request on a 70-billion-parameter model in BF16—close to the model's own memory footprint. Push to a million tokens, and the cache alone exceeds what a single high-end GPU holds, before the model's own weights are even loaded.&lt;/p&gt;

&lt;h3&gt;
  
  
  Latency: why time-to-first-token is the number that breaks
&lt;/h3&gt;

&lt;p&gt;Attention compares every token against every other token, so compute grows with the square of input length: double the context, quadruple the work. That happens entirely during prefill, before a user sees a single word, which is why time-to-first-token ranges from milliseconds with short context to multiple seconds with long context. It also means one long request can hold a GPU for seconds, quietly degrading p95 and p99 latency for every short, unrelated request queued behind it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Throughput: the bandwidth ceiling no amount of compute fixes
&lt;/h3&gt;

&lt;p&gt;Generating each output token requires reading the entire KV cache from GPU memory, and the read speed is limited by hardware bandwidth. Double the context, double the cache, and tokens-per-second roughly halves, with a limit that has nothing to do with how much compute is sitting idle. A cluster can appear underutilized on a FLOPS dashboard and still serve long-context requests slowly because the bottleneck has shifted to the memory bus.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accuracy: why a bigger window doesn't guarantee a better answer
&lt;/h3&gt;

&lt;p&gt;Longer context doesn't reliably mean a better answer. A 2026 measurement study found that accuracy at long context lengths doesn't track model size — a smaller model sometimes outperformed a larger sibling — and that a wrong answer just becomes a retry, which turns an accuracy problem into a latency problem measured in total time-to-correct-answer. Production systems that route by expected accuracy at a given context length, not just by cost, cut that wasted retry time substantially.&lt;/p&gt;

&lt;h2&gt;
  
  
  How production teams are actually solving the long-context problem today
&lt;/h2&gt;

&lt;p&gt;Successful teams aren't fighting the KV cache, they're making it reusable. &lt;a href="https://www.digitalocean.com/resources/articles/what-is-sglang" rel="noopener noreferrer"&gt;SGLang&lt;/a&gt;'s RadixAttention implements prefix caching alongside continuous batching, so a repeated prompt prefix (i.e. a system prompt, a shared reference document, a stable set of few-shot examples) gets computed once and reused across requests instead of recomputed on every call. That keeps throughput comparatively stable even as context length grows into the millions of tokens, which is exactly the workload where naive serving falls apart first.&lt;/p&gt;

&lt;p&gt;You can run this pattern yourself on &lt;a href="https://www.digitalocean.com/products/gpu-droplets" rel="noopener noreferrer"&gt;DigitalOcean GPU Droplets&lt;/a&gt;, or skip the setup work with the &lt;a href="https://www.digitalocean.com/resources/articles/what-is-sglang" rel="noopener noreferrer"&gt;SGLang 1-Click Marketplace app&lt;/a&gt;, which handles the underlying infrastructure for you.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F20hh5y3klu0mii00c2pp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F20hh5y3klu0mii00c2pp.png" alt="SGLang on DigitalOcean" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DigitalOcean's Inference Router adds cache-aware routing on top of that. It keeps a session pinned to the same model, so a warm KV cache doesn't get discarded mid-task by a switch to a different model chosen for cost reasons.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;If you're self-hosting long-context serving on GPU Droplets rather than going through a managed router, three additional levers matter:&amp;nbsp;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chunked prefill, which breaks a large prefill pass into pieces so it doesn't stall the rest of the batch.&amp;nbsp;
&lt;/li&gt;
&lt;li&gt;Tuning max batch size and max batched-token limits for your actual mix of context lengths.
&lt;/li&gt;
&lt;li&gt;Keeping long-context traffic in a separate pool from interactive traffic so one doesn't degrade the other.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When time-to-first-token degrades as context grows, &lt;a href="https://www.digitalocean.com/community/tutorials/debugging-p99-ttft-llm-inference" rel="noopener noreferrer"&gt;DigitalOcean's inference-debugging guidance&lt;/a&gt; points to KV-cache pressure—not the scheduler—as the usual culprit. This is why watching KV-cache occupancy, eviction, and preemption counts diagnoses the problem faster than staring at a scheduler queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do you even need long context? Choosing between caching, retrieval, or using both
&lt;/h2&gt;

&lt;p&gt;If a model accepts a million tokens, it's fair to ask why you'd also use a &lt;a href="https://www.digitalocean.com/community/conceptual-articles/a-dive-into-vector-databases" rel="noopener noreferrer"&gt;vector database&lt;/a&gt;, a chunking pipeline, and a retrieval step. The answer is that the price of skipping retrieval includes the quadratic prefill cost, the multi-second time-to-first-token, and the tiered per-token pricing. They’re all paid on every request—even when the answer only needed to use three paragraphs of the input.&lt;/p&gt;

&lt;p&gt;As a practical rule, long context plus caching wins when your working set is stable and reused. For example, many requests against the same document set, or a day-long agent session where the context is the state. RAG wins when your corpus is larger than any context window, changes frequently, or is mostly irrelevant to any single query. Precision lookups favor RAG even when the full corpus would technically fit, since retrieval keeps the model working at the shorter lengths where it's most reliable. Most production systems end up using both: retrieval to decide what enters the context, a long window to hold a generous amount of it, and caching wherever it repeats.&lt;/p&gt;

&lt;h2&gt;
  
  
  Long-context LLM serving FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How do you serve long-context (1M token) models in production?&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Serving a 1M-token model in production means treating context length as a cost and latency variable you manage on purpose, not a spec you flip on, since supporting long context and serving it reliably are not the same claim. It requires managing KV cache memory, the quadratic prefill cost, and the resulting time-to-first-token, then choosing the right mix of caching, prefix reuse, and retrieval for your workload. The DigitalOcean Inference Router applies cache-aware routing to this problem by pinning a session to the same model so a warm KV cache isn't discarded mid-task.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is disaggregated prefill and decode in LLM inference?&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Prefill is the compute-bound pass where the model reads your entire input before writing anything, while decode is the token-by-token generation that follows. Attention compares every token against every other token during prefill, so compute grows with the square of input length, meaning one long request can hold a GPU for seconds and degrade latency for every short request queued behind it. Chunked prefill breaks a large prefill pass into pieces so it doesn't stall the rest of the batch.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What metrics matter for LLM inference observability (TTFT, TPOT, ITL)?&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Time-to-first-token is the number that breaks under long context, ranging from milliseconds with short context to multiple seconds with long context, because it's entirely determined by the prefill pass. Beyond latency averages, observability into KV-cache occupancy, eviction, and preemption counts is what actually explains a p99 problem caused by long-context traffic, not request counts alone. KV-cache pressure, not the scheduler, is the usual culprit when time-to-first-token degrades as context grows.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which inference provider has the best caching to reduce token costs for long autonomous coding sessions?&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Caching the context and reusing it lets a coding agent hold state across dozens of turns without resending the same 100K-token context every message. SGLang's RadixAttention implements this as prefix caching alongside continuous batching, computing a repeated prompt prefix once and reusing it across requests. DigitalOcean supports this pattern on GPU Droplets or through the SGLang 1-Click Marketplace app, and the Inference Router adds cache-aware routing so a warm cache isn't discarded by a mid-task model switch.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you model cost-per-token for LLM inference?&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;The cleanest way to model cost is pricing a full session rather than a single token: resending the full context every turn costs $3.93 for a 10-turn, 128K-context session, caching and reusing that context brings it to $0.95, and retrieving only the relevant slice (RAG) brings it to $0.33. Caching cuts the bill roughly 4x against resending, while retrieval cuts it roughly 12x, a difference that matters more at scale than any provider's per-token rate. DigitalOcean prices around this same curve, with tiered per-token rates that account for long-context requests costing more than proportionally, plus a prompt-caching rate meaningfully cheaper than a full rewrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serve long-context models without managing the cache yourself
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.digitalocean.com/products/inference-engine" rel="noopener noreferrer"&gt;DigitalOcean Inference Engine&lt;/a&gt; prices per token by model, with prompt-caching rates listed right next to the standard rate. That means you can work out what a long-context session costs before you run it, not after the invoice shows up. The Inference Router automatically applies cache-aware routing, pinning a session to the model whose KV cache is already warm rather than discarding it during a mid-task switch.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;That gets you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic model-to-request matching, so cost- or latency-sensitive requests route to the right model without the need for writing the routing logic yourself.
&lt;/li&gt;
&lt;li&gt;Dedicated Inference to isolate long-context, latency-sensitive workloads from noisy-neighbor traffic.
&lt;/li&gt;
&lt;li&gt;Serverless-to-dedicated scaling with no migration step, so a workload that outgrows shared capacity doesn't require re-architecting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://cloud.digitalocean.com/registrations/new" rel="noopener noreferrer"&gt;Get started with DigitalOcean's Inference Engine&lt;/a&gt; →&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/customers/hippocratic-ai" rel="noopener noreferrer"&gt;Hippocratic AI&lt;/a&gt; cut prefill latency 2x on long-context clinical sessions running production inference on DigitalOcean's cache-aware routing.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=WeAAISnnNVA" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=WeAAISnnNVA&lt;/a&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;These customer-reported results reflect Hippocratic AI’s methodology, workload, configuration, and measurement period and may not be representative of results in other environments. Results in customer environments may vary depending on configuration, implementation, and usage. Results and/or savings are not guaranteed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Any references to third-party companies, trademarks, or logos in this document are for informational purposes only and do not imply any affiliation with, sponsorship by, or endorsement of those third parties.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>infrastructure</category>
      <category>llm</category>
      <category>developers</category>
    </item>
    <item>
      <title>AI token billing continues to cause sticker shock</title>
      <dc:creator>DigitalOcean</dc:creator>
      <pubDate>Fri, 18 Sep 2026 16:25:40 +0000</pubDate>
      <link>https://dev.to/digitalocean/ai-token-billing-continues-to-cause-sticker-shock-4a21</link>
      <guid>https://dev.to/digitalocean/ai-token-billing-continues-to-cause-sticker-shock-4a21</guid>
      <description>&lt;h3&gt;
  
  
  Tech talk: are there inference providers that are transparent about token usage?&amp;nbsp;
&lt;/h3&gt;

&lt;p&gt;A top pain point for companies using AI is the discrepancy between expected and actual invoice rates. Particularly when it comes to tokens. The increase in AI usage and tokenmaxxing has created a paradox where a provider knows exactly how many tokens it generated on your behalf, yet you find out only after the fact. It's become a real cost problem when using reasoning models. Internal step-by-step reasoning counts as billed output, but it's invisible by design. The providers willing to open up their token accounting now are betting that transparency will become table stakes before their competitors catch up.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;The 2025 study, “&lt;a href="https://arxiv.org/html/2508.00912v1" rel="noopener noreferrer"&gt;Predictive Auditing of Hidden Tokens in LLM APIs via Reasoning Length Estimation&lt;/a&gt;,” estimated that hidden reasoning tokens can account for over 90% of a model's total token spend on complex tasks. A short, simple-looking answer can hide 10,000+ reasoning tokens, but the only confirmation of their use is the bill.&lt;/p&gt;

&lt;p&gt;This trend in billing surprises has rightfully drawn industry attention. Especially with token usage projected to grow 24x to 120 quadrillion tokens per month by 2030, according to &lt;a href="https://www.goldmansachs.com/insights/articles/ai-agents-forecast-to-boost-tech-cash-flow-as-usage-soars" rel="noopener noreferrer"&gt;research from Goldman Sachs&lt;/a&gt;. Developers have started noticing the gap between what usage dashboards imply and what invoices actually charge, and the industry's response is arriving on two tracks.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;First, standards bodies are getting involved. The Linux Foundation's proposed &lt;a href="https://www.digitalocean.com/blog/inference-router-architecture" rel="noopener noreferrer"&gt;Tokenomics Foundation&lt;/a&gt; wants open, vendor-neutral measurement standards so token accounting isn't just whatever a provider's internal dashboard says it is.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Second, providers like Groq and Cerebras are sharing flat per-token pricing. And the newly launched DigitalOcean &lt;a href="https://www.digitalocean.com/blog/inference-router-architecture" rel="noopener noreferrer"&gt;Inference Router&lt;/a&gt; helps your team route tasks to the most cost-effective or optimal model, providing budget control based on your priorities for specific AI tasks.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Thanks to rapidly scaling AI adoption, developers know these costs aren’t a simple line item to ignore. When evaluating inference options, knowing exactly how your tokens are used and what that can mean for overall billing is essential.&amp;nbsp;&lt;/p&gt;




&lt;h3&gt;
  
  
  Event calendar&amp;nbsp;
&lt;/h3&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/open-intelligence-summit" rel="noopener noreferrer"&gt;&lt;strong&gt;Open Intelligence Summit by DigitalOcean&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The argument is no longer “Is open source AI cheaper?” It’s now “Who owns intelligence?” A movement is forming around open intelligence and generating the belief that the intelligence powering our AI products and companies should be more open, portable, and controllable.&lt;/p&gt;

&lt;p&gt;Join DigitalOcean, RadixArk, Inferact, and more for deep dives, demos, and discussions about the technologies that keep intelligence portable, interoperable, and in the hands of builders. The two-day event runs at The Midway in San Francisco from October 12-13th.&amp;nbsp;&lt;/p&gt;




&lt;h3&gt;
  
  
  Industry news&amp;nbsp;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Coding agents are earning real trust in production codebases&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A &lt;a href="https://arxiv.org/abs/2607.21832" rel="noopener noreferrer"&gt;study&lt;/a&gt; by researchers at Polytechnique Montréal, led by Canada Research Chair Foutse Khomh, analyzed 220,612 PRs across 539 Python repos and found Claude Code's PRs merge 84.3% of the time—well ahead of Codex (73.5%), Cursor (63.9%), Copilot (59.6%), and Devin (43.0%)—with bug rates comparable to or lower than human-written code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenAI launches GPT-6 Astra&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
OpenAI introduced &lt;a href="https://openai.com/index/gpt-6-astra/" rel="noopener noreferrer"&gt;GPT-6 Astra&lt;/a&gt;, a new frontier model focused on advanced reasoning, computer use, coding, scientific research, and professional workflows. The model achieves major gains across benchmarks, including 99.9% on ARC-AGI-3 and 100% on ExploitBench, while also improving task efficiency and alignment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anthropic introduces Claude Fable 5.1 and Mythos 5.1&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The &lt;a href="https://www.anthropic.com/claude-fable-and-mythos-5-1" rel="noopener noreferrer"&gt;new models&lt;/a&gt; target advanced coding, knowledge work, and scientific research, with Fable 5.1 offering stronger performance at lower cost and Mythos 5.1 providing more permissive safeguards for vetted cybersecurity and life-science users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Grok Bot comes to Android&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Cursor has launched the &lt;a href="https://forum.cursor.com/t/grok-bot-is-now-live-on-android/170384" rel="noopener noreferrer"&gt;Grok Bot Android app&lt;/a&gt;, letting users assign tasks to AI Bots from their phones, continue conversations across devices, and monitor multiple Bots running in parallel on cloud computers. The app is currently in beta for eligible Cursor and SuperGrok plans.&amp;nbsp;&lt;/p&gt;




&lt;h3&gt;
  
  
  Community tutorials&amp;nbsp;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/why-your-best-model-is-two-models" rel="noopener noreferrer"&gt;&lt;strong&gt;Why Your Best Model Is Two Models: Routing Between Kimi K3 and Claude&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Hardcoded routing logic gets messy fast and using a small model like Haiku to classify requests means paying for two calls on every one. DigitalOcean built Plano-Orchestrator, a routing model that scored 87.84% accuracy against GPT-5.1's 86.93% and Claude Sonnet 4.5's 86.11%, deciding where a request goes in about 200 milliseconds. Walk through building a router that pools Kimi K3 and Claude, and see how to check with live traffic data whether it's actually working.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/spot-gpu-droplets-doks" rel="noopener noreferrer"&gt;&lt;strong&gt;Resilient GPU Compute on DigitalOcean Kubernetes: Surviving Spot Interruptions&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
When DOKS reclaims Spot GPU capacity, it deletes the entire node pool at once, not one node at a time so the usual "autoscaler quietly relaunches it" assumption breaks completely, and nothing automatically brings a reclaimed pool back. Walk through building a pre-provisioned On-Demand fallback pool that costs nothing until a reclaim happens, and run the companion repo's automated interruption simulation to see the failover in action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/conceptual-articles/glm-5-3-flash-cost-per-token" rel="noopener noreferrer"&gt;&lt;strong&gt;GLM-5.3-Flash is the cheapest model on DigitalOcean. It's also the most verbose.&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
GLM-5.3-Flash lists at one twelfth of Qwen3.8-Max's output price, but on unconfigured defaults, it burned 625 output tokens answering what port SSH uses because it silently defaults to maximum reasoning effort, cutting its real-world price advantage down to just 2.3x. See the measured cost breakdown across 2,700 API calls, and get the one-line reasoning_effort fix that made Flash 6.3x cheaper on the same prompts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/pgvector-at-scale-article" rel="noopener noreferrer"&gt;&lt;strong&gt;When pgvector Starts to Slow Down as Your Vector Table Grows&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
A pgvector's query latency doesn't creep up gradually as a table grows. It stays flat for a long time, then jumps hard the moment the HNSW graph outgrows available RAM and Postgres starts reading it from disk instead. Get the six-step method for finding your own breaking point, measuring recall, latency, and index build time at the table sizes you'll actually reach.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/does-context-length-affect-inference-cost-linearly" rel="noopener noreferrer"&gt;&lt;strong&gt;Does Context Length Affect Inference Cost Linearly? We Measured Why It Doesn't&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Cost calculators price context length linearly, but measured throughput on a single H200 serving Ministral 3 14B fell from 19,089.8 tokens/sec at 2K context to 4,967.2 tokens/sec at 256K: a 3.84x collapse driven by concurrent request capacity dropping from 311 to just 2 as the fixed KV cache pool fills up. See the full cost curve and break-even utilization math showing exactly where a dedicated GPU stops being cheaper than a flat per-token serverless rate.&amp;nbsp;&lt;/p&gt;




&lt;h3&gt;
  
  
  Product updates
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/spot-gpu-droplets-doks" rel="noopener noreferrer"&gt;&lt;strong&gt;DigitalOcean Kubernetes (DOKS) now supports Spot GPU Droplets&lt;/strong&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Running Spot GPUs on DOKS automates interruption handling with automatic cordoning, draining, and PodDisruptionBudget enforcement. Cluster autoscaling dynamically scales your GPU capacity based on workload demand. Kubernetes capabilities such as labels, taints, and node affinity allow you to configure on-demand node pools as a fallback when Spot capacity is reclaimed. Plus, reclaim events surface as native Kubernetes events. &lt;a href="https://cloud.digitalocean.com/gpus/new?i=403c6d&amp;amp;region=mem1&amp;amp;size=gpu-mi355x8-2304gb-spot&amp;amp;fleetUuid=94ff983a-9cbc-4198-a245-118a1e5e476b" rel="noopener noreferrer"&gt;Try it today&lt;/a&gt;&amp;nbsp;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>startup</category>
    </item>
    <item>
      <title>April 2026 DigitalOcean Tutorials: Inference Optimization and AI Infrastructure</title>
      <dc:creator>DigitalOcean</dc:creator>
      <pubDate>Fri, 22 May 2026 21:55:02 +0000</pubDate>
      <link>https://dev.to/digitalocean/april-2026-digitalocean-tutorials-inference-optimization-and-ai-infrastructure-5fcf</link>
      <guid>https://dev.to/digitalocean/april-2026-digitalocean-tutorials-inference-optimization-and-ai-infrastructure-5fcf</guid>
      <description>&lt;p&gt;Most AI teams hit the same walls once they move past prototyping. The RAG pipeline that worked flawlessly in a demo starts hallucinating under real traffic. Inference costs climb without clear optimization levers. GPU resources sit underutilized while workloads spike elsewhere. &lt;/p&gt;

&lt;p&gt;Most of the time, the root cause traces back to architecture decisions that weren't pressure-tested for production. This month's &lt;a href="https://www.digitalocean.com/community/tutorials" rel="noopener noreferrer"&gt;DigitalOcean tutorials&lt;/a&gt; focus on diagnosing and fixing those failure points across the AI infrastructure stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.digitalocean.com/community/conceptual-articles/why-rag-systems-fail-in-production" rel="noopener noreferrer"&gt;Why RAG Systems Fail in Production&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Why do seemingly solid RAG demos collapse under real-world conditions? This article traces failures back to retrieval quality, latency tradeoffs, and embedding drift. You’ll get a clear picture of how upstream decisions—such as chunking strategy and ranking—directly affect downstream LLM outputs. If your team is building production pipelines, evaluation, monitoring, and retrieval engineering matter just as much as model choice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fogkanycez0ox4kj1fjmi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fogkanycez0ox4kj1fjmi.png" alt="RAG System architecture" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.digitalocean.com/community/conceptual-articles/dedicated-vs-serverless-inference-at-scale" rel="noopener noreferrer"&gt;Dedicated vs. Serverless Inference as You Scale&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The choice between serverless and dedicated inference isn't a one-time decision but an evolution driven by how your workload changes over time. Early on, serverless makes sense because traffic is unpredictable and iteration speed matters more than performance optimization. As usage stabilizes, the cracks show up—latency variability frustrates users and per-request pricing gets expensive for always-on systems. Walk-throughs of Modal and Together.ai show where that transition point hits and why delaying it costs you.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.digitalocean.com/community/conceptual-articles/serverless-fine-tuned-llms" rel="noopener noreferrer"&gt;Fine-Tuned LLMs on Serverless Architecture&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Parameter-efficient methods like LoRA let platforms serve hundreds of fine-tuned model variants from a single GPU by layering small adapter weights on top of a shared frozen base model. This makes serverless, pay-per-token inference possible for custom models without dedicated GPU deployments. The tradeoff is cold starts: idle adapters get evicted from VRAM and need to be reloaded, adding a few hundred milliseconds of latency to the first token. You’ll learn how to minimize that with keep-alive requests, adapter rank tuning, and smarter layer targeting.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.digitalocean.com/community/tutorials/model-silent-versioning-problem" rel="noopener noreferrer"&gt;The Silent Versioning Problem in AI Inference&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This one is a cautionary tale about what happens when the model behind your endpoint changes and nobody tells you. The serving stack is full of moving parts that can shift independently of the model name, and the result is silent regressions that break prompt tuning and invalidate your evaluations before you even know something moved. It includes a practical buyer's checklist for pressing inference platforms on snapshot pinning, retention commitments, and how they handle disclosure when something in the stack changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fai6i5tt8aydh7zx752l8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fai6i5tt8aydh7zx752l8.png" alt="Silent versioning framework" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.digitalocean.com/community/conceptual-articles/bottlenecks-llm-inference-optimization" rel="noopener noreferrer"&gt;The Hidden Bottlenecks in LLM Inference and How to Fix Them&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Faster GPUs are not the answer if the rest of your serving stack can't keep up. Spoiler: the bottlenecks are GPU underutilization from rigid batching, memory bandwidth constraints during decode, KV cache fragmentation, and CPU-side overhead from tokenization and prompt assembly. Click through for a deeper look at each one and practical fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.digitalocean.com/community/tutorials/ai-platform-security-review" rel="noopener noreferrer"&gt;We Built a Private-Document AI App to Test Platform Security. Here Is What We Could Actually Verify&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;AI security should always be treated as a first-class concern, not an afterthought. This tutorial puts that to the test by building a private-document chatbot and running the same workflow across six inference platforms: DigitalOcean, Baseten, Nebius, Fireworks AI, Modal, and Together AI. Each platform is evaluated on access controls, data retention defaults, network isolation, audit logging, and shared responsibility clarity. It doubles as a practical framework for figuring out what you can actually verify before sensitive data is in flight.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.digitalocean.com/community/tutorials/post-inference-querying-mongodb" rel="noopener noreferrer"&gt;Post-Inference Storage and Querying with MongoDB&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Many inference tutorials stop at the model response. This one keeps going. You'll build a FastAPI app that sends images through a vision model, stores the structured predictions in MongoDB, and then exposes endpoints that let you filter by detected labels and confidence scores or run aggregation pipelines across your full dataset. It's a practical blueprint for turning raw model output into something queryable and operational.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-build-multi-agent-ai-system-docker-agent-digitalocean" rel="noopener noreferrer"&gt;How to Build a Multi-Agent AI System with Docker and DigitalOcean&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Instead of routing everything through a single model, multi-agent systems let you split a workflow across specialized agents that each handle a different part of the problem and pass results between them. The tradeoff is coordination complexity. This walkthrough covers how to containerize each agent with Docker, manage communication between them, and deploy the full system on DigitalOcean. You'll come away with a working deployment pattern you can adapt to your own orchestration needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.digitalocean.com/community/tutorials/gpu-fleet-optimizer" rel="noopener noreferrer"&gt;Building an AI-Powered GPU Fleet Optimizer with the DigitalOcean AI Platform ADK&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A single idle GPU Droplet left running overnight can add hundreds of dollars to your monthly bill, and standard CPU monitoring won't catch it because it can't see whether the GPU is actually doing work. This tutorial builds an AI-powered agent using the DigitalOcean AI Platform ADK that scrapes NVIDIA DCGM metrics like VRAM usage, engine utilization, and power draw across your fleet in real time. It compares those metrics against configurable thresholds to flag idle resources before they inflate your cloud spend. The repo is designed to be forked and customized to your own workloads, including adding tools that let the agent take action like powering off idle nodes.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>infrastructure</category>
      <category>tutorial</category>
      <category>learning</category>
    </item>
    <item>
      <title>Python Decorators: From Basics to Real-World Use Cases</title>
      <dc:creator>DigitalOcean</dc:creator>
      <pubDate>Tue, 12 May 2026 21:04:07 +0000</pubDate>
      <link>https://dev.to/digitalocean/python-decorators-from-basics-to-real-world-use-cases-n5f</link>
      <guid>https://dev.to/digitalocean/python-decorators-from-basics-to-real-world-use-cases-n5f</guid>
      <description>&lt;p&gt;&lt;em&gt;This article was originally written by Shaoni Mukherjee (AI Technical Writer)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Key takeaways
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Python decorators allow additional functionality to be added to functions without changing the original function code.&lt;/li&gt;
&lt;li&gt;Decorators help reduce repeated code and improve code reusability.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;@decorator_name&lt;/code&gt; syntax is a cleaner way of wrapping functions.&lt;/li&gt;
&lt;li&gt;Decorators are commonly used for logging, authentication, caching, validation, and performance monitoring.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;*args&lt;/code&gt; and &lt;code&gt;**kwargs&lt;/code&gt; make decorators flexible enough to work with different function arguments.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;functools.wraps&lt;/code&gt; helps preserve the original function metadata and should be considered a best practice.&lt;/li&gt;
&lt;li&gt;Multiple decorators can be chained together to add multiple layers of functionality.&lt;/li&gt;
&lt;li&gt;Frameworks like Flask and Django rely heavily on decorators for routing, authentication, and request handling.&lt;/li&gt;
&lt;li&gt;Decorators should be kept simple and focused to maintain readability and easier debugging.&lt;/li&gt;
&lt;li&gt;Understanding decorators is important for writing cleaner and more maintainable Python applications.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;While building real-world &lt;a href="https://www.digitalocean.com/community/tutorials/python-tutorial" rel="noopener noreferrer"&gt;Python&lt;/a&gt; applications, a common challenge is the repetition of certain logic codes, such as logging, authentication, validation, time, or performance monitoring across multiple functions. For instance, API endpoints often require user authentication checks, and performance-critical functions may need execution time tracking.&lt;/p&gt;

&lt;p&gt;Adding the same logic code within each function often leads to cluttered code, reduced readability, and increased maintenance effort. Decorators address this problem by creating the separation of such cross-cutting concerns into reusable components that can be applied to functions in a clean and consistent manner. In frameworks like &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-create-your-first-web-application-using-flask-and-python-3" rel="noopener noreferrer"&gt;Flask&lt;/a&gt;, the &lt;code&gt;@app.route("/")&lt;/code&gt; decorator links a URL to a function without requiring explicit routing logic, while in &lt;a href="https://www.digitalocean.com/solutions/django-hosting" rel="noopener noreferrer"&gt;Django&lt;/a&gt;, decorators such as &lt;code&gt;@login_required&lt;/code&gt; enforce access control by restricting views to authenticated users. This approach promotes modularity, improves code clarity, and simplifies the overall structure of applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are Python decorators?
&lt;/h3&gt;

&lt;p&gt;Decorators are basically a wrapper around a function to modify it for better use. The function remains the same, but the decorator adds an extra something to the function.&lt;/p&gt;

&lt;h4&gt;
  
  
  The core idea
&lt;/h4&gt;

&lt;p&gt;Say you have a simple function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, world!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now imagine you want to print a line before and after every function you write, without modifying each one. A decorator lets you do exactly that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--- Before ---&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;# calls the original function
&lt;/span&gt;        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--- After ---&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@my_decorator&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, world!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="n"&gt;Before&lt;/span&gt; &lt;span class="o"&gt;---&lt;/span&gt;
&lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="n"&gt;After&lt;/span&gt; &lt;span class="o"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@my_decorator&lt;/code&gt; line is just shorthand for &lt;code&gt;greet = my_decorator(greet)&lt;/code&gt;. Python replaces your function with the wrapped version automatically.&lt;br&gt;
To understand the concept better, let us take a real-world example of timing a function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;        &lt;span class="c1"&gt;# *args lets it work with ANY function
&lt;/span&gt;        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; took &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; seconds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@timer&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;slow_task&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Task done!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;slow_task&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="n"&gt;slow_task&lt;/span&gt; &lt;span class="n"&gt;took&lt;/span&gt; &lt;span class="mf"&gt;1.0012&lt;/span&gt; &lt;span class="n"&gt;seconds&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Why decorators matter (especially in real projects)
&lt;/h4&gt;

&lt;p&gt;They're everywhere in Python. Common use cases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@staticmethod&lt;/code&gt; / &lt;code&gt;@classmethod&lt;/code&gt;&lt;/strong&gt; — built into Python for class methods&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@app.route('/home')&lt;/code&gt;&lt;/strong&gt; — Flask/Django use them to define web routes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@login_required&lt;/code&gt;&lt;/strong&gt; — Django uses this to protect pages behind authentication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging, caching, retrying failed requests&lt;/strong&gt; — all cleanly handled with decorators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A decorator takes a function, adds behavior around it, and returns a new function without touching the original code.&lt;/p&gt;

&lt;h2&gt;
  
  
  How decorators work internally
&lt;/h2&gt;

&lt;p&gt;To understand decorators better, we will first need to understand a few core Python concepts:&lt;/p&gt;

&lt;h3&gt;
  
  
  Foundation: Functions are objects in Python
&lt;/h3&gt;

&lt;p&gt;In Python, functions aren't special, but they're just objects like integers or strings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Pass a function as an argument
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;run_it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# prints: Hello!
&lt;/span&gt;
&lt;span class="c1"&gt;# Assign a function to a variable
&lt;/span&gt;&lt;span class="n"&gt;my_func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;say_hello&lt;/span&gt;
&lt;span class="nf"&gt;my_func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;# prints: Hello!
&lt;/span&gt;
&lt;span class="c1"&gt;# Return a function from another function
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_greeter&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;say_hi&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hi!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;say_hi&lt;/span&gt;   &lt;span class="c1"&gt;# returning the function, not calling it
&lt;/span&gt;
&lt;span class="n"&gt;greeter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_greeter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;greeter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;# prints: Hi!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the entire foundation that decorators are built on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why are decorators needed?
&lt;/h3&gt;

&lt;p&gt;Imagine there are many functions in a project, and each function needs logging.&lt;/p&gt;

&lt;h4&gt;
  
  
  Without decorators:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Function started&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Function ended&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Function started&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Function ended&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repeated code&lt;/li&gt;
&lt;li&gt;Hard to maintain in large projects&lt;/li&gt;
&lt;li&gt;If logging changes, every function must be updated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Decorators solve this problem by reusing common functionality.&lt;/p&gt;

&lt;h4&gt;
  
  
  With decorators:
&lt;/h4&gt;

&lt;p&gt;Using decorators, the repeated code (&lt;code&gt;"Function started"&lt;/code&gt; and &lt;code&gt;"Function ended"&lt;/code&gt;) can be moved into a single reusable decorator.&lt;br&gt;
Instead of writing the same lines inside every function, the decorator handles it automatically.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 1: Create the decorator
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Function started&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Function ended&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step 2: Apply the Decorator&lt;/strong&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@log_function&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;


&lt;span class="nd"&gt;@log_function&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Calling the Functions&lt;/strong&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;Function&lt;/span&gt; &lt;span class="n"&gt;started&lt;/span&gt;
&lt;span class="n"&gt;Function&lt;/span&gt; &lt;span class="n"&gt;ended&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="n"&gt;Function&lt;/span&gt; &lt;span class="n"&gt;started&lt;/span&gt;
&lt;span class="n"&gt;Function&lt;/span&gt; &lt;span class="n"&gt;ended&lt;/span&gt;
&lt;span class="mi"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  What changed?
&lt;/h4&gt;

&lt;p&gt;The functions now only contain their main logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The extra behavior (logging) is handled by the decorator separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual understanding
&lt;/h3&gt;

&lt;p&gt;When this runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python internally does this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;log_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the actual flow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Function started&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;original&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Function ended&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Better Version Using *args and **kwargs
&lt;/h2&gt;

&lt;p&gt;The previous decorator only works for functions with two arguments.&lt;br&gt;
A more reusable decorator looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Function started&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Function ended&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it works with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;any number of arguments&lt;/li&gt;
&lt;li&gt;positional arguments&lt;/li&gt;
&lt;li&gt;keyword arguments&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why this is powerful
&lt;/h2&gt;

&lt;p&gt;Imagine 100 functions needing logging.&lt;/p&gt;

&lt;p&gt;Without decorators:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repeated code everywhere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With decorators:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;write logging once&lt;/li&gt;
&lt;li&gt;reuse everywhere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is one of the biggest reasons decorators are widely used in real-world Python projects and frameworks like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://flask.palletsprojects.com/en/stable/" rel="noopener noreferrer"&gt;Flask&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.djangoproject.com/" rel="noopener noreferrer"&gt;Django&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fastapi.tiangolo.com/" rel="noopener noreferrer"&gt;FastAPI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/pytorch-101-advanced" rel="noopener noreferrer"&gt;PyTorch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/introduction-to-tensorflow-build-ai-across-domains" rel="noopener noreferrer"&gt;TensorFlow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common practical examples of Python decorators
&lt;/h2&gt;

&lt;p&gt;A few of the most common practical examples are listed here, from solo projects to production systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Timing and performance measurement
&lt;/h3&gt;

&lt;p&gt;Useful when profiling slow functions or benchmarking code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ran in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@timer&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;

&lt;span class="nf"&gt;process_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1_000_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# process_data ran in 0.0312s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;perf_counter()&lt;/code&gt; is preferred over &lt;code&gt;time.time()&lt;/code&gt; for short measurements, and it's higher resolution and is not affected by system clock adjustments.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Logging
&lt;/h3&gt;

&lt;p&gt;Instead of adding print statements everywhere, a logging decorator handles it in one place.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;

&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log_calls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Calling &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; | args=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; kwargs=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; returned &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@log_calls&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;

&lt;span class="nf"&gt;multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# INFO: Calling multiply | args=(4, 5) kwargs={}
# INFO: multiply returned 20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In production, you'd swap &lt;code&gt;logging.info&lt;/code&gt; for a structured logger like &lt;code&gt;structlog&lt;/code&gt; or a cloud logging sink.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Retry on failure
&lt;/h3&gt;

&lt;p&gt;Critical for network calls, API requests, or anything that can fail transiently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Attempt &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; failed after &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; attempts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;

&lt;span class="nd"&gt;@retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;fetch_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.example.com/data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Attempt 1 failed: Connection timeout
# Attempt 2 failed: Connection timeout
# Attempt 3 failed: Connection timeout
# Exception: fetch_data failed after 3 attempts
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice this is a &lt;strong&gt;decorator factory&lt;/strong&gt; — &lt;code&gt;retry(times=3)&lt;/code&gt; returns the actual decorator. This is how you pass arguments to decorators.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Caching memoization
&lt;/h3&gt;

&lt;p&gt;Avoids recomputing expensive results by storing previous outputs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cache miss — computing for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cache hit for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@memoize&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Cache miss — computing for (6,)
# Cache miss — computing for (5,)
# ...
&lt;/span&gt;&lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Cache hit for (6,)   ← instantly returns stored result
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python actually ships a production-grade version of this built in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;lru_cache&lt;/span&gt;

&lt;span class="nd"&gt;@lru_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;lru_cache&lt;/code&gt; (Least Recently Used) is thread-safe and evicts old entries when the cache is full — use it over a hand-rolled version in real projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Access control authorization
&lt;/h3&gt;

&lt;p&gt;A staple in web frameworks like Flask and Django.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;require_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;PermissionError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Access denied. Required role: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;

&lt;span class="nd"&gt;@require_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delete_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deleting user &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Shaoni&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;guest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Guest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;viewer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;delete_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# Deleting user 42
&lt;/span&gt;&lt;span class="nf"&gt;delete_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;guest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# PermissionError: Access denied. Required role: admin
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Django's &lt;code&gt;@login_required&lt;/code&gt; and &lt;code&gt;@permission_required&lt;/code&gt; follow this exact pattern internally.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Input validation
&lt;/h3&gt;

&lt;p&gt;Validate arguments before they even reach your function's logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_positive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arg_positions&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;arg_positions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Argument at position &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; must be positive, got &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;

&lt;span class="nd"&gt;@validate_positive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_area&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;

&lt;span class="nf"&gt;calculate_area&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# 50
&lt;/span&gt;&lt;span class="nf"&gt;calculate_area&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# ValueError: Argument at position 0 must be positive
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;7. Rate Limiting&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Preventing a function from being called too frequently is very common in API clients.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rate_limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calls_per_second&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;min_interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;calls_per_second&lt;/span&gt;
    &lt;span class="n"&gt;last_called&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;# mutable container to hold state in closure
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;last_called&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;min_interval&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;elapsed&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Rate limit: waiting &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;last_called&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;

&lt;span class="nd"&gt;@rate_limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calls_per_second&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call_api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Calling &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;call_api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;call_api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/posts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# Rate limit: waiting 0.49s
&lt;/span&gt;&lt;span class="nf"&gt;call_api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/comments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Rate limit: waiting 0.49s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Quick reference
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decorator&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Real-world Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@timer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Measure execution time&lt;/td&gt;
&lt;td&gt;Profiling, benchmarking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@log_calls&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Audit function calls&lt;/td&gt;
&lt;td&gt;Observability, debugging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@retry&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Handle transient failures&lt;/td&gt;
&lt;td&gt;API clients, DB connections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@lru_cache&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cache expensive results&lt;/td&gt;
&lt;td&gt;ML inference, DB queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@require_role&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Guard endpoints by role&lt;/td&gt;
&lt;td&gt;Django, Flask auth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@validate_positive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sanitize inputs early&lt;/td&gt;
&lt;td&gt;Data pipelines, APIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@rate_limit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Throttle call frequency&lt;/td&gt;
&lt;td&gt;External API clients&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Real-world use cases in frameworks
&lt;/h2&gt;

&lt;p&gt;Decorators are heavily used in modern Python frameworks because they provide a clean and reusable way to add functionality to applications without modifying the core business logic.&lt;br&gt;
Frameworks such as Flask and Django use decorators for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routing&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Authorization&lt;/li&gt;
&lt;li&gt;Caching&lt;/li&gt;
&lt;li&gt;Request validation&lt;/li&gt;
&lt;li&gt;Restricting HTTP methods&lt;/li&gt;
&lt;li&gt;Logging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These decorators make applications cleaner, easier to maintain, and more readable.&lt;/p&gt;
&lt;h3&gt;
  
  
  Flask routing decorator
&lt;/h3&gt;

&lt;p&gt;One of the most common examples of decorators appears in Flask routing.&lt;br&gt;
Using Flask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;home&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Homepage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is a decorator.&lt;br&gt;
It tells Flask:&lt;br&gt;
“When a user visits &lt;code&gt;/&lt;/code&gt;, execute the &lt;code&gt;home()&lt;/code&gt; function.”&lt;/p&gt;
&lt;h3&gt;
  
  
  Flask authentication decorator
&lt;/h3&gt;

&lt;p&gt;Decorators are also commonly used for authentication.&lt;br&gt;
Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/dashboard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@login_required&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dashboard&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Dashboard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@login_required&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;checks whether the user is logged in before allowing access to the dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why this is useful
&lt;/h3&gt;

&lt;p&gt;Without decorators, authentication checks would need to be repeated inside every protected function.&lt;br&gt;
Example without decorator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dashboard&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;logged_in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Please log in&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Dashboard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using decorators:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;avoids repeated code&lt;/li&gt;
&lt;li&gt;keeps route definitions clean&lt;/li&gt;
&lt;li&gt;centralizes authentication logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This becomes extremely useful in large applications with many protected routes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Django authentication decorator
&lt;/h3&gt;

&lt;p&gt;Django also uses decorators extensively.&lt;br&gt;
Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.contrib.auth.decorators&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;login_required&lt;/span&gt;
&lt;span class="nd"&gt;@login_required&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dashboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Welcome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@login_required&lt;/code&gt; decorator ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;only authenticated users can access the view&lt;/li&gt;
&lt;li&gt;unauthorized users are redirected to the login page&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Reusable security checks&lt;/li&gt;
&lt;li&gt;Cleaner view functions&lt;/li&gt;
&lt;li&gt;Better maintainability&lt;/li&gt;
&lt;li&gt;Centralized authentication handling&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Django HTTP method restriction
&lt;/h3&gt;

&lt;p&gt;Django provides decorators to restrict HTTP request methods.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.views.decorators.http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;require_POST&lt;/span&gt;
&lt;span class="nd"&gt;@require_POST&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Submitted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The decorator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@require_POST&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ensures the function only accepts POST requests.&lt;br&gt;
If a GET request is sent, Django automatically returns an error.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why this matters
&lt;/h3&gt;

&lt;p&gt;This helps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;enforce API rules&lt;/li&gt;
&lt;li&gt;improve security&lt;/li&gt;
&lt;li&gt;prevent invalid request types&lt;/li&gt;
&lt;li&gt;simplify validation logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without decorators, manual checks would be needed inside every function.&lt;/p&gt;
&lt;h3&gt;
  
  
  Django caching decorator
&lt;/h3&gt;

&lt;p&gt;Decorators are also used for performance optimization.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.views.decorators.cache&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cache_page&lt;/span&gt;
&lt;span class="nd"&gt;@cache_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cached&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@cache_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;stores the response for 60 seconds.&lt;br&gt;
If another user requests the same page during that time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Django serves the cached version&lt;/li&gt;
&lt;li&gt;the function does not run again&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Advanced decorator concepts
&lt;/h2&gt;

&lt;p&gt;Once the basic concepts are understood, the next step is to learn how decorators are implemented in production-grade Python applications. Advanced decorator patterns solve practical problems such as preserving function metadata, creating configurable decorators, and combining multiple decorators together.&lt;/p&gt;

&lt;p&gt;These concepts are widely used in frameworks, libraries, and enterprise-level Python applications.&lt;/p&gt;
&lt;h3&gt;
  
  
  Preserving function metadata with &lt;code&gt;functools.wraps&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;One common issue with decorators is that they replace the original function with the wrapper function. As a result, important metadata such as the function name, documentation string, annotations, and debugging information may be lost.&lt;/p&gt;

&lt;p&gt;Consider the following decorator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@decorator&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This function greets the user&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now checking the function name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;wrapper&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of returning &lt;code&gt;"greet"&lt;/code&gt;, Python returns &lt;code&gt;"wrapper"&lt;/code&gt; because the original metadata has been overridden by the wrapper function.&lt;br&gt;
This creates problems for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;debugging&lt;/li&gt;
&lt;li&gt;logging&lt;/li&gt;
&lt;li&gt;API documentation&lt;/li&gt;
&lt;li&gt;introspection&lt;/li&gt;
&lt;li&gt;testing frameworks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To solve this problem, Python provides &lt;code&gt;functools.wraps&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using &lt;code&gt;functools.wraps&lt;/code&gt;
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

   &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Using it again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@decorator&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This function greets the user&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;greet&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@wraps(func)&lt;/code&gt; decorator copies the original function metadata into the wrapper function. This is considered a best practice when writing decorators in production applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decorators with arguments
&lt;/h3&gt;

&lt;p&gt;In many real-world scenarios, decorators need configuration values. This requires creating decorators that accept arguments.&lt;br&gt;
A decorator with arguments introduces an additional level of nesting.&lt;br&gt;
Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

       &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

           &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
               &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;Hello&lt;/span&gt;
&lt;span class="n"&gt;Hello&lt;/span&gt;
&lt;span class="n"&gt;Hello&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Understanding the structure
&lt;/h2&gt;

&lt;p&gt;This example contains three functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;        &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;accepts&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;
&lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;     &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;accepts&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;original&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;
&lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;       &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;executes&lt;/span&gt; &lt;span class="n"&gt;additional&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The execution flow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;greet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern is heavily used in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retry mechanisms&lt;/li&gt;
&lt;li&gt;caching systems&lt;/li&gt;
&lt;li&gt;rate limiting&lt;/li&gt;
&lt;li&gt;authorization frameworks&lt;/li&gt;
&lt;li&gt;logging systems&lt;/li&gt;
&lt;li&gt;timeout handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a retry decorator may accept the number of retries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A caching decorator may accept an expiration time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expire&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Decorator arguments make decorators significantly more flexible and reusable.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Chaining Multiple Decorators&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Python allows multiple decorators to be applied to the same function.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@decorator_one&lt;/span&gt;
&lt;span class="nd"&gt;@decorator_two&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is internally interpreted as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;decorator_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;decorator_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The execution order is important.&lt;/p&gt;

&lt;p&gt;Python applies decorators from bottom to top:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;decorator_two&lt;/code&gt; wraps the function first&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;decorator_one&lt;/code&gt; wraps the result next&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example of chained decorators
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Decorator One - Before&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Decorator One - After&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Decorator Two - Before&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Decorator Two - After&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Applying both decorators:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@decorator_one&lt;/span&gt;
&lt;span class="nd"&gt;@decorator_two&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;Decorator&lt;/span&gt; &lt;span class="n"&gt;One&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Before&lt;/span&gt;
&lt;span class="n"&gt;Decorator&lt;/span&gt; &lt;span class="n"&gt;Two&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Before&lt;/span&gt;
&lt;span class="n"&gt;Hello&lt;/span&gt;
&lt;span class="n"&gt;Decorator&lt;/span&gt; &lt;span class="n"&gt;Two&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;After&lt;/span&gt;
&lt;span class="n"&gt;Decorator&lt;/span&gt; &lt;span class="n"&gt;One&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;After&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Understanding the execution flow
&lt;/h3&gt;

&lt;p&gt;The function call stack becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;decorator_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nf"&gt;decorator_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="n"&gt;greet&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates nested execution layers where each decorator adds behavior before and after the wrapped function. Decorator chaining is extensively used in frameworks. For example, a web route may simultaneously use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication&lt;/li&gt;
&lt;li&gt;caching&lt;/li&gt;
&lt;li&gt;rate limiting&lt;/li&gt;
&lt;li&gt;logging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/dashboard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@login_required&lt;/span&gt;
&lt;span class="nd"&gt;@cache_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dashboard&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Dashboard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each decorator contributes a separate layer of functionality while keeping the core business logic clean and isolated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Python decorators provide a clean and powerful way to add extra functionality to functions without modifying the original code. They help reduce code duplication, improve reusability, and make applications easier to maintain.&lt;/p&gt;

&lt;p&gt;From simple logging examples to advanced use cases in frameworks like Flask and Django, decorators play an important role in modern Python development. Understanding how decorators work helps in writing cleaner, more scalable, and more professional Python code.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>tutorial</category>
      <category>learning</category>
    </item>
    <item>
      <title>NVIDIA B300 Blackwell Ultra: A Technical Deep Dive</title>
      <dc:creator>DigitalOcean</dc:creator>
      <pubDate>Thu, 07 May 2026 23:53:39 +0000</pubDate>
      <link>https://dev.to/digitalocean/nvidia-b300-blackwell-ultra-a-technical-deep-dive-5c6i</link>
      <guid>https://dev.to/digitalocean/nvidia-b300-blackwell-ultra-a-technical-deep-dive-5c6i</guid>
      <description>&lt;p&gt;The NVIDIA B300 (Blackwell Ultra) is NVIDIA's latest data center GPU, built for AI training and inference. In this deep dive, we break down the full architecture, from its dual-die design and 5th-generation tensor cores to NVFP4 precision and NVLink 5 scaling.        &lt;/p&gt;

&lt;p&gt;What we cover:&lt;br&gt;
  &lt;a href="https://www.youtube.com/watch?v=Kf_3n_pxa0I" rel="noopener noreferrer"&gt;00:00&lt;/a&gt; - Introduction&lt;br&gt;
  &lt;a href="https://www.youtube.com/watch?v=Kf_3n_pxa0I&amp;amp;t=56s" rel="noopener noreferrer"&gt;00:56&lt;/a&gt; - Why the B300 exists&lt;br&gt;
  &lt;a href="https://www.youtube.com/watch?v=Kf_3n_pxa0I&amp;amp;t=145s" rel="noopener noreferrer"&gt;02:25&lt;/a&gt; - B300 vs B200 vs H100 — the numbers&lt;br&gt;
  &lt;a href="https://www.youtube.com/watch?v=Kf_3n_pxa0I&amp;amp;t=239s" rel="noopener noreferrer"&gt;03:59&lt;/a&gt; - Dual-reticle design &amp;amp; NV-HBI interconnect&lt;br&gt;
  &lt;a href="https://www.youtube.com/watch?v=Kf_3n_pxa0I&amp;amp;t=304s" rel="noopener noreferrer"&gt;05:04&lt;/a&gt; - 5th-gen tensor cores &amp;amp; NVFP4&lt;br&gt;
  &lt;a href="https://www.youtube.com/watch?v=Kf_3n_pxa0I&amp;amp;t=476s" rel="noopener noreferrer"&gt;07:56&lt;/a&gt; - 288GB HBM3e memory breakdown&lt;br&gt;
  &lt;a href="https://www.youtube.com/watch?v=Kf_3n_pxa0I&amp;amp;t=544s" rel="noopener noreferrer"&gt;09:04&lt;/a&gt; - Multi-GPU &amp;amp; NVLink 5 architecture&lt;br&gt;
  &lt;a href="https://youtu.be/watch?v=Kf_3n_pxa0I&amp;amp;t=578s" rel="noopener noreferrer"&gt;10:38&lt;/a&gt; - Performance &amp;amp; efficiency summary&lt;/p&gt;

</description>
      <category>nvidia</category>
      <category>ai</category>
      <category>gpu</category>
      <category>hardware</category>
    </item>
    <item>
      <title>Video Demo: How Does Model Compression Change AI Reasoning?</title>
      <dc:creator>DigitalOcean</dc:creator>
      <pubDate>Thu, 30 Apr 2026 16:00:00 +0000</pubDate>
      <link>https://dev.to/digitalocean/video-demo-how-does-model-compression-change-ai-reasoning-3jdk</link>
      <guid>https://dev.to/digitalocean/video-demo-how-does-model-compression-change-ai-reasoning-3jdk</guid>
      <description>&lt;p&gt;In this video, I benchmark Mistral-7B-Instruct-v0.2 on an NVIDIA H200 DigitalOcean GPU in three formats: FP16, INT8, and 4-bit AWQ — and test how precision impacts reasoning quality, speed, VRAM usage, and real serving density.&lt;/p&gt;

&lt;p&gt;We’ll cover:&lt;br&gt;
👉 What quantization actually does to model weights&lt;br&gt;
👉 Where reasoning starts breaking down (FP16 → INT8 → 4-bit)&lt;br&gt;
👉 Why memory savings don’t always reduce total GPU usage in vLLM&lt;br&gt;
👉 Tokens/sec vs aggregate throughput&lt;br&gt;
👉 When 4-bit wins — and when it doesn’t&lt;/p&gt;

&lt;p&gt;If you're building AI systems and deciding between full precision and aggressive quantization, this is a practical infrastructure-level breakdown of the real tradeoffs.&lt;/p&gt;

&lt;p&gt;Chapters:&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=50YBZvdwMWM" rel="noopener noreferrer"&gt;00:00&lt;/a&gt; Introduction&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=50YBZvdwMWM&amp;amp;t=41s" rel="noopener noreferrer"&gt;00:41&lt;/a&gt; Understanding how quantization works&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=50YBZvdwMWM&amp;amp;t=102s" rel="noopener noreferrer"&gt;01:42&lt;/a&gt; Why do you even need quantization&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=50YBZvdwMWM&amp;amp;t=158s" rel="noopener noreferrer"&gt;02:38&lt;/a&gt; The experiment we ran&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=50YBZvdwMWM&amp;amp;t=236s" rel="noopener noreferrer"&gt;03:56&lt;/a&gt; The observations we had&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=50YBZvdwMWM&amp;amp;t=343s" rel="noopener noreferrer"&gt;05:43&lt;/a&gt; Overall learnings&lt;/p&gt;

</description>
      <category>ai</category>
      <category>nvidia</category>
      <category>tutorial</category>
      <category>models</category>
    </item>
  </channel>
</rss>
