فصل ۷: ماژول‌ها، کتابخانه‌ی استاندارد و شیءگرایی

random، secrets و itertools

تصادف، امنیت و ترکیب‌های هوشمند

سه ماژول کوچک از کتابخانه‌ی استاندارد که تقریباً در هر پروژه‌ای به کار می‌آیند، و یکی از آن‌ها اگر اشتباه انتخاب شود، حفره‌ی امنیتی می‌سازد.

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 در قرعه‌کشی‌های واقعی جشنواره‌ی فروش.

برای ذخیره‌ی پیشرفت و شرکت در آزمون، وارد شوید — رایگان است.