A Scratch és a Python összehasonlítása

Kategória: Python gyerekeknek.

Áttekintés

Melyik a jobb: a Scratch vagy a Python?

Erre a kérdésre egyelten helyes válasz létezik: attól függ! A Pythonban mindent meg lehet valósítani, amit a Scratchben, és még sokkal többet, így adódna a nyilvánvaló válasz, hogy a Python jobb, mint a Scratch. Ez igaz is lenne az esetek egy jó részében. Ám érdemes azt is figyelembe venni, hogy Scratchben már az első alkalommal játékot készítettünk, és minden egyes alkalommal más-más játékok kerültek terítékre. A Pythonban csak az "építőkockák" ismertetésére annyi időt kel szánni, mint a teljes Scratch tanfolyamra, és csak ezt követően lehet elkezdeni a játék készítését, ami el fog tartani egy jó pár alkalommal. Ilyen értelemben viszont sokkal jobb a Scratch. Ráadásul vannak olyan műveletek (pl. ütközésvizsgálat, vagy az, hogy "ha szélen vagy, pattanj vissza"), melyeket nagy nagyon nehéz megvalósítani Pythonban. A Scratch-ben vannak szereplők, azoknak vannak jelmezeik, és a szereplők mozgatása is sokkal jobban megvalósított, mint a Pythonban. A párhuzamosítás a programozási nyelvek egyik "rákfenéje", Scratch-ben viszont ez alapból benne van.

A Scratch tehát rendkívül gyorsan tanulható. Ugyanakkor elég gyorsan elérjük a lehetőségek felső határát. Néhány szereplő egy-egy oldalnyi kódja már bővel elég, egyre nehezebben karbantartható, míg a valóságban a programok ennek a nagyon sokszorosai. Sok hasznos művelet nincs a Scratch-ben megvalósítva: nincs például nagybetűsítés, nem lehet listákat rendezni, nincs szótár adattípus stb. A Scratch-et nem lehet modularizálni. Hiányoznak a jó külső könyvtárak. Nem tudjuk ott alkalmazni az olyan hasznos programozási technikákat, mint pl. az objektumorientáltság, a funkcionális programozás vagy a folyamok kezelése. A Scratch nem tud adatokat kívülről olvasni vagy akárhova kiírni, így adatfeldolgozásra is alkalmatlan. Ám tökéletesen alkalmas a Scratch arra, hogy a Python irányába tett nagy lépést két kisebb lépésre ossza fel.

Ezen az oldalon részletesebben megnézzük a hasonlóságokat és különbségeket. Ez az oldal elsősorban azoknak készült, akik ismerik a Scratch-et, és meg szeretnének ismerkedni a Pythonnal. Az első részben végigvesszük a Scratch lehetőségeit, és megnézzük, hogy ugyanaz hol található Pythonban. Utána pedig megnézzük, hogy a Pythonban hova lehet fejlődni, a Scratch-en túl.

Az oldal célja

Az első ötletem az volt, hogy készítek egy táblázatos összefoglalót: ami a Scratch-ben ez, a Pythonban az. Elég gyorsan rájöttem arra, hogy ez ebben a formában nem fog menni. Három ponton is megvágtam az eredeti elképzelést:

  • Scratch-ben egy-egy utasítás komplett programrészeket jelent Pythonban, ráadásul nagyon nehéz kiragadni a környezetéből. Gondoljunk pl. erre: "ha szélen vagy, pattanj vissza". Ennek hatására eleve lemondtam arról, hogy utasítás szintjén keressem a két nyelv megfelelőit, helyette nagyobbrészt rövidebb kódrészleteket vettem.
  • Az előzőt folytatva: arról is elég gyorsan letettem, hogy pontosan ugyanazt adjam Pythonban mint Scratch-ben, mert az az érthetőség rovására ment volna. Pl. Scratch-ben kiírni nehézkes, emiatt úgy döntöttem, hogy a kiírást a szereplő "mondd" utasításával helyettesítem. Csakhogy ennek megvalósítása elég összetett lenne Python-ban: kell hozzá TK grafikus felület, kell szereplő, rajzolni kell megfelelő ábrát, ahova a szöveget kell írni, és ha mindezt pl. a feltételkezelés illusztrálására használnánk, akkor elveszne a lényeg. Emiatt úgy döntöttem, hogy az "ugyanaz" fogalom helyett a "neki leginkább megfelelő" fogalmat használom; számos esetben kellően lazán kezelve ezt, az érthetőséget szem előtt tartva. Számos esetben egyszerűsítettem a problémát Pythonban, pl. két szereplő érintésvizsgálata kevésbé precíz Pythonban, mint Scratch-ben.
  • Arról is elég gyorsan le kellett mondanom, hogy minden Scratch utasításnak megkeressem a Python párját. Nagyon sok idő menne el - valójában feleslegesen - azzal, hogy minden aprósághoz keressek Python könyvtárat: a kamera kezeléshez, a mikrofon kezeléshez, zene lejátszáshoz stb. Ugyanis a Python alapvetően nem ezekre lett kitalálva, nagyon speciális szelete a Python fejlesztésnek az ilyesmi; nemhogy egy fél éves, éves, gyerekeknek szóló kurzuson nem jutunk el ilyen szintre, de még a professzionális Python fejlesztők többsége sem. Szükség esetén utána lehet persze járni, de egy ilyen alapozó leírásból kihagytam. Ugyancsak kimaradtak a különböző külső eszközök vezérlései: LEGO Mindstorms, micro:bit stb.

Persze voltak részek, amelyek egész jól táblázatba voltak szervezhetőek, pl. műveletek; ott éltem ezzel a lehetőséggel. Összefoglalva:

  • a Scratch utasításainak csak kb. a kétharmadát ültettem át Pythonba,
  • pontos megfeleltetés helyett a neki leginkább megfelelő utasításokat vettem figyelembe,
  • legkisebb logikai egységként sok esetben nem egy-egy utasítást, hanem működő kódrészletet vettem.

Az oldalt leginkább referenciaként célszerű használni.

A Scratch felől

A Pythonnak és a Scratch-nek a következőkben alapvetően eltérő a filozófiája:

  • A Scratch-ben van egy fix méretű vászon, míg a Pythonban ilyen nincs, ezt külön létre kell hozni. Ráadásul ez nem "beépített", ahhoz az ún. TK könyvtárat kell használni.
  • A Scratch-ben vannak szereplők, a Pythonban nincsenek. Az utóbbit leginkább úgy lehet elképzelni, mintha a Scratch-ben minden kód egy fix helyen, mondjuk a háttéren lenne.
  • A Scratch-ben az egyes szereplők programja párhuzamosan fut, ráadásul egy szereplőnek egyszerre több programja is lehet, amelyek szintén párhuzamosan futnak. Pythonban alapból összesen egy főprogram van. A párhuzamosságot vagy szimuláljuk, vagy ún. szálakat (thread) használunk.

Mozgás

Szereplők mozgatása Pythonban a TK vásznon lényegesen bonyolultabb, mint a Scratch-ben. Néhány lényeges különbség a Scratch vászon és a TK vászon között:

  • A Scratch-ben a vászon közepén van a (0, 0) pont, míg TK-ban a vászon bal felső sarkában.
  • A Scratch-ben az y koordináta fentről lefelé csökken (180-ról -180-ra), míg TK-ban fentről lefelé növekszik (0-ról a vászon függőleges méretéig).
  • A Scratch-ben az irányt fokokban számítjuk. A Pythonban (ez tehát Python tulajdonság, nem TK) radiánban.
  • A Scratch-ben forgásnál a pozitív irány az óramutató járásával megegyező, Pythonban pedig (ahogy általában a matematikában) azzal ellentétes.
  • A Scratch-ben a 0 fok felfelé mutat, a Pythonban jobbra.
  • A Scratch-ben a szereplők forgatása alapművelet. A Pythonban annyira nem az, hogy még a TK sem tudja alapból, ahhoz a Pillow nevű külső könyvtárat kell használnunk. Ráadásul Python-ban nem is lehet szereplőket forgatni, hanem a forgatást úgy lehet csak szimulálni, hogy letöröljük a korábbit, és újra kirajzoljuk.
  • A Scratch-ben tudjuk a szereplőket abszolút pozícióba mozgatni, míg TK-ban csak a változást tudjuk megadni.

