A következő címkéjű bejegyzések mutatása: python. Összes bejegyzés megjelenítése
A következő címkéjű bejegyzések mutatása: python. Összes bejegyzés megjelenítése

2013. december 26., csütörtök

Javascript futtatása Python kódból, PyV8 fordítása

Kellemes Ünnepeket mindenkinek!
Természetesen azért, mert megint nem írtam már hetek hónapok óta, még nem állt meg az élet. Mostanában web scraping-el foglalkozok, ami nagyon komplex egy feladat, persze csak ha az ember normálisan akarja megcsinálni.

Egy olyan problémába ütköztem, ami manapság egyre hétköznapibb, hogy a weboldal nagy részét Javascript kódból építik fel. Használhatnék amúgy erre egy valódi böngészőt is, ami futtatja a kapott kódot, és Python alól birizgálom, pl Selenium-al, de nekem csak a Javascript kódban tárolt adatokra van szükségem. Párperces keresgélés után nem találtam normális parsert a nyelvhez, így aztán úgy döntöttem, hogy felrakom a Google V8 engine-jét, a hozzá tartozó Python-os bindinggel, a PyV8-al, betápolom neki a kódot, és dolgozok a visszakapott értékekkel.

Szerencsére a kis Odroid-X2-n szépen -lassan- lefordul maga az engine, és a binding is. A dokumentációban nem nagyon van részletes leírás a fordítás menetéről, így ezt magamnak kellett kitalálnom. Szerencsére apt-ből mindent össze lehet szedni. Lássuk a parancsokat!
sudo apt-get install libboost-python-dev libboost-thread-dev libboost-system-dev
Ennyi az összes függőség a fordításhoz. Ha nincs svn kliens feltelepítve, akkor erre még szükség lehet:
sudo apt-get install subversion
Ezek után egyszerűen pip-el telepítjük
sudo pip install pyv8

Rövid példácska

Rendbe, ha már ilyen szépen feltelepült a lib, akkor azt is leírom hogy mire kellett.
Tehát, a feldolgozandó kódban, egyes HTML tag-ek onmouseover eventjén van az alábbihoz hasonló kód:
jQuery("#1337").html("Leet");
Azaz rámutatáskor ad 1337 id-ű tag tartalma legyen a Leet string. Ilyen egyszerű.

Nem akartam az egész jQuery-t betölteni a memóriába, ezért inkább írtam egy kis kamu függvényt, amivel a fenti sor futtatható. Így néz ki:
var jQuery = function (unused){
    html = function(data){
        return data
    }
    return this;
}
A jQuery függvény visszatér a this-el, ami úgy mellékesen a window. Maga a függvény nem csinál semmit se a paraméterével. A függvény törzsében definiálunk egy html nevű függvényt. Ez globális lesz, így a window.html-en keresztül is elérhető.
Tehát amikor a jQuery visszatér a this-el, ott lesz már a window.html is, így működni fog method chaining (igazából nem fog működni, ahhoz megint csak this-el kellett volna visszatérni, de nekem most így is megfelel a kód).

Rakjuk össze az egészet és próbáljuk ki:

import PyV8
ctx = PyV8.JSContext()
ctx.enter()
ctx.eval('var jQuery=function(unused){html=function(data){return data};return this;}')
ctx.eval("jQuery('#1337').html('Leet')")
#>>>'Leet'

Először létrehozunk egy új contextet és bele is lépünk. Ez után betöltjük a függvényt, aztán kipróbáljuk hogy visszakapjuk-e a html-nek adott stringet, természetesen a Python interpreterben.
Az utolsó sorban látszik hogy ez megtörtént, úgyhogy nagy az öröm!

-slp

2013. február 9., szombat

Anaglif 3D kép előállítása Python és PIL segítségével

Az elmúlt napokban/hetekben háromdimenziós képek előállításával foglalkoztam. Hogy egész pontos legyek, csak azzal a részével, ahol a két kép egyé lesz. A mai 3D-s tartalom legnagyobb része SBS 3D módszerrel kerül kiadásra, ez az, amikor a bal- és a jobb szemnek szánt képek 1 db képre kerülnek rá, és ennek a képnek a jobb oldalán van a jobb szemnek szánt kép, és a bal oldalán a bal. Az ilyen képek megjelenítéséhez speciális eszközre van szükség, szóval egy 3D TV-re (vagy monitorra), de szerintem gondolni kell azokra is, akik nem szeretnének ilyen eszközköbe beruházni (pl.: én). Nekik az anaglif 3D módszer lehet egy (átmeneti) megoldás. Aki nem akarja elolvasni a wikipédiás cikket: ez az a módszer amikor piros-cián szemüveggel kell nézni a képet.

