Pythonでユーザーのレート制限チェックに対応したデータ構造を実装する方法
問題の概要
今回は、「有効期限(expire)」を持つデータ構造を作り、ユーザーIDとタイムスタンプを受け取って、そのリクエストを許可するか拒否するかを判定する機能を実装します。リクエストが拒否されるのは、対象ユーザーの直近の成功リクエストから経過した時間が、設定された有効期限以内である場合のみです。
例えば、expire = 6 としてオブジェクト obj を生成し、次の順番でメソッドを呼び出した場合の出力を見てみましょう。
obj.limit(0, 10)→ False:ユーザー0の初回リクエストであり、履歴がないため許可されるobj.limit(0, 16)→ False:前回のリクエスト(時刻10)からの経過時間が6で、有効期限以内のため許可されるobj.limit(0, 17)→ True:前回(時刻10)からの経過時間が7となり、有効期限6を超えたため拒否されるobj.limit(1, 20)→ False:ユーザー1の初回リクエストのため許可される
解決のアプローチ
この問題は、各ユーザーの「直近の成功リクエスト時刻」を記録しておくことで解決できます。具体的には以下の手順で実装します。
- コンストラクタ
__init__()を定義し、有効期限expireを受け取る lastCall:= デフォルト値が-1の辞書を作成する(まだリクエストしていないユーザーの初期値として使う)limit()関数を定義し、引数としてuidとtimestampを受け取るlast:=lastCall[uid](該当ユーザーの前回リクエスト時刻)を取得する- もし
lastが-1(初回リクエスト)または(last + expire) <= timestamp(有効期限が切れている)の場合:
・lastCall[uid] := timestampを更新する
・Falseを返す(リクエスト許可) - それ以外は
Trueを返す(リクエスト拒否=レート制限発動)
ここでポイントになるのが defaultdict(lambda: -1) の使い方です。通常の辞書では存在しないキーへのアクセスでエラーが発生しますが、defaultdict を使えば未登録のユーザーに対しても自動的に初期値 -1 が返るため、コードをシンプルに保てます。
実装例
それでは、実際のコードを見てみましょう。
from collections import defaultdict class RateLimit: def __init__(self, expire): self.expire = expire self.lastCall = defaultdict(lambda: -1) def limit(self, uid, timestamp): last = self.lastCall[uid] if last == -1 or last + self.expire <= timestamp: self.lastCall[uid] = timestamp return False return True expire = 6 obj = RateLimit(expire) print(obj.limit(0,10)) print(obj.limit(0,16)) print(obj.limit(0,17)) print(obj.limit(1,20))
入力
RateLimit(6) obj.limit(0,10) obj.limit(0,16) obj.limit(0,17) obj.limit(1,20)
出力
False False True False
まとめ
この実装では、辞書による記録管理により、リクエストごとの判定処理を O(1) の計算量で実現しています。また、成功したリクエスト時だけタイムスタンプを更新する仕組みになっているため、「拒否されたリクエストは直近の成功時刻に影響しない」という要件も正しく満たしています。APIのアクセス制御やスパム対策など、実務におけるレートリミット処理の基礎として応用できるパターンです。
-
Pythonで単利を計算するプログラムの作成方法
この記事では、Python 3.x(およびそれ以前のバージョン)を使用して、単利を計算する方法について解説します。単利とは、元本に対して一定の利率で発生する利息のことです。一般的には、利率に元本を掛け、さらに利息が発生する期間を掛けることで求められます。単利の計算式単利は数学的に以下の式で表すことができます。単利(SI) = (P × T × R) / 100 P:元本(Principal) T:期間(Time) R:利率(Rate)例えば、元本 P = 1000、利率 R = 1%、期間 T = 2 の場合、単利は次のように計算されます。SI = (1000 × 1 × 2) / 100
-
Pythonで選択ソートを実装する方法|仕組みとサンプルコードをわかりやすく解説
この記事では、選択ソート(Selection Sort)の基本的な仕組みと、Python 3.x(およびそれ以前のバージョン)での実装方法について解説します。 選択ソートとは 選択ソートは、ソートされていない部分から最小の要素を繰り返し見つけ出し、先頭側へ移動させることで配列全体を整列していくアルゴリズムです。処理の過程で、対象の配列は次の2つの部分配列に分けられます。 すでにソートが完了している部分配列 まだソートされていない部分配列 選択ソートの各イテレーションでは、未ソートの部分配列から最小要素を取り出し、ソート済みの部分配列の末尾に追加していきます。 アルゴリズムの動作イメー