Ennyi koncepcionális eltérésnél nem igazán érdemes olyan táblázatot készíteni, ami a Scratch parancsok Python megfelelőit tartalmazza, ugyanis annak csak megfelelően beültetett programrészletek feleltethetőek meg. Emiatt inkább néhány gyakoribb kódrészletet nézünk meg Scratch-ben és Pythonban.

A példákhoz szükség lesz egy képre. Töltsük le az alábbit:

scratch_cat.png

Ha jobban szemügyre vesszük, akkor láthatjuk, hogy alul,, felül, jobb és bal oldalon is van egy üres sáv. Erre a forgatás miatt van szükség: hogy elfogatva is kiférjen.

Szereplő mozgatása jobbra, balra, előre, hátra

Az egyik leggyakoribb Scratch program váza az alábbi:

scratch_mozgat.png

Ennek többé-kevésbé megfelelő Python kód:

from tkinter import *
 
def key_pressed(event):
    scratch_cat_coord = canvas.coords(scratch_cat)
    if event.keysym == 'Left' and scratch_cat_coord[0] > 50:
        canvas.move(scratch_cat, -5, 0)
    if event.keysym == 'Right' and scratch_cat_coord[0] <= 430:
        canvas.move(scratch_cat, 5, 0)
    if event.keysym == 'Up' and scratch_cat_coord[1] > 50:
        canvas.move(scratch_cat, 0, -5)
    if event.keysym == 'Down' and scratch_cat_coord[1] <= 310:
        canvas.move(scratch_cat, 0, 5)
 
root = Tk()
canvas = Canvas(master=root, width=480, height=360, bg='white')
canvas.pack()
scratch_cat_image = PhotoImage(file='scratch_cat.png')
scratch_cat = canvas.create_image(240, 180, image=scratch_cat_image)
root.bind('<KeyPress>', key_pressed)
root.mainloop()

Magyarázat:

  • from tkinter import *: betöltjük a TK komponenseket.
  • root = Tk(): létrehozzuk a TK programot.
  • canvas = Canvas(master=root, width=480, height=360, bg='white'): létrehozunk egy akkora fehér vásznat, amekkora a Scratch-ben van.
  • canvas.pack(): láthatóvá tesszük a vásznat. (Sajnos sok ehhez hasonló felesleges kódot kell írni.)
  • scratch_cat_image = PhotoImage(file='scratch_cat.png'): betöltjük a képet. Ne feledjük: alapból a Pythonban nincsenek szereplők, azokat be kell tölteni. Gondoskodjunk arról, hogy a kép megfelelő könyvtárban legyen.
  • scratch_cat = canvas.create_image(240, 180, image=scratch_cat_image): ezzel létre hozzuk a létható képet. Tehát az előző magára a png képre hivatkozik, ez pedig arra, ami a vásznon látszik.
  • root.bind('<KeyPress>', key_pressed): ezzel mondjuk meg azt, hogy mi történjen billentyű lenyomáskor.
  • root.mainloop(): enélkül néha működik, néha nem, így ki kell írni.
  • def key_pressed(event):: ez fut le billentyű lenyomáskor.
  • scratch_cat_coord = canvas.coords(scratch_cat): lekérdezi a macska aktuális koordinátáit. Erre amiatt van szükség, hogy megállapítsuk, elérte-e a szélét. Erre a Scratch-ben nem volt szükség, viszont egyben példát mutat arra, hogy hogyan tudjuk a szereplő koordinátáit (Scratch-ben: "x-hely", "y-hely") lekérdezni.
  • if event.keysym == 'Left' and scratch_cat_coord[0] > 50:: ha a bal gomb van lenyomva, és az x koordináta nagyobb mint 50.
  • canvas.move(scratch_cat, -5, 0): a vízszintes tengelyen -5 képpontnyit mozgassuk, a függőleges tengelyen pedig 0 képpontnyit.
  • A következő 6 sor a jobbra, fel ill. le mozgatás.

Szereplő forgatása és mozgatása

Tekintsük a következő programot, melyben a szereplőt jobbra-balra forgathatjuk, valamint előre-hátra mozgathatjuk:

scratch_fordulj.png

Szereplőt forgatni Pythonban nem lehet. A megoldás a következő: le kell törölni a korábbit, és újra ki kell rajzolni. Kép esetén ez annyiban más, hogy magát a képet kell elforgatni, majd letörölni és újra kirajzolni, csakhogy képet alapból sem a Python, sem a TK nem tud, ahhoz egy külső könyvtárat kell használnunk. Adjuk ki Pythonon kívül az alábbi parancsot:

pip install Pillow

Ezzel feltelepítjük az Pillow csomagot, amit felhasználunk a kép forgatásához. Sajnos sokkal rosszabb eredményt ad, mint a Scratch, így nem is azt fogjuk csinálni, hogy forgatjuk, majd a forgatottat forgatjuk tovább, hanem minden lépésben kiszámoljuk, hogy a kezdeti állapotból mennyit kell forgatni, és mindig a kezdő képet forgatjuk. Az eredmény így is csúnya, de legalább nem annyira.

Az eredmény egészen elképesztően bonyolult lett:

import math
from tkinter import *
from PIL import Image, ImageTk # pip install Pillow
 
def is_within_canvas(new_x, new_y):
    return new_x >= scratch_cat_size / 2 \
        and new_x <= canvas_width - scratch_cat_size / 2 \
        and new_y >= scratch_cat_size / 2 \
        and new_y <= canvas_height - scratch_cat_size / 2
 
def bounce(new_x, new_y):
    if new_x < scratch_cat_size / 2:
        rotate_image(-2 * (scratch_cat_rotate_degrees - 90))
    elif new_x > canvas_width - scratch_cat_size / 2:
        rotate_image(-2 * (scratch_cat_rotate_degrees - 90))
    if new_y < scratch_cat_size / 2:
        rotate_image(-2 * scratch_cat_rotate_degrees)
    elif new_y > canvas_height - scratch_cat_size / 2:
        rotate_image(-2 * scratch_cat_rotate_degrees)
 
def key_pressed(event):
    if event.keysym in ['Up', 'Down']:
        scratch_cat_rotate_radians = math.radians(scratch_cat_rotate_degrees)
        steps_a = speed * math.sin(scratch_cat_rotate_radians)
        steps_b = speed * math.cos(scratch_cat_rotate_radians)
        scratch_cat_coord = canvas.coords(scratch_cat)
        if event.keysym == 'Up':
            new_x = scratch_cat_coord[0] + steps_b
            new_y = scratch_cat_coord[1] - steps_a
            if is_within_canvas(new_x, new_y):
                canvas.move(scratch_cat, steps_b, -steps_a)
            else:
                bounce(new_x, new_y)
        if event.keysym == 'Down':
            new_x = scratch_cat_coord[0] - steps_b
            new_y = scratch_cat_coord[1] + steps_a
            if is_within_canvas(new_x, new_y):
                canvas.move(scratch_cat, -steps_b, steps_a)
            else:
                bounce(new_x, new_y)
    if event.keysym == 'Left':
        rotate_image(15)
    if event.keysym == 'Right':
        rotate_image(-15)
 
