<?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: Saikiran Kalidindi</title>
    <description>The latest articles on DEV Community by Saikiran Kalidindi (@saikirankalidindi).</description>
    <link>https://dev.to/saikirankalidindi</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%2F746975%2Faab4f633-b153-4add-be3c-f69a47f40299.png</url>
      <title>DEV Community: Saikiran Kalidindi</title>
      <link>https://dev.to/saikirankalidindi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/saikirankalidindi"/>
    <language>en</language>
    <item>
      <title>Your LLM gateway's token budget is a suggestion</title>
      <dc:creator>Saikiran Kalidindi</dc:creator>
      <pubDate>Mon, 26 Oct 2026 14:43:09 +0000</pubDate>
      <link>https://dev.to/saikirankalidindi/your-llm-gateways-token-budget-is-a-suggestion-1jkb</link>
      <guid>https://dev.to/saikirankalidindi/your-llm-gateways-token-budget-is-a-suggestion-1jkb</guid>
      <description>&lt;p&gt;If several teams share one LLM bill, someone eventually asks for a hard cap: &lt;em&gt;team A gets two million tokens an hour, and not one more.&lt;/em&gt; Most LLM gateways offer that. I wanted to know how hard&lt;br&gt;
the cap really is, so I built a gateway, put a budget on it, and hammered it with concurrent&lt;br&gt;
streams.&lt;/p&gt;

&lt;p&gt;With 128 streams in flight per tenant, spread across three gateway replicas, the usual implementation let a tenant spend &lt;strong&gt;3.3× its budget&lt;/strong&gt;. The approach this post describes held&lt;br&gt;
the same tenant to &lt;strong&gt;0.03%&lt;/strong&gt; over: 5 tokens on a 20,000-token budget.&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%2F97r6qz4m4d6n0yziey9f.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%2F97r6qz4m4d6n0yziey9f.png" alt="Budget overshoot vs concurrency" width="799" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code, the benchmark and the raw results are open source:&lt;br&gt;
&lt;a href="https://github.com/saikirankalidindi/hardcap" rel="noopener noreferrer"&gt;github.com/saikirankalidindi/hardcap&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why request limits don't work for LLMs
&lt;/h2&gt;

&lt;p&gt;A classic rate limiter counts requests. That's fine when every request costs about the same. An&lt;br&gt;
LLM request can cost 10 tokens or 100,000, and you don't know which until the response is done:&lt;br&gt;
output length is decided by the model, one token at a time, while the stream is open.&lt;/p&gt;

&lt;p&gt;So gateways count tokens instead. The common implementation is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On each request, look up how many tokens the tenant has used this window.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;used &amp;lt; limit&lt;/code&gt;, let it through.&lt;/li&gt;
&lt;li&gt;When the response finishes, add its real token count to &lt;code&gt;used&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 3 is the problem. Between admission and settlement, a request is &lt;em&gt;invisible&lt;/em&gt; to the budget.&lt;br&gt;
Run one request at a time and you overshoot by at most one response. Run 128 at once and all 128&lt;br&gt;
are admitted while the tenant still looks under budget, and all 128 are charged when they finish.&lt;br&gt;
The overshoot grows linearly with concurrency, which is exactly what the blue line shows.&lt;/p&gt;

&lt;p&gt;Replicas make it worse, not better. Even with shared state in Redis, nothing reserves the tokens&lt;br&gt;
that in-flight requests are about to use.&lt;/p&gt;
&lt;h2&gt;
  
  
  Reserve, then settle
&lt;/h2&gt;

