05. MODUL · PYTHON

A random modul.

Véletlenszámok, választás, keverés

1. fejezet

Véletlen a programban

Dobókocka, lottósorsolás, kártyakeverés, egy ellenfél kiszámíthatatlan lépése egy játékban, szimuláció („mi történne 10 000 próbálkozás után?”) – mindegyikhez véletlenszám kell. A Python ehhez a random modult adja.

Modul, import

A modul egy kész, újrafelhasználható Python-fájl, amely függvényeket és értékeket tartalmaz. A Pythonhoz sok modul tartozik alapból (ez a standard könyvtár), de használat előtt be kell tölteni az import utasítással. Utána a modul függvényeit modul.függvény() alakban hívjuk: random.randint(1, 6).

import random

dobas = random.randint(1, 6)
print("A dobás:", dobas)

Futtasd többször egymás után: minden futás más eredményt adhat. A modul betöltésének másik formája a from random import randint – ilyenkor a függvényt modulnév nélkül hívjuk (randint(1, 6)). Kezdőknek az import random alak az átláthatóbb, mert mindig látszik, honnan jön a függvény.

2. fejezet

Mennyire véletlen? Álvéletlen számok és a mag

A számítógép determinisztikus gép: ugyanabból a kiindulásból mindig ugyanazt számolja ki. A random modul ezért álvéletlen (pszeudovéletlen) számokat ad: egy algoritmus egy kiinduló értékből – a magból (seed) – olyan számsorozatot állít elő, amely véletlennek tűnik, és statisztikailag úgy is viselkedik. Alapesetben a Python a magot az operációs rendszer véletlenforrásából veszi (ha az nem elérhető, az aktuális időből), ezért minden futás más.

Ha viszont mi adjuk meg a magot a random.seed() függvénnyel, a sorozat megismételhető: ugyanaz a mag ugyanazokat a „véletlen” számokat adja. Ez hibakeresésnél és tesztelésnél nagyon hasznos.

import random

for mag in [2026, 2026, 7]:
    random.seed(mag)
    print(f"mag = {mag}:", end=" ")
    for i in range(5):
        print(random.randint(1, 6), end=" ")
    print()

Biztonsági célra nem jó. Az álvéletlen sorozat elég sok ismert értékből kiszámítható. Jelszóhoz, tokenhez, nyereményjáték kódjához a secrets modul való (pl. secrets.randbelow(100), secrets.token_hex(8)). Játékhoz, szimulációhoz, gyakorláshoz a random tökéletes.

3. fejezet

Véletlenszámok: random(), randint(), randrange(), uniform()

FüggvényEredményPélda
random.random()valós szám, 0 ≤ x < 10.6394…
random.randint(a, b)egész, a ≤ x ≤ b – mindkét határ benne vanrandint(1, 6) → 1…6
random.randrange(a, b)egész, a ≤ x < b – mint a range()randrange(1, 7) → 1…6
random.randrange(a, b, lépés)a range(a, b, lépés) egy véletlen elemerandrange(0, 101, 10) → 0, 10, …, 100
random.uniform(a, b)valós szám a és b közöttuniform(36.0, 37.5)

A határok eltérnek. A randint(1, 6) a 6-ot is adhatja, a randrange(1, 6) nem – ez a range() logikáját követi.

Mit ír ki?

import random

hatosok = 0
for i in range(10000):
    if random.randrange(1, 6) == 6:
        hatosok += 1
print(hatosok)
  1. körülbelül 1667 (minden hatodik)
  2. 0
  3. körülbelül 2000 (minden ötödik)

A randrange(1, 6) a range(1, 6) egy elemét adja: 1, 2, 3, 4 vagy 5 – a 6-ot soha. Ezért a számláló 0 marad. Kockadobáshoz randint(1, 6) vagy randrange(1, 7) kell.

import random

print("random():", random.random())
print("kocka:", random.randint(1, 6))
print("páros szám 0 és 20 között:", random.randrange(0, 21, 2))
print("testhőmérséklet:", round(random.uniform(36.0, 37.5), 1))
x = random.random()
skala = 10 + x * 5
print(f"{x:.3f} átskálázva 10 és 15 közé: {skala:.3f}")

A random() 0 és 1 közötti értéke bármilyen tartományra átskálázható: ha 0 ≤ x < 1, akkor 10 ≤ 10 + 5x < 15. Az uniform(a, b) lényegében ezt csinálja.

Szimuláció: a nagy számok törvénye

Egy szabályos kockán minden szám valószínűsége 1/6. Néhány dobásnál ez egyáltalán nem látszik – sok dobásnál viszont az arányok egyre közelebb kerülnek az 1/6-hoz. Próbáld ki:

Ugyanez Pythonban: 6000 dobás gyakoriságai egy listában (a lista 0. eleme az 1-es dobások száma, és így tovább), majd szöveges oszlopdiagram:

import random