def rotate_image(degrees, first_run = False):
    global scratch_cat_image
    global scratch_cat_tkimage
    global scratch_cat_rotate_degrees
    global scratch_cat
    scratch_cat_rotate_degrees = scratch_cat_rotate_degrees + degrees
    scratch_cat_image_rotated = scratch_cat_image.rotate(scratch_cat_rotate_degrees)
    scratch_cat_tkimage = ImageTk.PhotoImage(scratch_cat_image_rotated)
    scratch_cat_coords_x = canvas_width/2
    scratch_cat_coords_y = canvas_height/2
    if not first_run:
        scratch_cat_coords = canvas.coords(scratch_cat)
        scratch_cat_coords_x = scratch_cat_coords[0]
        scratch_cat_coords_y = scratch_cat_coords[1]
        canvas.delete(scratch_cat)
    scratch_cat = canvas.create_image(scratch_cat_coords_x, scratch_cat_coords_y, image=scratch_cat_tkimage, tags = 'scratch_cat_image')
 
speed = 5
scratch_cat_rotate_degrees = 0
root = Tk()
canvas_width = 480
canvas_height = 360
scratch_cat_size = 100
canvas = Canvas(master=root, width=canvas_width, height=canvas_height, bg='white')
canvas.pack()
scratch_cat_image = Image.open('scratch_cat.png')
rotate_image(0, True)
root.bind('<KeyPress>', key_pressed)
root.mainloop()

Néhány fontosabb részt kiemelek:

  • A scratch_cat_rotate_degrees globális változóban tároljuk a macska irányát, és felhasználjuk, ahol kell.
  • A "menj 5 lépést" utasításnak megfelelő rész a key_pressed függvényben a mat.sin() ill. math.cos() rész, melyben átszámoljuk a pillanatnyi irányt radiánná, és trigonometrikus függvények segítségével kiszámoljuk az új koordinátákat.
  • Nem a TK PhotoImage osztályát használjuk a kép betöltésére, hanem a Pillow Image osztályát, amit el tudunk forgatni. Ezt átalakítjuk a ImageTk osztály segítségével olyanná, amit a TK vászon is meg tud jeleníteni.
  • A bounce() a "ha szélen vagy, pattanj vissza" megfelelője. Itt minden esetre pontosan ki kell számolni az új irányt.
  • Persze azt is ki kell számolni, hogy szélen vagyunk-e; ez az is_within_canvas() függvény.

Szereplő csúsztatása

Tekintsük az alábbi Scratch programot:

scratch_csussz.png

Pythonban ehhez a root.after() függvényt használjuk. Századmásodpercenként egyszer lefut. Ott meghatározzuk, hogy mennyit kell csúsznunk:

from tkinter import *
 
def slide():
    global counter
    counter = counter + 1
    delta_x = (destination_x - start_x) / (100 * slide_time)
    delta_y = (destination_y - start_y) / (100 * slide_time)
    canvas.move(scratch_cat, delta_x, delta_y)
    if  counter < 100 * slide_time:
        root.after(10, slide)
 
start_x = 100
start_y = 100
destination_x = 380
destination_y = 280
slide_time = 2
root = Tk()
canvas = Canvas(root, width=480, height=360, bg='white')
canvas.pack()
scratch_cat_image = PhotoImage(file='scratch_cat.png')
scratch_cat = canvas.create_image(start_x, start_y, image=scratch_cat_image)
counter = 0
root.after(10, slide)
root.mainloop()

Ugrás az egérmutatóhoz

A következő program folyamatosan követi az egérmutatót:

scratch_egermutato.png

Pythonban ezt közvetlenül nem tudjuk megvalósítani; az egérmozgás eseményt kell összekapcsolni egy függvénnyel, és ott lekezelni:

from tkinter import *
 
def motion(event):
    scratch_cat_coords = canvas.coords(scratch_cat)
    new_x = event.x - scratch_cat_coords[0]
    new_y = event.y - scratch_cat_coords[1]
    canvas.move(scratch_cat, new_x, new_y)
 
root = Tk()
canvas = Canvas(root, width=480, height=360, bg='white')
canvas.pack()
scratch_cat_image = PhotoImage(file='scratch_cat.png')
scratch_cat = canvas.create_image(240, 180, image=scratch_cat_image)
root.bind('<Motion>', motion)
root.mainloop()

Ugrás egy véletlen pozícióba

A következő programban a szereplő másodpercenként egy másik véletlen helyre ugrik:

scratch_veletlenhely.png

Pythonban ehhez a random könyvtárat kell használnunk, valamint ki kell számolnunk az eltérést az aktuális és az új pozíció között. Ezt is az after() függvény segítségével oldjuk meg:

from tkinter import *
from random import randint
 
def move():
    new_x = randint(0, 480)
    new_y = randint(0, 360)
    scratch_cat_coords = canvas.coords(scratch_cat)
    canvas.move(scratch_cat, new_x-scratch_cat_coords[0], new_y-scratch_cat_coords[1])
    root.after(1000, move)
 
root = Tk()
canvas = Canvas(master=root, width=480, height=360, bg='white')
canvas.pack()
scratch_cat_image = PhotoImage(file='scratch_cat.png')
scratch_cat = canvas.create_image(240, 180, image=scratch_cat_image)
root.after(1000, move)
root.mainloop()

Összefoglaló

Habár a Python, ill. azon belül jelen esetben a TK tudása sokkal nagyobb, mint a Scratch-é, a fent bemutatott alapdolgok jóval egyszerűbbek Scratch-ben, mint Pythonban.

Kinézet

Ehhez hasonló nincs a Pythonban, szinte mindent az alapoktól kellene leprogramozni.

Hang

A Python alapból hangot lejátszani nem tud, viszont van számos külső könyvtár, amelynek segítségével erre van mód.

Események

Zöld zászlóra kattintáskor

Ez a legfontosabb esemény: ezzel indul el a program. A Pythonban több módja van a program elindításának:

  • python [programnév].py paranccsal
  • F5 az IDLE-ben
  • Duplán kattintunk a py fájlra

Érdemes viszont megemlíteni, hogy a Scratch-ben minden szereplőnek lehet saját programja, akár több is, és ezek párhuzamosan futnak. Pythonban erre közvetlenül nincs lehetőség, két módszert viszont alkalmazhatunk:

  • A Tk objektum after() metódusának segítségével tudunk egy fő ciklust készíteni, ahogy fent már láttuk, és azon belül szimulálni a párhuzamosítást. A TK-ban leginkább ezt tudjuk alkalmazni.
  • Egyébként függetlenül a TK-tól használhatjuk a szálakat.

A szálak bemutatása messze meghaladja ennek a leírásnak a kereteit, nagyon sok részletre kell figyelni. Viszont lássunk egy viszonylag egyszerű példát: két szál fut párhuzamosan, az első kiír valamit, utána a második kiír valamit, majd azt követően még valamit, végül az első kiír valamit. Talán egyszerűbb látni mint elmagyarázni:

scratch_szalak.png

Ennek megfelelő Python kód:

import threading
import time
 
def thread_func_one():
    print('Az első szál eleje.')
    time.sleep(3)
    print('Az első szál vége.')
 
def thread_func_two():
    print('A második szál eleje.')
    time.sleep(1)
    print('A második szál vége.')
 
thread_one = threading.Thread(target=thread_func_one)
thread_two = threading.Thread(target=thread_func_two)
thread_one.start()
time.sleep(1)
thread_two.start()

Gombnyomáskor

Tekintsük a következő Scratch programot:

scratch_gomb_lenyomva.png