Tehát most ez utóbbival foglalkoztam. Egy olyan python scriptet raktam össze, ami benyel 2 képet, és kiadja magából az anaglif eredményt. Lássuk az elméletet mögötte:

Szemüveg

Image

A lényeg az, hogy a piros-cián szemüveg lencséi a fénynek csak egyes komponenseit engedik tovább a szem felé. A bal szemnek a piros, a jobbnak a cián színű jut, azaz annyi a feladatunk, hogy a két forrás képből egy olyan képet állítsunk elő, amin a bal forrásképnek csak a piros csatornája szerepel, és a jobb forrásképnek pedig a zöld és kék csatornája (hisz e két szín keveréke adja ki a ciánt). Ezt az egyszerű módszert hívják color anaglyphnek.

Ezeket a színcsatorna műveleteket mátrixok írják le. Nagy segítség, hogy a Stereoscopic Player készítőinek weboldalán több módszert is felsorolnak. A bejegyzés további részében az optimized anaglyph eljárás implementálását mutatom be.

Naív kód

Természetesen először körbenéztem, hogy mások hogy valósítják meg a feladatot. Szinte általános, hogy mindenki a mátrixműveletekhez a NumPy matematikai libraryt használja. Használhatnám én is, viszont azt szerettem volna, hogy minél kevesebb függősége legyen a kész scriptnek.
A képfeldolgozáshoz elengedhetetlen a Python Image Library (PIL) beszerzése, ezt nem tudtam kiküszöbölni. Szerencsére találtam egy gyors megoldást, amivel a NumPy nélkül is gyorsan elkészül az eredmény.

Az eredeti ötletem az volt, mint sok más embernek is, hogy végig haladok egy ciklussal mindkét képen, és minden pixelre értelmezem a mátrix műveleteket. Ez egy 640*480-as felbontású képnél 307,200 mátrix szorzás, aminél a számítógép általában sokkal többet is lazán elvégez, de sajnos a Python igen hamar lassúnak mutatkozik ilyen igénybevétel mellett.

Forrás képeknek a fenti 3dtv.at weblap DeAnaglyph oldalán levő képeket használtam, így könnyen le tudtam ellenőrizni hogy ugyan olyan képet generál-e az én kódom mint amilyenek a weboldalon vannak.

Lássuk a kódot:
from PIL import Image

def transform(l, r):
    #http://www.3dtv.at/Knowhow/AnaglyphComparison_en.aspx
    ml = ((0, .7, .3),
          (0, 0, 0),
          (0, 0, 0))

    mr = ((0, 0, 0),
          (0, 1, 0),
          (0, 0, 1))

    return int(ml[0][0] * l[0] + ml[0][1] * l[1] + ml[0][2] * l[2] +
               mr[0][0] * r[0] + mr[0][1] * r[1] + mr[0][2] * r[2]), \
           int(ml[1][0] * l[0] + ml[1][1] * l[1] + ml[1][2] * l[2] +
               mr[1][0] * r[0] + mr[1][1] * r[1] + mr[1][2] * r[2]), \
           int(ml[2][0] * l[0] + ml[2][1] * l[1] + ml[2][2] * l[2] +
               mr[2][0] * r[0] + mr[2][1] * r[1] + mr[2][2] * r[2])


def PIL_naive(left, right, out):
    l = Image.open(left)
    r = Image.open(right)

    pixel_left = l.load()
    pixel_right = r.load()

    for x in xrange(l.size[0]):
        for y in xrange(l.size[1]):
            pixel_right[x, y] = transform(pixel_left[x, y], pixel_right[x, y])

    cR, cG, cB = r.split()
    #Gamma correction on red channel. Value = 1.5
    cR = Image.eval(cR, lambda px: ((float(px) / 255) ** (1/1.5)) * 255)

    Image.merge('RGB', (cR, cG, cB)).save(out)

PIL_naive('sample1left.jpg', 'sample1right.jpg', 'pil_naive.jpg')