&lt;p&gt;The fix comes from payments, where it is old news: a card terminal &lt;em&gt;authorizes&lt;/em&gt; an amount before&lt;br&gt;
the sale and &lt;em&gt;captures&lt;/em&gt; the real amount after. Applied to tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;admit   used + reserved + estimate ≤ limit ?   → reserved += estimate
stream  every 64 tokens: grow the reservation (or stop if the budget is gone)
settle  reserved -= reservation;  used += actual
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each of these is a single Lua script in Redis. Redis runs one script at a time, so for a given&lt;br&gt;
tenant the checks and updates are serialized, no matter how many gateway replicas send them. That&lt;br&gt;
gives one invariant, checked inside every admit and every extension:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;used + reserved ≤ limit&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Settlement swaps a reservation for the real count, so the only way past the limit is a token that&lt;br&gt;
was generated &lt;em&gt;without&lt;/em&gt; a reservation. The whole design comes down to deciding what happens to&lt;br&gt;
those tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real problem is the estimate
&lt;/h2&gt;

&lt;p&gt;What should you reserve? There are two obvious answers, and both are wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reserve &lt;code&gt;max_tokens&lt;/code&gt;.&lt;/strong&gt; It's safe, because the model can't exceed it. But most completions use a&lt;br&gt;
fraction of their cap. With &lt;code&gt;max_tokens: 1024&lt;/code&gt; and a median response of about 150 tokens, every&lt;br&gt;
in-flight request holds about 6× what it will use. Near the end of a budget, the remaining tokens&lt;br&gt;
are all &lt;em&gt;held&lt;/em&gt; and none are &lt;em&gt;used&lt;/em&gt;, so new requests get rejected even though the budget isn't&lt;br&gt;
spent. In the benchmark, about &lt;strong&gt;4% of every budget was never usable&lt;/strong&gt;, and at 128 streams each&lt;br&gt;
tenant's clients saw roughly 2,900 "come back later" rejections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reserve a small fixed number.&lt;/strong&gt; It's efficient, until a long response blows straight past it.&lt;/p&gt;

&lt;p&gt;Hardcap reserves the &lt;strong&gt;rolling p95&lt;/strong&gt; of real output lengths for that route (the last 1,000&lt;br&gt;
completed responses) and treats the 5% tail as an &lt;em&gt;extension&lt;/em&gt; problem. As a stream gets within&lt;br&gt;
32 tokens of its reservation, the gateway asks Redis for 64 more. If the budget can't cover them,&lt;br&gt;
there are two policies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;allow&lt;/strong&gt;: let the stream finish. Overshoot is bounded by the tail of the streams in flight when
the budget ran out (+7.9% worst case at 128 streams).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;truncate&lt;/strong&gt; (the default): stop forwarding, send the client a final chunk with
&lt;code&gt;finish_reason: "length"&lt;/code&gt;, and close the upstream connection so the provider stops generating.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Truncated responses are kept out of the p95 sample. Otherwise the estimate would drift down, cause&lt;br&gt;
more truncation, drift down further, and spiral.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;128 streams per tenant, 3 replicas&lt;/th&gt;
&lt;th&gt;Worst overshoot&lt;/th&gt;
&lt;th&gt;Budget usable&lt;/th&gt;
&lt;th&gt;Truncated streams per tenant&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Count after the fact&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+234.3%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reserve &lt;code&gt;max_tokens&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;never over&lt;/td&gt;
&lt;td&gt;95.6%&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reserve p95, allow&lt;/td&gt;
&lt;td&gt;+7.9%&lt;/td&gt;
&lt;td&gt;98.7%&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reserve p95, truncate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+0.03%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;98.7%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That 0.03% isn't a rounding error, and I didn't want to hide it. It is the tokens a provider&lt;br&gt;
generates between the gateway closing the connection and the provider noticing: a chunk or two&lt;br&gt;
sitting in a TCP buffer. The benchmark only catches them because ground truth is what the &lt;em&gt;mock&lt;br&gt;
upstream&lt;/em&gt; says it generated, not what the gateway thinks it forwarded. A real provider bills the&lt;br&gt;
former.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two kinds of "no"
&lt;/h2&gt;