A Pythonban "csak úgy" a gombnyomás esemény nem értelmezett, a TK-ban viszont igen. A fentinek többé-kevésbé megfelelő Python kód a következő:

from tkinter import *
 
def key_pressed(event):
    if event.keysym == 'Left':
        print('balra nyíl lenyomva')
    if event.keysym == 'Right':
        print('jobbra nyíl lenyomva')
    if event.keysym == 'Up':
        print('felfelé nyíl lenyomva')
    if event.keysym == 'Down':
        print('lefelé nyíl lenyomva')
 
root = Tk()
root.bind('<KeyPress>', key_pressed)
root.mainloop()

Kattintáskor

Nézzük meg a következő Scratch kódot:

scratch_szereplore_kattintas.png

Ehhez hasonló program Pythonban:

from tkinter import *
 
def button_pressed(event):
    print('Rám kattintottak.')
 
root = Tk()
canvas = Canvas(root, width=480, height=360, bg='white')
canvas.pack()
circle = canvas.create_oval(220, 160, 260, 200, width=3, outline='black', fill='yellow')
canvas.tag_bind(circle, '<Button-1>', button_pressed)
root.mainloop()

Üzenet küldése és fogadása

Tekintsük a következő küldő és fogadó Scratch kódot:

scratch_uzenet_kuldese.png
scratch_uzenet_fogadasa.png

Pythonban ilyen jellegű üzenetküldésére ritkán van szükség, mivel ott az eltérő programszervezés miatt "közvetlenebbül" kommunikálnak a szereplők. Egészen pontosan: nem kommunikálnak, hanem egy központi vezérlő vezérli a dolgokat. Ha mégis meg szeretnénk valósítani az üzenetküldést, akkor arra mintát mutat az alábbi program:

import threading
import time
 
def receiver(my_message):
    with my_message:
        print('Várakozás az üzenetre…')
        my_message.wait()
        print('…az üzenet megérkezett.')
 
def sender(my_message):
    with my_message:
        print('Üzenet küldése…')
        time.sleep(1)
        my_message.notifyAll()
        print('…üzenet elküldve')
 
if __name__ == '__main__':
    my_message = threading.Condition()
    receiver_thread = threading.Thread(target=receiver, args=(my_message,))
    sender_thread = threading.Thread(target=sender, args=(my_message,))
    receiver_thread.start()
    sender_thread.start()

A többi

Van még három esemény:

  • Háttér beállásakor: ennek egyfajta üzenetküldő szerepe van a Scratch-ben; az egyik szereplő beállítja pl. a vége hátteret, és a többi szereplő ennek megfelelően reagál. Pythonban nincsenek szereplők, a főprogramot pedig meg tudjuk úgy írni, hogy az ilyen helyzeteket le tudja kezelni.
  • Amikor a hangerő elér egy szintet (mikrofonban): alapból a Python nem kezeli a mikrofont, ahhoz külön könyvtárak kellenek, pl. pyaudio.
  • Amikor az időmérő elér egy értéket: Pythonban nincs egyetlen kitüntetett időzítő, mint a Scratchben, viszont számos módon hozhatunk létre időzítőt. Az egyik lehetőség a már fent látott TK specifikus after(), egy másikat pedig lent láthatunk.
import threading 
 
def timer_expired(): 
    print('Időzítő lejárt') 
 
timer = threading.Timer(1, timer_expired) 
timer.start()

Vezérlés

Várj valamennyi másodpercet

Az következő Scratch Program:

scratch_varj.png

Python megfelelője:

import time
 
print('előtte')
time.sleep(2)
print('utána')

Ismételd

A következő programban amiatt van 1 másodepr4ces késeltetés, hogy lássuk az eredményt:

scratch_ismeteld.png

Hasonló program Scratch-ben, késleltetés nélkül:

for i in range(10):
    print(i)

Mindig

A mindig utasításra - noha elég egyértelműnek tűnik - nehéz olyan példát találni, ami kellően egyszerű, és kb. megegyezik Pythonban és Scratch-ben. Elvileg a következővel egyenértékű:

while True:
    pass

ahol a pass helyére kerül az, ami a Scratch-ben a belsejébe. Csakhogy van pár olyan eltérés, ami megakadályozza a jó példa elkészítését:

  • A Scratch-ben általában a szereplők mozgatására alkalmazzuk ezt, ahol végtelen ciklusban figyeljük a billentyűzetet, vagy adott időközönként készítünk másolatot, mozgatjuk a szereplőket stb. A Python-ban a TK picit másképp működik, ott pont nem tudjuk ezt while True: segítségével megoldani.
  • A Scratch-ben ha leállítjuk a mindig ciklust, akkor az gyakran a program végét, de legalább az adott szereplő végét jelenti. Tehát ott csak drasztikus véget tud érni a mindig ciklus; normál esetben nem ér véget. Ilyen értelemben "enyhébb" a Python (és más programozási nyelvek) ciklusa, ahol van ún. break utasítás, amellyel ki lehet lépni a végtelen ciklusból, és lehet folytatni a program futását. Emlékeztetőül: a Scratch-ben a mindig ciklus után nem tudunk utasításokat beszúrni.
  • A Scratch-ben nincs hagyományos értelembe vett kiírás. Ha végtelen sokszor mondatjuk a szereplővel ugyanazt, akkor nem látunk változást, míg Pythonban addig írja a konzolra, amíg meg nem unjuk.

Egy olyan program, ami kellően egyszerű, és nagyjából ugyanazt hajtja végre, az Scratch-ben ez:

scratch_mindig.png

míg Pythonban ez:

while True:
    print('egy')
    print('kettő')

Ez utóbbiban persze egy másodperces késleltetést is bele kellene tenni, de talán a lényeg anélkül is érhető. (Ctrl+C billentyűkombinációval lehet "lelőni" a programot.)

Ha … akkor

A ha [feltétel] akkor [művelet] Scratch szerkezet Python megfelelője:

if [feltétel]:
    [művelet]

Vegyük a következő Scratch példát!

scratch_ha.png

Ennek többé-kevésbé megfelelő Python kód:

valasz = input('Mennyi 3+2? ')
if valasz == '5':
    print('A válasz helyes!')

Ha … akkor … különben

Az előző folytatása: Scratch-ben ha [feltétel] akkor [ág1] különben [ág2] a Pythonban:

if [feltétel]:
    [ág1]
else:
    [ág2]

Erre is lássunk egy példát! Az előzőt folytatva:

valasz = input('Mennyi 3+2? ')
if valasz == '5':
    print('A válasz helyes!')
else:
    print('A válasz helytelen, a helyes válasz 5 lett volna!')

Várj eddig

A várj eddig utasítás hatására megáll a program, és valamilyen esemény bekövetkeztéig úgy marad. Ha az esemény bekövetkezik, akkor leáll a várakozás, és tovább fut a program.

Távolról és hunyorítva ennek megfelelő Python utasítás a while feltétellel, viszont itt is van pár eltérés:

  • A Scratch várj eddig utasítása nem csinál semmit, míg a Python while utasításának a magja lefut.
  • A Scratch várj eddig utasítása addig vár, amíg a feltétel nem teljesül; amint teljesül, tovább lép. A Python while ciklusának a belseje addig fut le ismételten, amíg a feltétel teljesül, és befejeződik, ha már nem teljesül.

Ill. van még egy olyan probléma, ami miatt még erre az egyszerű utasításra sem tudunk egyszerű működő példát adni: mivel a Scratch-ben az adott szereplő adott programja nem fut, a várj eddig hatására, ott nem is következhet be az az esemény, hanem csak úgy, hogy vagy az adott szereplő másik programja hozza létre, egy másik szereplő hozza létre, vagy valamilyen külső körülmény. Ezt viszont programozástechnikailag úgy hívjuk, hogy az esemény egy másik szál hatására következi be. A többszálúság nem tartozik az egyszerű dolgok közé, anélkül viszont nem lehet olyan működő Python kódot írni, ami a várj eddig utasítást szimulálja.