A transform() függvényben megadtam a két mátrixot, ez az ml és mr. A szorzás ki van fejtve a return utasításban, mert nem akartam még ciklusokkal is lassítani a programot. Amúgy valószínűleg még itt is lehetne kicsit gyorsítani, de ez már így marad.

A PIL_naive() függvény végzi a piszkos munkát.
A 20 & 21. sorban betöltődik a paraméterül kapott kép kép 1-1 változóba.
A 23 & 24. sorban a .load() metódus visszaad egy-egy pixel access objektumot, amivel közvetlenül bele lehet nyúlni a betöltött kép pixeleinek információiba.
A 26 & 26. sorban elindulunk függőlegesen és vízszintesen a bal oldali kép felbontása szerint. Általában a két kép ugyan olyan méretű szokott lenni, így én most a bal képnek a méretei szerint haladok.

A függvényünk szíve a 28. sorban van, itt történik a transzformáció. Létrehozhattam volna egy 3. Image objektumot, de spórolni akartam a memóriával, így egyből visszaírom a kiszámított pixel színét a jobb oldali képbe. Ez lehetne a bal is.

A 30. sorban akár be is fejezhetnénk és kiírhatnánk a képet a lemezre, de ennek a bejegyzésnek az írása közben láttam csak meg, hogy gamma korrekciót végeztek a kész kép piros csatornáján. Ezért a 30. sorban felbontjuk a már anaglif képet színcsatornákra.
A 32. sorban a a cR nevű piros színcsatorna minden pixeljére alkalmazzuk az 1.5-ös gamma korrekciót. Ehhez a pixel színének értékét leosztjuk 255-el, hogy 0 és 1 közé essen, majd elvégezzük a hatványozást az 1.5 reciprokával (így lesz világosabb a kép), majd a végén felszorozzuk 255-el a pixel színét, hogy 0 .. 255 közé essen újra az értéke.
A 34. sorban összefűzzük a csatornákat, és elmentjük a képet az out változóban levő string névvel.

Futtatjuk a kódot, és az eredmény:
Image
Összehasonlítva az eredeti képpel, szerintem tök egyformák.

Probléma: a sebesség

Ez a cikk azért született meg, mert a fenti kód, bár teljesen nyilvánvaló hogy mit csinál, de lassú. A mai napomat arra szántam, hogy átírom úgy a kódot, hogy több processzoron fusson. Az algoritmus felbontotta volna a képet annyi részre ahány processzormag van az aktuális számítógépben, majd mindegyik mag transzformálgatja a maga részét, a végén pedig összeragasztódnak a képek.

A fenti kód az én Core 2 Duo E8400-as gépemen 1.42 mp alatt fut le. Ez talán még elfogadható. Kipróbáltam a Raspberry Pi-men, ott 32.62 mp alatt készült el egy képpel, ami azért már eléggé sok.

A 2 magos gépen a várható gyorsulás legfeljebb kétszeres, tehát 700 ms, ami egyébként 1.4 FPS. Az RPi egymagos, azaz ott nem lesz gyorsabb.

Gyors konvertálás .convert() metódussal

Miközben olvasgattam a PIL kézikönyvet, a szemem a Image objektumok .convert() metódusánál erősen elkezdett csillogni. Ez a metódus képes átkonvertálni a kép palettáját egy mátrix segítségével. Gondoltam elég ha ide betápolom az anaglif mátrixokat, akkor mivel ez egy beépített metódus, biztos valahol a mélyben natív kód végzi majd a szorzást. Ez a gondolatom valószínűleg igaz is, mivel jelentős gyorsulást értem el így. De lássuk a kódot:
from PIL import Image, ImageChops

def PIL_only(left, right, out):
    #http://www.3dtv.at/Knowhow/AnaglyphComparison_en.aspx
    l = Image.open(left).convert('RGB', (0, .7, .3, 0,
                                         0, 0, 0, 0,
                                         0, 0, 0, 0))

    r = Image.open(right).convert('RGB', (0, 0, 0, 0,
                                          0, 1, 0, 0,
                                          0, 0, 1, 0))

    cR, cG, cB = ImageChops.add(l, r).split()
    cR = Image.eval(cR, lambda px: ((float(px) / 255) ** (1 / 1.5)) * 255)

    Image.merge('RGB', (cR, cG, cB)).save(out)

PIL_only('sample1left.jpg', 'sample1right.jpg', 'pil_only.jpg')