&lt;p&gt;Reservations created a problem I didn't expect. A tenant with 900 tokens left, all held by&lt;br&gt;
in-flight requests, is in a different position from a tenant whose 900 tokens are &lt;em&gt;spent&lt;/em&gt;. The&lt;br&gt;
first will have room again in a second; the second has to wait for the window to reset. Return&lt;br&gt;
the same error for both and clients either give up too early or retry a spent budget forever.&lt;/p&gt;

&lt;p&gt;So the admission script checks one more thing when it rejects: &lt;em&gt;would this fit if nothing were in&lt;br&gt;
flight?&lt;/em&gt; If yes, it answers &lt;code&gt;budget_busy&lt;/code&gt; with &lt;code&gt;Retry-After: 1&lt;/code&gt;; if no, &lt;code&gt;budget_exceeded&lt;/code&gt; with the&lt;br&gt;
time until the window resets.&lt;/p&gt;

&lt;h2&gt;
  
  
  When a replica dies mid-stream
&lt;/h2&gt;

&lt;p&gt;Reservations are only safe if they can't leak. Each one is stored with an expiry. A live stream&lt;br&gt;
refreshes it, and the next admission for that tenant reclaims any that expired. If a replica&lt;br&gt;
crashes, its tenants get their held budget back after the TTL (two minutes by default). The&lt;br&gt;
benchmark checks this too: across every run, &lt;strong&gt;0 reserved tokens were left behind&lt;/strong&gt; once traffic&lt;br&gt;
stopped.&lt;/p&gt;

&lt;p&gt;What it can't recover is the &lt;em&gt;usage&lt;/em&gt; of the streams that died with it. The provider billed those&lt;br&gt;
tokens and the gateway never learned the count. That's in the limitations section of the README,&lt;br&gt;
because it's a real gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs
&lt;/h2&gt;

&lt;p&gt;Two Redis round trips per request, plus a small extension call every 64 tokens. Through the full&lt;br&gt;
path (auth, rate limit, reservation, settlement, Prometheus metrics), measured open-loop on one&lt;br&gt;
laptop:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Load&lt;/th&gt;
&lt;th&gt;Added p50&lt;/th&gt;
&lt;th&gt;Added p99&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1,000 req/s&lt;/td&gt;
&lt;td&gt;+1.1 ms&lt;/td&gt;
&lt;td&gt;+1.2 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2,500 req/s&lt;/td&gt;
&lt;td&gt;+1.6 ms&lt;/td&gt;
&lt;td&gt;+3.2 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,000 req/s, streaming&lt;/td&gt;
&lt;td&gt;+1.9 ms&lt;/td&gt;
&lt;td&gt;+3.0 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For calls that take hundreds of milliseconds to seconds, that's noise. It isn't free at the top&lt;br&gt;
end: five Python workers saturate somewhere between 2,500 and 5,000 req/s on my machine, and the&lt;br&gt;
knee moved between runs. Profiling showed about 65% of the handler's CPU going to the Redis&lt;br&gt;
client's pure-Python protocol code. Switching to its C parser (&lt;code&gt;hiredis&lt;/code&gt;) moved one worker's limit&lt;br&gt;
from about 1,300 to over 1,600 req/s. If raw throughput were the goal, the hot path would be Go. It&lt;br&gt;
wasn't: the goal was a budget that holds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failover, briefly
&lt;/h2&gt;

&lt;p&gt;A budget gateway also has to route around a failing provider. With a primary → secondary route at&lt;br&gt;
200 streaming req/s:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary returns 503 for seven seconds:&lt;/strong&gt; 0 of 4,000 requests failed, and p99 latency didn't
move.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Primary process killed with SIGKILL:&lt;/strong&gt; 26 of 4,000 failed. Every one of them was a stream
already in flight on the killed process. Once bytes have reached the client, no gateway can
retry transparently. Every request sent after the kill succeeded.&lt;/li&gt;
&lt;/ul&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%2F17hd86sutwkxw3fa9nhc.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%2F17hd86sutwkxw3fa9nhc.png" alt="Failover timeline" width="799" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug the live test found
&lt;/h2&gt;