Tekintsük az alábbi Scratch kódot:

scratch_varjeddig.png

Itt az egyik program másodpercenként eggyel növeli az i változó értékét, ami kezdetben 0, a másik program másodpercenként hárommal növeli, az első program figyeli a változó értékét, és leáll, ha az meghaladja a 10-et. Ezzel azt számoljuk ki, hogy melyik az az első szám,a mi nagyobb mint 10.

Ennek megfelelő Python kód:

import threading
import time
 
i = 0
 
def varj():
    while i <= 10:
        pass
    print(i)
 
def novel():
    global i
    while True:
       time.sleep(1)
       i = i + 3
 
varo = threading.Thread(target = varj)
novelo = threading.Thread(target = novel)
varo.start()
novelo.start()

Itt számunkra a while <= 10 sor az érdekes.

Ismételd eddig

A várj eddig félig-meddig párja. Ez annyiban hasonlít a Python while ciklusához, hogy itt is, ott is lefut a ciklusmag. Azonban egy gyakorlott programozónak nagyon nehéz megszoknia a Scratch logikáját, hogy a ciklusmag mindaddig lefut, amíg a feltétel nem igaz, míg Pythonban (és szinte mindegyik más programozási nyelvben is) pont ellenkezőleg: amíg a feltétel igaz. (Erről személy szerint azt gondolom, hogy ez egy komoly tervezési hiba a Scratch-ben; azt kellett volna úgy megalkotni, hogy fordítva működjön.)

A fenti programot leegyszerűsítve, tekintsük az alábbi Scratch programot:

scratch_ismeteld_eddig.png

Ennek megfelelő Python program:

i = 0
while i <= 10:
    i = i + 3
print(i)

Ez így sokkal egyszerűbb, mint a fenti!

Álljon le minden

Az álljon le minden kilépés a programból. Tekintsük a következő programot, melyben elkezdjük növelni és kiírni a számokat egytől egyesével, és ha több lesz mint 5, álljon le:

scratch_alljon_le_minden.png

Ennek kb. megfelelő Python program:

i = 1
while True:
    i = i + 1
    print(i)
    if i > 5:
        exit()

Álljon le ez az eljárás

Kevésbé drasztikus az adott szál leállítása, ami jelen esetben ugyanazt csinálja, mint a fenti (feltéve, hogy nincs másik szereplő, vagy az adott szereplőnek másik programja):

scratch_alljon_le_ez.png

Pythonban ezt többféleképpen is megvalósíthatjuk, pl.:

i = 1
while True:
    i = i + 1
    print(i)
    if i > 5:
        break

Vagy ha függvényről van szó, akkor break helyett mehet a return is.

Álljon le a szereplő többi feladata

A szereplő többi feladatának leállítására nehéz Python analógiát találni, mivel ott nincsenek hagyományos értelembe vett szereplők. Ismét a többszálúság területére tévedtünk, és a feladat lényegében az, hogy az egyik szál le szeretne állítani egy vagy több másikat. Tekintsük az alábbi Scratch példát:

scratch_alljon_le_tobbi.png

Itt pontban 10 másodperc elteltével kilőjük a többit. Pythonban ennél "finomabb" módon valósítjuk meg:

import threading
import time
 
i = 0
vege = False
 
def szamok():
    while not vege:
        print('egy')
        time.sleep(2)
        print('kettő')
        time.sleep(2)
 
def gyumik():
    while not vege:
        print('alma')
        time.sleep(2)
        print('körte')
        time.sleep(2)
 
szamolo = threading.Thread(target = szamok)
gyumizo = threading.Thread(target = gyumik)
szamolo.start()
time.sleep(1)
gyumizo.start()
time.sleep(10)
vege = True

A szálak figyelik a vege változót, és annak megfelelően cselekednek. Persze az igazsághoz hozzátartozik, hogy azt szinte minden lépésben figyelni kellene, a programunk viszont csak 4 másodpercenként figyeli.

Másolat kezelése

A szereplő másolatainak kezeléséhez talán az osztályok és objektumok állnak legközelebb a Scratch-ben. Lássunk egy példát!

scratch_masolat_kozos.png

Itt az i_kozos legyen miden szereplőé. Ha lefuttatjuk, akkor egymáson megjelenik összesen 4 macska, ebből 3 kiírja, hogy 28, majd eltűnnek. A probléma az, hogy ugyanazt a változót használják, az elején a harmadik is kinullázza, majd párhuzamosan növelik, így értik el a 28-at a végére. Ennek megfelelő Python kód (azzal a különbséggel, hogy ott nem párhuzamosan fut, és az eredmények 10, 20 és 30 lesznek) a következő:

class Macska:
    i_sajat = 0
 
    def novel(self):
        for i in range(10):
            self.i_sajat = self.i_sajat + 1
        print(self.i_sajat)
 
macska1 = Macska()
macska2 = macska1
macska3 = macska1
macska1.novel()
macska2.novel()
macska3.novel()
del macska1
del macska2
del macska3

Itt a macska1 = Macska() felel meg annak, hogy készíts másolatot, a macska1.novel() függvényhívás annak, hogy másolatként kezdéskor, míg a del macska1 annak, hogy töröld ezt a másolatot. (Az osztály magát nem tudja törölni.)

Módosítsuk a Scratch kódot úgy, hogy a változó most az adott szereplőhöz tartozzon:

scratch_masolat_sajat.png

Az ennek megfelelő Python kód:

import copy
 
class Macska:
    i_sajat = 0
 
    def novel(self):
        for i in range(10):
            self.i_sajat = self.i_sajat + 1
        print(self.i_sajat)
 
macska1 = Macska()
macska2 = copy.copy(macska1)
macska3 = copy.copy(macska1)
macska1.novel()
macska2.novel()
macska3.novel()
del macska1
del macska2
del macska3

Mindkét esetben az eredmény 3-szor 10. A Pythonban az történt, hogy valóban másolatot készítettünk a copy.copy() függvénnyel, míg a fentiben három referencia mutatott ugyanarra a példányra. (Ez lehet, hogy kicsit zavaros; nem probléma.)

Érzékelés

Egérműveletek

Az Érzékelés részben az alábbi egérműveleteket támogatja a Scratch:

  • Érinted: egérmutató (ez azt jelenti, hogy az adott szereplőt érinti-e az egérmutató)
  • Egérmutató távolsága (az adott szereplőtől)
  • Egér lenyomva
  • Egér x és y koordinátája

Mivel a Pythonban a program nem egy adott szereplőhöz tartozik, hanem attól független, ezeknek önmagukban nincs értelmük. Viszont le tudjuk kérdezi a szereplő koordinátáit.

Vegyük a következő Scratch példát! Ebben folyamatosan lekérdezzük az egérmutató távolságát az adott szereplőtől, azt is megnézzük, hogy érintjük-e, valamint folyamatosan követjük az egér koordinátáit, valamint azt is, hogy le van-e nyomva az egérmutató! Ehhez hozzunk létre megfelelő változókat.

scratch_egermuveletek.png

Egy ehhez hasonló megoldás Pythonban:

import math
from tkinter import *
 
def motion(event):
    scratch_cat_coords = canvas.coords(scratch_cat)
    diff_x = event.x - scratch_cat_coords[0]
    diff_y = event.y - scratch_cat_coords[1]
    diff = math.sqrt(diff_x ** 2 + diff_y ** 2)
    touch = diff < 50
    print(f'Távolság: {diff}')
    print(f'Érinted: {touch}')
    print(f'Koordináták (x, y): {scratch_cat_coords[0]}, {scratch_cat_coords[1]}')
 