dobasok = 6000
gyakorisag = [0, 0, 0, 0, 0, 0]
for i in range(dobasok):
    d = random.randint(1, 6)
    gyakorisag[d - 1] += 1

for szam in range(1, 7):
    db = gyakorisag[szam - 1]
    arany = db / dobasok
    print(f"{szam}: {db:5} ({arany:6.1%}) " + "#" * (db // 40))

A {db:5} a számot 5 karakter szélesen, jobbra igazítva írja ki; a {arany:6.1%} százalékként, egy tizedesre, 6 karakter szélesen (0.1667 → 16.7%).

4. fejezet

Választás és keverés: choice(), shuffle(), sample()

FüggvényMit csinál?
random.choice(sorozat)egy véletlen elemet ad vissza (listából, tuple-ből, szövegből)
random.shuffle(lista)helyben összekeveri a listát; az eredménye None
random.sample(sorozat, k)k elemet húz visszatevés nélkül, új listában (ha a sorozat elemei különbözők, az eredmény elemei is)
random.choices(sorozat, k=…)k elem visszatevéssel (ismétlődhet)
import random

diakok = ["Anna", "Bence", "Csilla", "Dani", "Emese"]
print("Felel:", random.choice(diakok))
print("Párok sorsolásához keverés:")
random.shuffle(diakok)
print(diakok)
lotto = random.sample(range(1, 91), 5)
print("Lottószámok:", sorted(lotto))

Mit ír ki?

import random

lista = [3, 1, 2]
kevert = random.shuffle(lista)
print(kevert)
  1. a három szám valamilyen sorrendben, pl. [2, 3, 1]
  2. [3, 1, 2]
  3. None

A shuffle() a meglévő listát keveri össze helyben, és nem ad vissza semmit – vagyis None-t. A kevert sorrendet a lista változón keresztül látod. Ez sok Python-függvény mintája: ami helyben módosít, az nem ad vissza új értéket (a 6. modulban a sort()-nál is ezt látod).

Mit ír ki?

import random

szamok = random.sample(range(1, 91), 5)
print(len(set(szamok)))
  1. 5
  2. 1 és 5 közötti szám, a sorsolástól függően
  3. 90

A sample() visszatevés nélkül húz, ezért az öt szám garantáltan különböző – a halmazzá alakítás nem szűr ki semmit, a hossz mindig 5. A choices(…, k=5) esetén viszont lehetne ismétlődés.

5. fejezet

Kidolgozott példák: kő-papír-olló és kincskereső

Kő-papír-olló

A gép véletlenül választ, a nyertest feltételek döntik el. Figyeld meg a bemenet tisztítását: a strip() levágja a véletlen szóközöket, a lower() kisbetűssé alakít – így a „ Kő” is érvényes válasz.

import random

lehetosegek = ["kő", "papír", "olló"]
jatekos = input("Kő, papír vagy olló? ").strip().lower()
if jatekos not in lehetosegek:
    print("Ilyen lehetőség nincs.")
else:
    gep = random.choice(lehetosegek)
    print("A gép választása:", gep)
    if jatekos == gep:
        print("Döntetlen.")
    elif ((jatekos == "kő" and gep == "olló")
          or (jatekos == "papír" and gep == "kő")
          or (jatekos == "olló" and gep == "papír")):
        print("Nyertél!")
    else:
        print("Vesztettél.")

A hosszú feltételt egy külső zárójelbe tettük: zárójelen belül az utasítás nyugodtan folytatódhat a következő sorokban. (Zárójel nélkül a sor végi \ jelezné a folytatást, de a PEP 8 a zárójeles formát ajánlja.)

Kincskereső

Egy 5 × 5-ös rácson el van rejtve a kincs. A koordináták: x az oszlop (1 a bal szél, balról jobbra nő), y a sor (1 a felső sor, lefelé nő). A program minden tipp után megmondja az irányt; legfeljebb 6 próbálkozás van.

import random

kincs_x = random.randint(1, 5)
kincs_y = random.randint(1, 5)
megtalalta = False
probalkozas = 0

while probalkozas < 6 and not megtalalta:
    x = int(input("Oszlop (1–5): "))
    y = int(input("Sor (1–5): "))
    probalkozas += 1
    if x == kincs_x and y == kincs_y:
        megtalalta = True
    else:
        irany = ""
        if y < kincs_y:
            irany += "lejjebb "
        elif y > kincs_y:
            irany += "feljebb "
        if x < kincs_x:
            irany += "jobbra"
        elif x > kincs_x:
            irany += "balra"
        print("A kincs innen:", irany.strip())

if megtalalta:
    print(f"Megtaláltad {probalkozas}. próbálkozásra!")
else:
    print(f"Nem találtad meg. A kincs itt volt: oszlop {kincs_x}, sor {kincs_y}.")

Egy irányokat adó programnál előre rögzíteni kell, merre nő a koordináta – különben a „feljebb” és a „lejjebb” fordítva jelenhet meg. Az ilyen megállapodásokat mindig érdemes leírni: képernyőn és táblázatban az y (a sorszám) jellemzően lefelé nő, a matematikai koordináta-rendszerben felfelé.

6. fejezet

Gyakorló feladatok

A véletlen miatt itt a gép nem egy minta-kimenettel veti össze a tiédet, hanem azt ellenőrzi, hogy a kiírt számok megfelelnek-e a szabályoknak (jó tartományba esnek, stimmel az összeg, nincs ismétlődés stb.).

Dobássorozat

Kérd be, hányszor dobjunk a kockával, írd ki a dobásokat egy sorban (szóközzel elválasztva), majd a következő sorban az összegüket:

Hány dobás? 5
3 6 1 1 4
Összeg: 15
import random

n = int(input("Hány dobás? "))
osszeg = 0
for i in range(n):
    d = random.randint(1, 6)
    print(d, end=" ")
    osszeg += d
print()
print("Összeg:", osszeg)
Tipp

Összegzés minta (3. modul) + random.randint(1, 6). A dobásokat end=" "-vel írd egy sorba, utána egy üres print() zárja a sort.

Ötös lottó

Sorsolj 5 különböző számot 1 és 90 között, és írd ki őket növekvő sorrendben, egy sorban:

A nyerőszámok: 7 21 38 64 85
import random

szamok = sorted(random.sample(range(1, 91), 5))
print("A nyerőszámok:", *szamok)
Tipp

A random.sample(range(1, 91), 5) öt különböző számot ad; a sorted() rendezett listát készít belőle. A print(*szamok) a lista elemeit külön argumentumként, szóközzel elválasztva írja ki (a csillag „kicsomagol”) – de ciklussal is kiírhatod.

Dobj, amíg hatos nem jön

Dobj a kockával addig, amíg 6-ost nem dobsz. Minden dobást írj ki egy sorban, a végén pedig azt, hányadikra jött ki a hatos:

2 5 2 6
A hatos a(z) 4. dobásra jött ki.
import random

db = 0
d = 0
while d != 6:
    d = random.randint(1, 6)
    db += 1
    print(d, end=" ")
print()
print(f"A hatos a(z) {db}. dobásra jött ki.")
Tipp

Nem tudjuk előre, hány dobás kell: while ciklus. A d kezdőértéke olyan legyen, ami biztosan nem 6 (pl. 0), hogy legalább egyszer dobjunk.

Pénzfeldobás-statisztika

Kérd be, hányszor dobjunk fel egy pénzérmét (fej vagy írás egyforma eséllyel), és írd ki a fejek és az írások számát, valamint a fejek arányát százalékban egy tizedesjegyre:

Hány dobás? 1000
Fej: 507, írás: 493
Fejek aránya: 50.7%
import random

n = int(input("Hány dobás? "))
fej = 0
for i in range(n):
    if random.choice(["fej", "írás"]) == "fej":
        fej += 1
iras = n - fej
print(f"Fej: {fej}, írás: {iras}")
print(f"Fejek aránya: {fej / n * 100:.1f}%")
Tipp

Számlálás minta: fej 0-ról indul, és a ciklusban nő, ha fej jött ki (random.choice(…) vagy random.randint(0, 1)). Az írások száma: n - fej.

Csapatsorsolás

Olvass be neveket üres sorig, keverd össze őket véletlenszerűen, és oszd két csapatba: az első csapatba a kevert lista első fele kerüljön (páratlan létszámnál az első csapat a kisebb). Írd ki a két csapatot listaként:

Név (üres = vége): Anna
…
Név (üres = vége): 
1. csapat: ['Dani', 'Anna', 'Feri']
2. csapat: ['Emese', 'Csilla', 'Bence']
import random

nevek = []
nev = input("Név (üres = vége): ")
while nev != "":
    nevek.append(nev)
    nev = input("Név (üres = vége): ")
random.shuffle(nevek)
fele = len(nevek) // 2
print("1. csapat:", nevek[:fele])
print("2. csapat:", nevek[fele:])
Tipp

Végjelig olvasás üres szöveggel (nev != ""), majd random.shuffle(nevek). A fele: len(nevek) // 2; az első csapat nevek[:fele], a második nevek[fele:].

7. fejezet

Összefoglalás

EszközLényeg
import randoma modul betöltése; hívás: random.függvény()
random.seed(n)megismételhető sorozat; álvéletlen – biztonsági célra a secrets
randint(a, b)egész a és b között, mindkét határt beleértve
randrange(a, b, lépés)mint a range(): a b már nem lehet
random(), uniform(a, b)valós szám [0, 1) illetve [a, b] között
choice, sample, shuffleegy elem; k különböző elem; helyben keverés (eredménye None)

Gyakorold tovább: szimuláld két kocka dobását 10 000-szer, és számold meg, hányszor lett az összeg 7. Az elméleti valószínűség 6/36 = 1/6 ≈ 16,7% – mennyire közelíti a mérésed? Melyik összeg a legritkább, és miért?