&lt;p&gt;The benchmarks use a mock upstream, because measuring overshoot exactly needs ground truth. Before&lt;br&gt;
release I also ran the same paths against a real API (Groq, &lt;code&gt;gpt-oss-20b&lt;/code&gt;). Ledger charges&lt;br&gt;
matched the provider's reported usage to the token, on unary and streaming calls. The truncation&lt;br&gt;
check failed: a stream on a 60-token output budget ran to &lt;strong&gt;400&lt;/strong&gt; billed tokens.&lt;/p&gt;

&lt;p&gt;The model was a reasoning model. Reasoning models stream their thinking in a separate&lt;br&gt;
&lt;code&gt;delta.reasoning&lt;/code&gt; field before any &lt;code&gt;delta.content&lt;/code&gt; appears, and Hardcap counted only &lt;code&gt;content&lt;/code&gt;.&lt;br&gt;
For the whole reasoning phase, the gateway saw zero tokens. It never asked to extend the&lt;br&gt;
reservation and never cut the stream, so the budget was right back to "count it afterwards".&lt;br&gt;
The mock upstream couldn't catch this: it only ever sent &lt;code&gt;content&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The fix counts every delta the provider bills for: &lt;code&gt;reasoning&lt;/code&gt;, &lt;code&gt;reasoning_content&lt;/code&gt;, Anthropic&lt;br&gt;
&lt;code&gt;thinking&lt;/code&gt; blocks and tool-call arguments. Rerun: truncated after 49 tokens. The lesson&lt;br&gt;
generalizes. &lt;strong&gt;Any part of the output the gateway doesn't count is output with no budget.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell someone building this
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Measure overshoot against the provider, not your ledger.&lt;/strong&gt; In my runs the ledger and the
upstream agreed to within 40 tokens, but only checking the upstream told me that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The estimator matters more than the locking.&lt;/strong&gt; Atomic Redis scripts are the easy part.
Reserving the right amount decides whether you leave 4% of the budget unusable or 1.3%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split "busy" from "spent".&lt;/strong&gt; It's one extra comparison, and it decides whether clients can
behave sensibly.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Publish the uncomfortable numbers.&lt;/strong&gt; Where it saturates, what a crash loses, which estimate&lt;br&gt;
the benchmark doesn't test (input tokens, counted with a heuristic that the mock upstream&lt;br&gt;
shares). A benchmark that only shows wins doesn't tell anyone much.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test against a real provider, even when the mock is the better benchmark.&lt;/strong&gt; The mock gave&lt;br&gt;
exact ground truth, and it also shared my assumptions about what a stream looks like.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Everything here reproduces with one command per benchmark. The raw JSON, the machine specs and the&lt;br&gt;
parameters are committed next to the charts:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://github.com/saikirankalidindi/hardcap" rel="noopener noreferrer"&gt;github.com/saikirankalidindi/hardcap&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>opensource</category>
      <category>python</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Mastering Python: Best Practices for Beginners and Advanced Developers</title>
      <dc:creator>Saikiran Kalidindi</dc:creator>
      <pubDate>Fri, 12 Apr 2024 07:27:48 +0000</pubDate>
      <link>https://dev.to/saikirankalidindi/mastering-python-best-practices-for-beginners-and-advanced-developers-2pif</link>
      <guid>https://dev.to/saikirankalidindi/mastering-python-best-practices-for-beginners-and-advanced-developers-2pif</guid>
      <description>&lt;p&gt;Python has established itself as a cornerstone of modern software development, powering everything from web applications to data science projects. Whether you're just starting your Python journey or have been coding in Python for years, adhering to best practices is essential for writing clean, efficient, and maintainable code. In this article, we'll explore some key practices that both beginners and advanced developers should follow to elevate their Python skills to the next level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. PEP 8: The Style Guide&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Python community values readability and consistency, and the Python Enhancement Proposal 8 (PEP 8) lays out the official style guide for Python code. Adhering to PEP 8 ensures that your code is easy to understand and maintain by yourself and others. Some key points from PEP 8 include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use 4 spaces for indentation.&lt;/li&gt;