Ez a kód sokkal egyszerűbb, és lényegesen gyorsabb is.
Az érdemi munkát a PIL_only() függvény végzi.
Az 5. sorban betöltjük a left nevű argumentumban megkapott fájlnévhez tartozó fájlt, majd átkonvertáljuk a palettáját RGB-ből az adott mátrix szerint. A mátrixhoz hozzá kell csapni még egy oszlopot. Mondjuk az nem derült ki számomra konkrétan hogy ez az oszlop mit állít, csak feltételezem, hogy az alpha értéket. Mivel JPG képpel dolgozunk, és az nem támogatja az alphát, ezért ide szerintem amúgy akármit be lehetne írni.

A 13. sorban történik az izgalmas rész. Az ImageChops könyvtár .add() függvénye a két paraméterül kapott kép színcsatornáinak értékeit összeadja. A "Chops" amúgy a channel operations rövidítése, azaz csatorna műveletek. A naív implementációban is ez történt, csak ott kiszámolta a kód az egyik kép pixelének értékét, és azonnal hozzáadta a másik kép pixeléhez. Az összeadás ott is lehetett volna külön lépés.
Ugyan ebben a sorban, a .split() metódus felbontja a képet színcsatornákra. Erre ugye azért lesz szükség, hogy elvégezzük a gamma korrekciót a piros csatornán. Ez meg is történik a 14. sorban, hasonlóan a natív kódhoz.

Ezek után már csak a csatornák összefűzése következik, a függvényen kívül pedig a függvény hívása.

Eredmények


Gyorsabb? Mi az hogy! Az E8400-on 0.062 mp, ez 22.9x-es gyorsulás, ami már 16.12 FPS. A Raspberry Pi-n 0.8 mp, ami 40,7x-es gyorsulás. Ja és a kész kép:

Image

Pontosan ugyan úgy néz ki

Nem próbáltam ki hogy NumPy-vel gyorsabb lenne-e a naív kódom mint ami a PIL beépített .convert() metódusát használja, majd egyszer kipróbálom azt is.
Azt viszont kipróbáltam, hogy gyorsabb-e ha a gamma korrekcióban az értékeket előre kiszámolom, és utána csak egy tömböt indexelgetek, de sajnos nem értem el gyorsulást. Előfordulhat viszont, hogy több pixellel idővel megjelenik valamilyen gyorsulás.

2013. január 9., szerda

01 - Python telepítés

Még mielőtt akárminek is nekikezdenék, szeretném jelezni, hogy igazodva a kor igényeihez, ez a bejegyzés 2016. február 14-én újraírásra került. Az eredeti bejegyzésben még a Python 2.7.3-as verziójának telepítését ismertettem. Azóta gyakorlatilag az összes jelentős csomag Python 3 kompatibilis verziója elkészült, és magam is napi rendszerességgel Python 3 nyelvű fejlesztéssel foglalkozok.

Python 2 vagy Python 3?

Gyakran visszatérő kérdés a kezdő programozóktól hogy Python 2-vel vagy 3-al érdemes-e kezdeni. Ma már nem kérdés, hogy a Python 3.x verzió használata az ajánlott. A PEP 373 szerint, a 2-es ág fejlesztése 2020-ban fog végleg befejeződni. Ez már csak 4 év!

A Python beszerzése

A Python interpretert a https://www.python.org/downloads/ címről lehet beszerezni. Rögtön az menüsor alatt, egészen pontosan a sárga Download the latest versions of Python felirat alatti gombokkal lehet a jelenlegi két elterjedt verzió letölteni. A bejegyzés megírásakor a legfrissebb verzió a Python 3.5.1.

Linuxos felhasználók többnyire előnyt élveznek a telepítést illetően, ugyanis általában megtalálható a Python 3 a csomagkezelőben. Debian-alapú rendszereknél (pl.: Ubuntu) apt-vel könnyen telepíthető a megfelelő verzió:

$ sudo apt-get install python3

64-bites verziót akarok!

A letöltés oldalán, a Looking for a specific release? alatti táblázatban a jelenlegi- és korábbi verziók saját oldalaira lehet tovább navigálni. Itt keresd ki a legújabb verziót (aminek a legnagyobb a verziószáma, jelenleg ez a 3.5.1), majd kattints a verzió sorában a Download gombra. A betöltődő oldal alján, a Files táblázatban található az összes elérhető kiadás. 64-biten a Windows x86-64 executable installer-t kell letölteni.

A Python telepítése Windowson

