تصادف، امنیت و ترکیبهای هوشمند
سه ماژول کوچک از کتابخانهی استاندارد که تقریباً در هر پروژهای به کار میآیند، و یکی از آنها اگر اشتباه انتخاب شود، حفرهی امنیتی میسازد.
random: برای شبیهسازی و بازی
import random
random.seed(1403) # نتیجهی تکرارپذیر برای تست
print(random.randint(1, 6)) # عدد صحیح، هر دو سر شامل
print(random.random()) # float بین 0 و 1
print(random.choice(["لاکی", "سرمهای", "کرم"]))
print(random.sample(range(1, 101), 5)) # ۵ عدد یکتا
print(random.choices(["کاشان", "تبریز"], weights=[3, 1], k=5)) # وزندار، با تکرار
colors = ["لاکی", "سرمهای", "کرم"]
random.shuffle(colors) # درجا؛ None برمیگرداند
secrets: برای هر چیز امنیتی
مولد اعداد random «شبهتصادفی» و قابل پیشبینی است: با دیدن چند خروجی، میتوان بقیه را حدس زد. برای رمز عبور، کد تأیید پیامکی، توکن بازیابی رمز یا لینک دعوت، فقط از secrets استفاده کنید:
import secrets
import string
otp = "".join(secrets.choice(string.digits) for _ in range(6)) # کد تأیید ۶ رقمی
token = secrets.token_urlsafe(32) # توکن مناسب URL
api_key = secrets.token_hex(16) # ۳۲ کاراکتر هگز
alphabet = string.ascii_letters + string.digits
password = "".join(secrets.choice(alphabet) for _ in range(12))
print(secrets.compare_digest(token, token)) # مقایسهی امن در برابر حملهی زمانی
itertools: جعبهابزار پیمایش
| تابع | کار | مثال |
|---|---|---|
batched(it, n) | تکههای n تایی (3.12+) | ارسال پیامکها در دستههای ۱۰۰تایی |
pairwise(it) | جفتهای پشتسرهم | تغییر قیمت روزبهروز |
product(a, b) | ضرب دکارتی | همهی ترکیبهای رنگ و اندازه |
combinations(it, r) | ترکیبهای r تایی بدون ترتیب | جفترنگهای ممکن |
accumulate(it) | جمع تجمعی | فروش تجمعی ماهبهماه |
chain(a, b) | پشتسرهم کردن | پیمایش دو لیست بدون ساختن لیست سوم |
count(start) / islice | شمارندهی بیپایان / برش | تولید شمارهی سفارش |
from itertools import batched, pairwise, product, accumulate, groupby
phones = [f"0912{n:07}" for n in range(250)]
for batch in batched(phones, 100):
print(len(batch)) # 100، 100، 50
prices = [9_500_000, 9_800_000, 9_650_000]
changes = [b - a for a, b in pairwise(prices)] # [300000, -150000]
variants = list(product(["لاکی", "کرم"], ["۶ متری", "۹ متری"]))
monthly = list(accumulate([42, 17, 29])) # [42, 59, 88]
rows = sorted([("کاشان", "K1"), ("تبریز", "T1"), ("کاشان", "K2")])
for city, group in groupby(rows, key=lambda r: r[0]):
print(city, [code for _, code in group])
نکتههایی که کمتر کسی میداند
groupbyفقط عضوهای پشتسرهم با کلید یکسان را گروه میکند؛ بدون مرتبسازی قبلی، «کاشان» دو گروه جدا میشود. برای گروهبندی بدون مرتبسازی از defaultdict استفاده کنید.random.shuffle(x)چیزی برنمیگرداند؛x = random.shuffle(x)لیست را به None تبدیل میکند. برای نسخهی جدید:random.sample(x, len(x)).- گروههای groupby یکبار مصرفاند و با رفتن به گروه بعد از بین میروند؛ اگر لازمشان دارید، همانجا
list(group)کنید. random.seedرا در کد اصلی ثابت نگذارید؛ فقط در تستها. seed ثابت در تولید یعنی هر بار همان «تصادف».secrets.randbelow(n)عدد صحیح امن بین 0 و n-1 میدهد؛ جایگزین امنrandom.randintدر قرعهکشیهای واقعی جشنوارهی فروش.