def click(event):
    print('Egérgomb lenyomva')
 
def release(event):
    print('Egérgomb elengedve')
 
root = Tk()
canvas = Canvas(root, width=480, height=360, bg='white')
canvas.pack()
scratch_cat_image = PhotoImage(file='scratch_cat.png')
scratch_cat = canvas.create_image(240, 180, image=scratch_cat_image)
canvas.bind('<Button-1>', click)
canvas.bind('<ButtonRelease-1>', release)
canvas.bind('<Motion>', motion)
root.mainloop()

Figyeljük meg, hogy a Pitagorasz-tétel alapján számoljuk ki a távolságot. A szereplő érintés precíz meghatározása bonyolult lenne; közelítéssel oldjuk meg a problémát.

Érinted: színpad széle

Jobb híján a szereplő koordinátáit kell figyelnünk. Példát láthatunk erre a fenti visszapattanásos programban.

Színérzékelés

Ezt bonyolult megvalósítani Pythonban, így ettől eltekintünk.

Kérdés

Tekintsük az alábbi Scratch programot:

scratch_kerdes.png

A Python megfelelője:

nev = input('Hogy hívnak? ')
print(f'Szia, {nev}')

Billentyű lenyomva

Tekintsük az alábbi Scratch programot:

scratch_lenyomva.png

A Pythonban most csak azt az esetet vizsgáljuk, hogy TK-ban hogyan kezeljük a billentyűzetet! Ott önmagában nem tudjuk lekérdezni azt, hogy épp le van-e nyomva egy billentyű, viszont két lehetőség is van a probléma megoldására. Az egyik: "feliratkozunk" az egyes billentyű eseményekre:

from tkinter import *
 
def left_pressed(event):
    print('Left pressed')
 
def right_pressed(event):
    print('Right pressed')
 
def up_pressed(event):
    print('Up pressed')
 
def down_pressed(event):
    print('Down pressed')
 
def a_pressed(event):
    print('a pressed')
 
def space_pressed(event):
    print('Space pressed')
 
root = Tk()
canvas = Canvas(master=root, width=480, height=360, bg='white')
canvas.pack()
root.bind("<Left>", left_pressed)
root.bind("<Right>", right_pressed)
root.bind("<Up>", up_pressed)
root.bind("<Down>", down_pressed)
root.bind("<space>", space_pressed)
root.bind("<a>", a_pressed)
root.mainloop()

A másik: feliratkozunk egy általános billentyű lenyomás eseményre, és ott nézzük, hogy melyik billentyű lett lenyomva. Ennek párja a felengedés. Ha megfelelő változókba beletesszük a számunkra érdekes billentyűket, akkor lényegében folyamatosan tudjuk, hogy melyik van lenyomva.

A fenti programnak többé-kevésbé megfelelő Python program az alábbi:

from tkinter import *
 
left_pressed = False
right_pressed = False
up_pressed = False
down_pressed = False
space_pressed = False
a_pressed = False
 
def key_pressed(event):
    global left_pressed, right_pressed, up_pressed, down_pressed
    global space_pressed, a_pressed
    if event.keysym == 'Left':
        left_pressed = True
    if event.keysym == 'Right':
        right_pressed = True
    if event.keysym == 'Up':
        up_pressed = True
    if event.keysym == 'Down':
        down_pressed = True
    if event.keysym == 'space':
        space_pressed = True
    if event.keysym == 'a':
        a_pressed = True
 
def key_released(event):
    global left_pressed, right_pressed, up_pressed, down_pressed
    global space_pressed, a_pressed
    if event.keysym == 'Left':
        left_pressed = False
    if event.keysym == 'Right':
        right_pressed = False
    if event.keysym == 'Up':
        up_pressed = False
    if event.keysym == 'Down':
        down_pressed = False
    if event.keysym == 'space':
        space_pressed = False
    if event.keysym == 'a':
        a_pressed = False
 
def play():
    if left_pressed:
        print('Balra nyíl lenyomva')
    if right_pressed:
        print('Jobbra nyíl lenyomva')
    if up_pressed:
        print('Felfelé nyíl lenyomva')
    if down_pressed:
        print('Lefelé nyíl lenyomva')
    if space_pressed:
        print('Szóköz lenyomva')
    if a_pressed:
        print('a lenyomva')
    root.after(100, play)
 
root = Tk()
canvas = Canvas(master=root, width=480, height=360, bg='white')
canvas.pack()
root.bind('<KeyPress>', key_pressed)
root.bind('<KeyRelease>', key_released)
root.after(100, play)
root.mainloop()

Húzás módja

Ez azt jelenti, hogy a játékos odább tudja-e tenni a szereplőt vagy sem. Valószínűleg Scratch-ben sem egyértelmű mindenki számára, hogy ez pontosan hogyan működik, ugyanis a szerkesztőben mindig tudjuk mozgatni a szereplőket. Valójában ha kilépünk a projektből ("Vissza a projekt oldalára") és onnan indítjuk, akkor alapból nem tudjuk mozgatni. Tegyük a következőt! Hozzunk létre két szereplőt, az egyiknél azt állítsuk be, hogy ne legyen mozgatható, a másikat pedig mozgathatóra állítsuk be.

scratch_nemhuzhato.pngscratch_huzhato.png

Pythonban ez elég komplikált megvalósítani. Igazából magát a mozgatást kell megvalósítani, az nincs alapból úgy, mint a Scratch-ben, a nem mozgatható szereplők esetén pedig egyszerűen nem valósítjuk meg a mozgatást. A mozgatást a következőképpen valósíthatjuk meg:

  • Figyeljük az egérgomb kattintást és felengedését.
  • Kattintáskor megnézzük a kattintás helyét. A fenti közelítő távolsággal megállapítjuk, hogy (többé-kevésbé) a szereplőn kattintottunk-e. Ha igen, akkor beállítjuk a mozgást.
  • Felengedéskor leállítjuk a mozgást.
  • Az egér mozgásakor mozgatjuk a képet.

A példában kétszer jelenítjük meg a képet, de csak az egyiknél valósíjtuk meg a mozgatást.

import math
from tkinter import *
 
moving = True
 
def motion(event):
    if moving:
        scratch_cat_coords = canvas.coords(scratch_cat_moving)
        new_x = event.x - scratch_cat_coords[0]
        new_y = event.y - scratch_cat_coords[1]
        canvas.move(scratch_cat_moving, new_x, new_y)
 
def touch(event):
    scratch_cat_coords = canvas.coords(scratch_cat_moving)
    diff_x = event.x - scratch_cat_coords[0]
    diff_y = event.y - scratch_cat_coords[1]
    diff = math.sqrt(diff_x ** 2 + diff_y ** 2)
    touch = diff < 50
    return touch
 
def click(event):
    global moving
    if touch(event):
        moving = True
 
def release(event):
    global moving
    moving = False
 
root = Tk()
canvas = Canvas(root, width=480, height=360, bg='white')
canvas.pack()
scratch_cat_image = PhotoImage(file='scratch_cat.png')
scratch_cat_moving = canvas.create_image(120, 180, image=scratch_cat_image)
scratch_cat_still = canvas.create_image(360, 180, image=scratch_cat_image)
canvas.bind('<B1-Motion>', motion)
canvas.bind('<Button-1>', click)
canvas.bind('<ButtonRelease-1>', release)
root.mainloop()

Ez már így is bonyolult, de még tovább lehetne (és sok esetben kellene is) komplikálni:

  • Több mozgatható szereplőnél külön kellene mindegyiket figyelni.
  • Ez a mozgatás ebben a formában "nincs élére vasalva": pl. ha a sarkára kattintunk, és egy nagyon picit megmozdítjuk az egeret, akkor nagyot ugrik, ugyanis a kép közepe az egérmutató helyére ugrik.