A régen sem túl bonyolult telepítési folyamat mostanra annyira egyszerű lett, hogy ráfér az egész egyetlen screenshotra. A telepítő elindítása után ez az ablak fogad minket:


Python 3.5.1 telepítő ablaka

  1. Figyelj oda hogy az Add Python 3.5 to PATH be legyen pipálva. Így parancssorból bárhonnan indíthatod majd az interpretert. Ha netán már túlvagy ezen, és véletlenül kihagytad a pipát, akkor is működni fog a Python, de lehet hogy egyszer majd valamilyen probléma miatt kézzel neked kell elvégezned a beállítást. Egyszer… majd.
  2. Install Now, és már zajlik is a telepítés.
  3. A telepítés végén pedig Close

Mi települ fel?

Nem jelent meg semmi új ikon az asztalon, akkor mégis mi változott a rendszeren, mi települt fel?

  • A Python értelmező. Ez futtatja majd a .py fájlokat
  • A dokumentáció. Így internet nélkül is kéznél van az amúgy kiváló minőségű leírása a nyelvnek.
  • A pip. Ez egy csomagkezelő, amivel röhejesen egyszerűen lehet mindenféle kódot telepíteni a Pythonunkhoz, ami így csomó új, okos funkcióval bővíti a nyelvet.
  • Az IDLE és a tkinter. Az IDLE egy nagyon egyszerű fejlesztői eszköz, amibe beírhatsz pár sor Python kódot, és azonnal látod is az eredményét. A tkinter pedig egy grafikus felület, amivel nagyon-nagyon egyszerű kattingatós programokat lehet írni. Mellékesen az IDLE is ezt használja.
  • A Python test suite. A forráskód tesztelésére.

Az első program

Miben kell írni a Python programot?

A Python forráskódot plain text (szöveges dokumentum) fájlba kell írni, és .py kiterjesztéssel kell ellátni. Erre bármilyen egyszerű szövegszerkesztő, így a Notepad (Jegyzettömb) is megfelel. Microsoft Word, és az ahhoz hasonló szövegszerkesztők nem használhatóak.

A Jegyzettömb az első pár program elkészítéséhez még elegendő, de idővel érdemes lesz feljebb kapcsolni például Notepad++-ra, vagy profi fejlesztői eszközre, mondjuk PyCharm-ra (ami a személyes kedvencem).

Linuxon a nano bőven megteszi kezdésnek.

Hello World!

Tradicionálisan az első program bármilyen nyelven amit bemutatnak, egyszerűen annyit csinál, hogy kiírja a képernyőre azt a mondatot hogy Hello World! (Helló Világ!)

Indítsd el valamelyik kéznél levő szerkesztődet, és egyszerűen csak gépelj be annyit hogy:

print('Hello World!')

Mentsd el a fájlt, de ne .txt kiterjesztéssel, hanem .py-al.


.py fájl létrehozása

Jegyzettömbben, de úgy általában a szerkesztőkben ki lehet választani a mentés során, hogy milyen legyen a fájltípus. Itt válaszd a Minden fájl lehetőséget. Ezután a Fájlnév-hez olyan nevet adj meg, ami .py-ra végződik (nálam: hello_world.py)

A mentés után keresd meg a fájlt, és indítsd el. Egy előugró fekete ablak úgy egy szempillantásnyi időre megjelenik, majd el is tűnik. Ez azért van, mert a program azonnal véget is és a szöveg kiírása után, ezért kilép. Ahhoz hogy lássuk a program befejezése után is hogy az miket írt ki a képernyőre, a programot parancssorból (konzolból) kell futtatni.

Python program futtatása

Ha egy már meglevő parancssor ablakból indítjuk a kódot, akkor a program kilépése után láthatóak maradnak a program üzenetei, hisz a szülő ablak továbbra is futni fog.

Parancssor használata (Windows)

A parancssort legegyszerűbben a Futtatás ablakból könnyű előhalászni. Ehhez:

  1. Nyomd le a WINKEY + R billentyűkombinációt. (A WINKEY az a billentyű a billentyűzeten amire a Windows logót nyomtatták.). Megjelnik a Futtatás nevő ablak, lent a képernyő bal-alsó sarkában.
  2. Írd be hogy cmd majd nyomj entert.

