Rate Limit per User ID in Python with a Dict Mock
Implements a simple sliding window rate limiter using a defaultdict of timestamps per user ID, blocking requests that exceed a max count within a time window.
Python code
38 linesimport time
from collections import defaultdict
class RateLimiter:
def __init__(self, max_requests, window_seconds):
self.max_requests = max_requests
self.window_seconds = window_seconds
self.user_timestamps = defaultdict(list)
def allow_request(self, user_id):
now = time.time()
timestamps = self.user_timestamps[user_id]
while timestamps and timestamps[0] <= now - self.window_seconds:
timestamps.pop(0)
if len(timestamps) >= self.max_requests:
return False
timestamps.append(now)
return True
if __name__ == "__main__":
limiter = RateLimiter(max_requests=3, window_seconds=10)
test_requests = [
("alice", True),
("alice", True),
("alice", True),
("alice", False), # 4th request should be blocked
("bob", True), # different user not affected
]
for user_id, expected in test_requests:
result = limiter.allow_request(user_id)
print(f"user={user_id}, allowed={result}, expected={expected}")
Output
user=alice, allowed=True, expected=True
user=alice, allowed=True, expected=True
user=alice, allowed=True, expected=True
user=alice, allowed=False, expected=False
user=bob, allowed=True, expected=True
How it works
The defaultdict(list) stores a list of request timestamps for each user. time.time() returns the current epoch, and the while loop removes expired timestamps older than the window. The length of the remaining list determines if the request is allowed. This is a sliding window approach, not a fixed bucket, so it adjusts naturally as time passes. The code is intentionally simple for a mock, lacking persistence or thread safety.
Common mistakes
- Forgetting to remove old timestamps, causing false blocks.
- Using a global list instead of per-user mapping, blocking all users together.
- Assuming `time.time()` is monotonic; use `time.monotonic()` for production.
- Not handling key errors when using a plain dict instead of defaultdict.
Variations
- Use `collections.deque` with `popleft()` for O(1) removal instead of `pop(0)`.
- Use a fixed window counter with reset instead of sliding window for simpler logic.
Real-world use cases
- Limiting API calls from a single user to prevent abuse or overuse.
- Throttling login attempts per account to slow down brute-force attacks.
- Capping the number of file uploads per customer within a time period.
Sponsored
More from Reliability & rate limiting
- At Least Once with Idempotent Consumer in Python medium
- Build a Rate Limiter Decorator in Python easy
- Build a queue-based admission control system in Python easy
- Chaos Inject Random Failures in Python easy
- Circuit breaker failure threshold count in Python medium
- Exactly Once Processing Dedupe Mock in Python easy
Keep learning
Related tutorials and quizzes for this topic.