&lt;li&gt;Limit lines to 79 characters.&lt;/li&gt;
&lt;li&gt;Use clear, descriptive variable names.&lt;/li&gt;
&lt;li&gt;Follow consistent naming conventions (e.g., snake_case for functions and variables, CamelCase for classes).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example of adhering to PEP 8
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_average&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers_list&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="n"&gt;numbers_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&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;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers_list&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;average&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Virtual Environments&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Virtual environments are essential for managing dependencies and isolating project environments. Tools like &lt;code&gt;venv&lt;/code&gt; or &lt;code&gt;virtualenv&lt;/code&gt; allow you to create separate environments for each project, preventing conflicts between different versions of libraries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a virtual environment&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv my_project_env

&lt;span class="c"&gt;# Activate the virtual environment&lt;/span&gt;
&lt;span class="nb"&gt;source &lt;/span&gt;my_project_env/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Use List Comprehensions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;List comprehensions are a concise and elegant way to create lists in Python. They improve readability and can often be more efficient than traditional loops.&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="c1"&gt;# Traditional loop
&lt;/span&gt;&lt;span class="n"&gt;squares&lt;/span&gt; &lt;span class="o"&gt;=&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="nf"&gt;range&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="n"&gt;squares&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&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="c1"&gt;# List comprehension
&lt;/span&gt;&lt;span class="n"&gt;squares&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&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="nf"&gt;range&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Embrace Pythonic Idioms&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Python has its own set of idioms and patterns that make code more idiomatic and expressive. For example, leveraging context managers with the &lt;code&gt;with&lt;/code&gt; statement for resource management or using &lt;code&gt;enumerate()&lt;/code&gt; for iterating over a sequence while keeping track of the index.&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="c1"&gt;# Using context managers
&lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;file.txt&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;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Using enumerate
&lt;/span&gt;&lt;span class="n"&gt;fruits&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;apple&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;banana&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;cherry&lt;/span&gt;&lt;span class="sh"&gt;'&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;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fruit&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fruits&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;Index &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;fruit&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Documentation Matters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Clear and concise documentation is crucial for understanding how your code works and how others can use it. Use docstrings to document modules, classes, functions, and methods following the &lt;a href="https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings"&gt;Google Python Style Guide&lt;/a&gt;.&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="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Greets the user with the given name.

    Args:
        name (str): The name of the user.

    Returns:
        str: A greeting message.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&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;Hello, &lt;/span&gt;&lt;span class="si"&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;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Unit Testing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Writing automated tests ensures the correctness of your code and makes it easier to refactor and maintain. Python's built-in &lt;code&gt;unittest&lt;/code&gt; module and third-party libraries like &lt;code&gt;pytest&lt;/code&gt; provide powerful tools for writing and running tests.&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;unittest&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;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&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;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestAddFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unittest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestCase&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;test_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertEqual&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;1&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="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertEqual&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="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="mi"&gt;1&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7. Continuous Integration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Integrating continuous integration (CI) into your workflow ensures that your code is automatically tested whenever changes are made. Services like GitHub Actions, Travis CI, or CircleCI can be used to set up CI pipelines for your projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By following these best practices, both beginners and advanced Python developers can write code that is not only functional but also clean, readable, and maintainable. Remember, the journey to mastering Python is ongoing, and continuously learning and applying these best practices will help you become a more proficient Pythonista. 🐍💻🚀&lt;/p&gt;

</description>
      <category>python</category>
      <category>beginners</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