Szóval bőven lenne még mit javítani ezen, de ahhoz képest, hogy Scratch-ben ez valóban csak a szereplő egy tulajdonsága, már így is nagyon komplikált.

Hangerő

Ezzel nem foglalkozunk

Időmérő

Vegyük az alábbi Scratch példát:

scratch_idomero.png

Ennek megfelelő Python program:

import time
 
start_time = time.perf_counter()
input('Nyomj entert!')
stop_time = time.perf_counter()
eltelt = stop_time - start_time
print(f'Eltelt idő: {eltelt}')

Szereplő tulajdonságai

A szereplő koordinátáinak a lekérdezését már láttuk; jelmeze, háttere stb. nincs a Pythonban, hangerővel nem foglalkozunk. Viszont itt megjelennek és le lehet kérdezni az adott szereplő változóit. (Az összes szereplőhöz tartozó változók a színpadhoz vannak rendelve.) Ez utóbbi az objektumorientált világba tett lépés, ami (sokkal bonyolultabb módon) a Pythonban is benne van. Egy példa:

class Szereplo:
    def __init__(self, name, x, y):
        self.name = name
        self.x = x
        self.y = y
 
    def move(self, dx, dy):
        self.x += dx
        self.y += dy
 
    def print(self):
        print(f'{self.name} koordinátái: {self.x}, {self.y}')
 
macska = Szereplo('Szijámijáú', 5, 8)
kutya = Szereplo('Frakk', 3, 2)
kutya.move(1, 2)
macska.print()
kutya.print()
print('A macska neve: ' + macska.name)

Le tudtuk tehát kérdezni a macska nevét, és még sok egyebet tudtunk csinálni.

Dátumkezelés

A Scratch-ben le lehet kérdezni az aktuális időt, annak részleteit, pl.:

scratch_ido.png

Látható egyébként, hogy még egy ilyen egyszerű dolog is mennyire el tud bonyolódni Scratch-ben is, ha nem igazán úgy lett megalkotva, hogy kényelmes legyen a használata. A Python alapértelmezésben mikromásodperc pontossággal írja ki az időt:

from datetime import datetime
 
print(datetime.now())

Van még egy furcsa lehetőség Scratch-ben: a 2000 óta eltelt napok száma:

scratch_y2k.png

Ehhez hasonló a Pythonban (kerek számokkal):

from datetime import date
 
y2k = date(2000, 1, 1)
today = date.today()
delta = today - y2k
print(delta)

Felhasználónév

Webes alkalmazásoknál lenne értelme erről beszélni. Habár a Python alkalmas webes alkalmazás szerver oldali részének a megvalósítására, meg kellene valósítani a grafikus felületet is HTML-t, CSS-t és JavaScript-et alkalmazva + valamilyen belépő modult, így oly mértékben meghaladja ez ennek a leírásnak a kereteit, hogy ettől most eltekintünk.

Műveletek

Az alábbi szakasz a műveleteket tárgyalja. Helyenként szükség van a következő sorra, amit általában a program elejére írunk (bár lehet máshova is):

import math

Alapműveletek

Művelet Scratch Python Eredmény Megjegyzés
összeadás scratch_osszeadas.png 3 + 2 5
kivonás scratch_kivonas.png 3 - 2 1
szorzás scratch_szorzas.png 3 * 2 6
osztás scratch_osztas.png 3 / 2 1.5 Scratch-ben és Pythonban is valós osztás, máshol nem
egész osztás scratch_egeszosztas.png 3 // 2 1 dupla perjel a Pythonban (egyedi)
maradék scratch_maradek.png 3 % 2 1 százalékjel (szokásos)

Logikai műveletek

Művelet Scratch Python Eredmény Megjegyzés
nagyobb scratch_nagyobbmint.png 7 > 5 False
kisebb scratch_kisebbmint.png 7 < 5 False
egyenlő scratch_egyenlo.png 7 == 5 False dupla egyenlőségjel a Pythonban, mert az egyszeres egyenlőségjel az értékadást jelenti
logikai és scratch_logikaies.png 2 < 7 and 7 < 8 True
logikai vagy scratch_logikaivagy.png 2 > 7 or 7 > 6 True
logikai tagadás scratch_logikaies.png not 7 > 5 False

Szöveg műveletek

Művelet Scratch Python Eredmény Megjegyzés
összefűzés scratch_egyutt.png 'őszi' + 'barack' 'őszibarack'
betűje scratch_betuje.png 'barack'[2] 'r' Pythonban (és általában más nyelvekben is) a sorszámozás 0-tól indul, a Scratch-ben 1-től
hossza scratch_hossza.png len('barack') 6
tartalmazza scratch_tartalmazza.png 'ara' in 'barack' True

Kerekítések

Művelet Scratch Python Eredmény Megjegyzés
kerekítés scratch_kerekitve.png round(1.6) 2 félig lefelé, féltől (beleértve a felet is) felfelé kerekít
lefelé kerekítés scratch_lefele.png math.floor(1.6) 1 a legnagyobb olyan egész számot adja vissza, ami kisebb vagy egyenlő a számmal (floor = plafon)
felfelé kerekítés scratch_felfele.png math.ceil(1.6) 1 a legkisebb olyan egész számot adja vissza, ami nagyobb vagy egyenlő a számmal (ceiling = plafon)
abszolút érték scratch_abszolut.png abs(-3) 3 ha a szám negatív, akkor a pozitívat adja vissza

Trigonometria

A trigonometria általában meghaladja azt a szintet, amire a Scratch használatakor szükség van. Egyrészt ez amiatt van, mert azokat a műveleteket, amelyhez szükség lenne ezekre a műveletekre (pl. fordulj; menj előre; ha szélen vagy, pattanj vissza) megvalósították külön, ezáltal elfedve a trigonometriát, másrészt amiatt is, mert a Scratch ajánlott korosztálya (felsős általános iskolások) még nem tanultak trigonometriát, az középiskolás tananyag. Ennek a szakasznak nem célja a trigonometria ismertetése, csak az, hogy ami van Scratch-ben, hogyan használjuk Pythonban.

A Scratch fokokban számol, míg a Python alapértelmezésben radiánban, emiatt ez utóbbi esetben konverzióra van szükség.

Művelet Scratch Python Eredmény Megjegyzés
szinusz scratch_szinusza.png math.sin(math.radians(90)) 1
koszinusz scratch_koszinusza.png math.cos(math.radians(180)) -1
tangens scratch_tangense.png math.tan(math.radians(45)) 1 a Python hibásan 0.9999999999999999-t ír ki
arkusz szinusz scratch_arcsin.png math.degrees(math.asin(1)) 90 a szinusz inverz művelete
arkusz koszinusz scratch_arccos.png math.degrees(math.acos(-1)) 180 a koszinusz inverz művelete
arkusz tangens scratch_arctan.png math.degrees(math.atan(1)) 45 a tangens inverz művelete

Exponenciális

Művelet Scratch Python Eredmény Megjegyzés
természetes alapú hatvány scratch_exp.png math.exp(2) 7.38905609893065 ez az $e$ konstans négyzete; közelítő érték
természetes alapú logaritmus scratch_ln.png math.log(7.38905609893065) 2 az előző inverz művelete; a log kissé megtévesztő (az ln lenne kézenfekvőbb)
tízes alapú hatvány scratch_tizexp.png 10 ** 3 1000 a Pythonban a hatványozás művelete alap nyelvi elem
tízes alapú logaritmus scratch_log.png math.log10(1000) 3 az előző inverz művelete; ezt a Scratch rontja el (2,9999…)
négyzetgyök scratch_gyoke.png math.sqrt(25) 5.0 a négyzetgyök olyan, mintha feledik hatvány lenne