Ezzel meg is érkeztünk a parancssorba. Már csak annyi van hátra,hogy elnavigáljuk magunka a fájlunkhoz. Itt van pár parancs azoknak, akik még sose jártak a parancssorban:

  • dir
    Ez a parancs kilistázza annak a könyvtárnak a tartalmát amiben épp benne vagyunk.
  • cd könyvtár
    Ezzel a paranccsal lehet megnyitni egy könyvtárat (mappát). A cd után a könyvtár nevét kell írni. Ha szóközt is tartalmaz a neve, akkor ” ” (idézőjel) közé kell írni a mappa nevét.
  • Ha pedig meghajtót akarunk váltani (pl.: A C:-ről a D:-re) akkor egyszerűen csak be kell gépelni a meghajtó betűjelét.

A sor elején mindig látszódik hogy épp melyik könyvtárban tartózkodunk. Ez a munkakönyvtár (working directory). Amikor elindul a parancssor, akkor a saját könyvtárunk a munkakönyvtár. Ez az a mappa ahol a Dokumentumok, Letöltések, Asztal, Képek, Zenék, Videók, … , könyvtárak találhatóak.

Tegyük fel hogy rögtön az asztalra mentettük a hello_world.py fájlt. Így néz ki a parancssor és a parancsok amiket be kell gépelni:

C:\Users\win7\>cd Desktop
C:\Users\win7\Desktop>python hello_world.py
Hello World!

Az 1. sorban beléptünk a Desktop könyvtárba, majd a python hello_world.py paranccsal futtattuk a hello_world.py-t. Egészen pontosan az történt, hogy a python program elkezdte futtatni a hello_world.py fájl tartalmát. Ha a telepítés során nem pipáltátok be, hogy Add Python 3.5 to PATH, akkor előfordulhat, hogy azt írja a parancssor, hogy A megadott nevet (python) a rendszer nem ismeri fel […]. Ekkor meg lehet próbálni futtatni a fájlt úgy, hogy egyszerűen begépelitek a nevét:

C:\Users\win7\Desktop>hello_world.py
Hello World!

A terminál használata (Linux)

Nem veszek rá mérget hogy tényleg szükséges-e egy rendes Linux felhasználónak magyaráznom, hogy hogyan kell mozogni a könyvtárakban, de azért a biztonság kedvéért röviden leírom a történetet.

  • cd könyvtár
    Ugyan úgy történik a könyvtárváltás mint a parancssorban. A cd után annak a mappának a nevét kell írni, amit meg akarunk nyitni. Ha szóközt tartalmaz ez a név, akkor ” ” (idézőjel) közé kell írni a mappa nevét.
  • ls
    Ez a parancs kilistázza az aktuális könyvtár tartalmát.

Disztrótól függ, hogy hogyan lehet elővarázsolni a terminált. Én Lubuntu-t használok, és ott a CTRL + ALT + T a megfejtés.

Ha odaértünk a fájlhoz, akkor úgy ahogy Windowson is, így futtathatjuk a kódot:

$ python hello_world.py
Hello World!

Konzolos program, grafikus program

Elsőre lehet meglepő, hogy miért kell ilyen ocsmány, DOS-os kőkorszaki ablakban nézni hogy mit ír ki a program. Miért nincs rendes ablak, kerettel, meg gombokkal, és miért nem lehet kattingatni?!

Kétféle programot különböztetünk meg egymástól, a parancssori (konzolos) alkalmazásokat (CLI), és a grafikus felületűeket (GUI). Windowson megszokott, hogy minden programnak szép ablaka van, de ezt egyáltalán nem triviális leprogramozni. Ezért egy jó ideig olyan programokat fogunk írni, amiknek nincs semmi ablakuk. Ez nem jelenti hogy ezek elavultak, vagy korlátozott szoftverek lennének!

Csendben megjegyzem, hogy idén (a bejegyzés újraírásakor) 6 éve hogy már programozok, és eddig összesen 3 grafikus felületű programot kellett írnom.

Zárunk

Ha minden úgy ment ahogy odafent írtam, akkor sikeresen feltelepült a Python interpreter, és ki is próbáltuk hogy működik-e minden rendesen. Tudjuk hogy hogy lehet úgy futtatni a kódot hogy a befejezése után ne vesszen el az eredménye, úgyhogy azt hiszem kijelenthetjük, hogy minden megvan hozzá hogy programozóvá váljunk.

Ez a bejegyzés a Python tutorialom egyik része. Az összes rész listája itt fellelhető.

-slp