Véletlen szám

Itt szükség van a következőre:

import random
Művelet Scratch Python Eredmény Megjegyzés
véletlen egész két szám között scratch_veletlen.png random.randint(1, 11) pl. 7 Pythonban a második paraméter a felső határ + 1

Változók

Változó

A Scratch-ben a változókat létre lehet hozni, az értéküket be lehet állítani, hozzá lehet adni valamennyit, valamint meg lehet jeleníteni ill. el lehet tüntetni.

A Scratch-ben a változó lehet minden szereplőé, vagy a kiválasztott szereplőé. Pythonban a "minden szereplő" változónak a globális felel meg, a kiválasztott szereplőé pedig vagy lokális, vagy osztályhoz kötött; ez utóbbiról a szereplő tulajdonságai alfejezetben láthatunk példát, ezen az oldalon.

Tekintsük az alábbi példát:

scratch_valtozo.png

Ennek a Python megfelelője kb. ez:

x = 3
x = x + 2
print(x)

A Scratch-ben számot és szöveget is értékül tudunk adni egy változónak. Pythonban van még más típus is. Érdemes megjegyezni, hogy számos programozási nyelvben meg kell adni a változók típusát (tehát pl. szám, szöveg, betű, stb.); a Scratch-ben erre nincs szükség.

Lista

A lista kezelése meglehetősen kiforrott a Scratch-ben, és nagyon jól megfeleltethető a Python ill. más programozási nyelvek hasonló eljárásaival, ezért táblázatos nézzük meg a kapcsolatokat:

Művelet Scratch Python Eredmény Megjegyzés
lista létrehozása scratch_lista_letrehoz.png gyümölcsök = ['alma', 'banán', 'narancs'] alma, banán, narancs
elem hozzáadása scratch_lista_hozzaad.png gyümölcsök.append('meggy') alma, banán, narancs, meggy
elem törlése sorszám alapján scratch_lista_torol.png gyümölcsök.pop(1) alma, narancs, meggy Scratch-ben 1-től indul a sorszámozás, Pythonban 0-tól
elem beszúrása adott pozícióba scratch_lista_beszur.png gyümölcsök.insert(1, 'cseresznye') alma, cseresznye, narancs, meggy sorszámozás: mint előbb
elem lecserélése scratch_lista_lecserel.png gyümölcsök[2] = 'mandarin' alma, cseresznye, mandarin, meggy sorszámozás: mint előbb
a lista adott indexű eleme scratch_lista_eleme.png gyümölcsök[1] cseresznye sorszámozás: mint előbb
adott elem sorszáma scratch_lista_eleme.png gyümölcsök.index('meggy') Scratch-ben 4, Pythonban 3 sorszámozás: mint előbb
lista hossza scratch_lista_hossza.png len(gyümölcsök) 4 a hossz ugyanaz
lista tartalmazza scratch_lista_tartalmazza.png 'mandarin' in gyümölcsök True
minden elem törlése scratch_lista_mindettorol.png gyümölcsök.clear()

A megjelenítést és az eltüntetést abban a formában Pythonban egyszerűen nem tudjuk megoldani. Kiíratni a lista tartalmát így tudjuk:

print(gyümölcsök)

Blokkjaim

A Scratch blokkok a Python (és egyéb programozási nyelv) függvényeinek felel meg. A Python függvény ennél jóval többet tud, pl. lehet neki visszatérési értéke.

Példaként tekintsük az alábbi Scratch blokkot:

scratch_blokk.png

Ennek nagyjából megfelelő Python program az alábbi:

def nagyobb(a, b):
    if a > b:
        print(f'{a} a nagyobb')
    else:
        print(f'{b} a nagyobb')
 
nagyobb(5, 3)
nagyobb(2, 6)

Szereplők

A Scratch-ben elég komoly a szereplő választék, ráadásul a többségnek van több jelmeze, hangja, bizonyos tulajdonságait be lehet állítani közvetlenül (pl. méret, irány), vagy kódból (7 féle hatás). A rajzasztal is egész profi: van vektoros és bitképes változat, mindenféle alakzatokat lehet használni.

Ezzel szemben a Pythonban semmi sincs. A szereplőket nekünk magunknak kell létrehoznunk, a programozás helyére vinnünk, alakítanunk stb. A szereplők kezelése a Scratch egy óriási előnye szinte minden programozási nyelvvel szemben.

Bővítmények

A Scratch bővítmény fogalmának a Python csomag felel meg. Viszont ez az a terület, ahol a Python nagyságrendekkel a Scratch fölé kerül: amíg a Scratch-ben 10 körüli bővítményt találunk, Pythonban több százezer van. Abban szinte biztosak lehetünk, hogy amit a Scratch tud, azt a Python is tudja, viszont ebből a nehezen felfogható számból kiindulva azt is láthatjuk, hogy a betanulási görbe a Pythone setében sokkal hosszabb.

A Python felől

Érdemes azt is megvizsgálni, hogy mi az, amit a Python tud és a Scratch nem. Erről persze több ezer oldalt lehetne írni; itt inkább csak egy kis ízelítőt nézünk a lehetőségekből.

Alap nyelvi elemek

Bizonyos alap nyelvi elemek - melyek egyébként a legtöbb programozási nyelvben megtalálhatóak - hiányoznak a Scratch-ből, de benne vannak a Pythonban:

  • osztályok és öröklődés,
  • funkcionális programozás,
  • adatszerkezetek: halmazok, szótárak,
  • modulok.

Ezen kívül a Scratch-ben is meglévő függvények (ott blokknak hívják) a Pythonban sokkal tokkal többet tudnak: pl. van visszatérési értékük.

Könyvtárak

Ez a bővítményeknek felel meg a Scratch-ben. A Pythonnak sokkal gazdagabb a könyvtárválasztéka. "Alapból" is sokkal több minden van benne, az igazi erejét viszont a külön letölthető könyvtárak adják, melyek különösen sok területet lefednek.

  • TK: erről a többi oldalon részletesen van szó. Azt láthatjuk, hogy amit a Scratch-ben könnyedén meg tudjuk valósítani, azt helyenként TK-ban igen nehézkesen, ám valahogy minden megvalósítható benne. Ugyanakkor a TK tudása jóval több mint a Scratch-é: például olyan grafikai elemek is találhatóak benne (nyomógomb, beviteli mező stb.), ami a Scratch-ben nem.
  • Adatformátumok: a Python támogatja az olyan adatformátumokat, mint pl. a JSON vagy az XML, melyek segítségével különböző rendszerek tudnak kommunikálni egymással.
  • Adatforrások: adatokat tudunk fájlba írni ill. onnan olvasni; adatbázisba menteni ill. onnan olvasni; web szolgáltatásokat igénybe venni akár szerverként, akár kliensként.
  • Adattudomány könyvtárak: a "data science" és a "big data" napjaink felfutó területe. A Python népszerűségét részben annak köszönheti, hogy igen gazdag az ezzel kapcsolatos könyvtára; nagyobbrészt adatfeldolgozásra használják a nyelvet. Érdemes összehasonlítani a Scratch-csel: ott pár száz szereplő után már nem tudunk újabb szereplőt létrehozni, míg a Pythonban - megfelelően beállítva - szinte nincs felső határa annak az adatmennyiségnek, amit fel tud dolgozni.

Konklúzióként elmondhatjuk, hogy a Scratch kiválóan alkalmas a kódolás megismerésére, a Python tudása viszont lényegesen nagyobb annál. Noha a megismerése sokkal több energiát igényel, megéri befektetni.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License