Python alapok

Ez a leírás Python 3.5-ös verziójához készült, de bármilyen Python 3.3 feletti verzióhoz használható.

Az anyag elsajátításához nem szükséges Pythont és Jupytert telepíteni, de teljes értékűbb, ha te is ki tudod próbálni, át tudod írni az itt szereplő kódrészleteket. Amennyiben nem szeretnéd kipróbálni, ugorj a Python gyorstalpalóra.

Előkészületek

Két lehetőségünk van:

  1. Anaconda telepítése: az Anaconda egy nagyméretű Python disztribúció, több mint 300 csomaggal.
  2. Kézi telepítés: 6-8 csomagot fogunk használni, ezeket kézzel is fel lehet telepíteni a pip (python package installer) segítségével

1. Anaconda telepítése

https://www.continuum.io/downloads

2. Kézi telepítés

Python telepítése

https://wiki.python.org/moin/BeginnersGuide/Download

IDE-t (PyCharm) nem szükséges telepíteni, mert a felkészüléshez szükséges feladatokat ebben a notebookban lehet futtatni.

Jupyter (IPython notebok telepítése)

http://jupyter.readthedocs.org/en/latest/install.html (a Python telepítését is tartalmazza)

További csomagok

A Pythonnal együtt feltelepült a pip nevű csomagkezelő, amellyel minden további csomag telepíthető az alábbi paranccsal:

pip install csomagnév

A következő csomagokra mindenképp szükségünk lesz:

  1. Ehhez a notebookhoz: jupyter
  2. A pandas laborhoz: jupyter numpy scipy scikit-learn pandas matplotlib

Notebook betöltése

Most pedig ezt a notebookot fogjuk megnyitni és szerkeszteni.

  1. Töltsük le a git repositoryt (zip fájlként vagy git klienssel): https://github.com/juditacs/labor
  2. Nyissunk egy terminált/Command Line-t és navigáljunk el a letöltött (és kicsomagolt) repóhoz
  3. írjuk be a jupyter notebook parancsot, aminek hatására az alapértelmezett böngészőben megnyílik a jupyter fájlnézegetője. Ha mégsem nyílna meg, akkor a http://localhost:8888 -on találjuk alapértelmezetten (a port felüldefiniálható).
  4. Navigáljunk el a Python_alapok.ipynb nevű fájlhoz és indítsuk el

Jupyter notebook alapok

A Jupyter notebookban cellákba rendezve keverhető a forráskód (Python, de más nyelvek is támogatottak), a Markdown szöveg és képek, illetve grafikonok. A Jupyter egyre népszerűbb kutatási és oktatási projektekben, a gravitációs hullámok felfedezői is ezt használták tutorial

Minden notebook cellákból épül fel, amik többfélék lehetnek:

  1. code: forráskód cella. A cellák melletti szögletes zárójelek üresek, ha a cellában lévő kód még nem futott le, *-ot tartalmaznak, ha éppen fut és egy számot, ha már lefutott a cella. A kiíró utasítások és az utolsó utasítás eredménye megjelenik a cella alatt.
  2. markdown: Markdown szöveges cella. LateX-es képleteket is tartalmazhat. A Markdownhoz egy rövid ismertető itt.
  3. raw: nyers szövegmező.

Kiválaszthatunk egy vagy több szomszédos cellát, egy választása esetén kékkel jelöli a választottat. Ekkor Command mode-ban vagyunk. Az Enter lenyomásával vagy dupla kattintással léphetünk Edit mode-ba. Edit módból Esc-pel tudunk Command módba lépni. Command módban érhető el a Help a H gomb megnyomásával, ami tartalmazza az összes gyorsbillentyűt. Ezeket érdemes tanulmányozni és kipróbálni.

A cellákat többféle módon futtathatjuk:

  1. Ctrl+Enter: lefuttatja az aktuális cellát.
  2. Alt+Enter: lefuttatja az aktuális cellát és létrehoz alatta egy újat.
  3. Shift+Enter: lefuttatja az aktuális cellát és kiválasztja az alatta lévőt, de nem hoz létre újat.
  4. Cell/Run all menü: lefuttatja az összes cellát.

A notebook mögött egy ún. kernel fut, ami azt jelenti, hogy a cellák közös interpretert használnak, tehát a változók közösek.

További hasznos információk:

  • Command módban az A megnyomásával szúrhatunk be az aktuális cella fölé egy újat, B-vel alá.
  • tab completion az első mélységig működik
  • létre lehet hozni checkpointot
  • cellánként külön lehet visszavonni Ctrl+Z-vel Edit módban
  • autosave funkció van, de érdemes menteni is
  • egy notebook valójában egyetlen XML fájl
  • tab completion a fájlrendszerre is vonatkozik
  • a cellákat tetszőleges sorrendben futtathatjuk, ekkor a változók mindig olyan értékűek, amit az utoljára futtatott cellában beállítunk
  • minden cella alatt megjelenik az utolsó kifejezés visszatérési értéke (kivéve, ha print az utolsó kifejezés), de ez nem aranyos a kiírással

Python gyorstalpaló

Hello world


In [1]:
print("Hello world\nvagy magyarul: Szia világ")


Hello world
vagy magyarul: Szia világ

Szintaxis

Kötelező az indentálás, 4 space a konvenció. Az indentálás jelöli a blokkok elejét és végét. A Jupyter automatikusan indentálja a következő sort, ha :-vel végződik az előző.


In [2]:
for x in range(3):
    print(x)


0
1
2

A #-kal kezdődő sorok kommentek, többsoros komment """-pal kezdődik és végződik.


In [3]:
# én egy egysoros komment vagyok
"""
én egy többsoros komment vagyok
"""


Out[3]:
'\nén egy többsoros komment vagyok\n'

Az értékadás és az összehasonlítás szintaxisa megegyezik a C-s szintaxissal:

  1. = értékadás
  2. == összehasonlítás

In [4]:
x = 6
print(x, x == 6, x == 3)


6 True False

Típuskezelés

Erősen típusos, tehát az interpreter számon tartja, hogy melyik változó milyen típusú. A típus lekérdezhető.


In [5]:
type(x), isinstance(x, int)


Out[5]:
(int, True)

Nincs implicit cast


In [6]:
# print("x: " + x) # TypeErrort ad
print("x: " + str(x)) # ez már helyes
print("x: {0}".format(x))  # python format string, automatikusan meghívja a paraméterekre az str függvényt


x: 6
x: 6

Dinamikus típusok


In [7]:
x = 6
print("x típusa: ", type(x))
x = "foo"
print("x típusa: ", type(x))


x típusa:  <class 'int'>
x típusa:  <class 'str'>

Miért nem kellett str(type(x))-et használni? Mert a print függvény a vesszővel elválasztott tetszőleges számú paraméterét kiírja. Az előző példában a + operátor hívásakor szükség lett volna az int paraméter implicit konverziójára.

Egyéb:

  • A paraméterek nevei case-sensitive-ek.
  • Minden osztály.

Típusok

Immutable típusok

  1. int
  2. float
  3. str
  4. tuple
  5. bool

In [8]:
i = 2
f = 3.2
s = 'abc'  # s[1] = 'a' hibát adna
t = (i, f, s)
b = True  # False
type(i), type(f), type(s), type(t), type(b)


Out[8]:
(int, float, str, tuple, bool)

A tuple elemei indexelhetők.


In [9]:
t[1]


Out[9]:
3.2

Mutable típusok

  1. dict: hash tábla alapú adattípus
  2. set: halmaz. Értelmezettek a halmaz alapműveletek, mint a metszet (set1 & set2), az unió (set1 | set2) vagy a különbség (set1 - set2)
  3. list: alapvető tároló. Nem láncolt lista, hanem dinamikus tömb.

Null objektum

Egy ilyen objektum létezik None néven. Ez a függények visszatérési értéke, ha nincs valami mást visszaadó return utasítás. Lehet rá külön vizsgálni:


In [10]:
print('A None None-e: {}'.format(None is None))
print('A False None-e: {}'.format(False is None))
print('A 0 None-e: {}'.format(0 is None))


A None None-e: True
A False None-e: False
A 0 None-e: False

Stringkezelés

Alapértelmezetten unicode, ami kiíráskor kódolódik a rendszer default karakterkódolásába. Ez Python2-ben még nem így volt, kézzel kellett kódolni és dekódolni.

Rengeteg beépített stringkezelő függvény és rendkívül rugalmas címzési lehetőségek állnak rendelkezésünkre.


In [11]:
s = 'ez egy alma, az pedig egy Álma'
print(len(s))
print(s.startswith('abc'), s.endswith('a'))
try:
    s[1] = 'n'
except TypeError:
    print("Assignment failed")

print("A 20. karaktertől: {0}".format(s[20:]))
print("A 5-19. karakterig: {0}".format(s[5:20]))  # a záróindex nincs benne!
print("A legutolsó karakter: {0}".format(s[-1:]))


30
False True
Assignment failed
A 20. karaktertől: g egy Álma
A 5-19. karakterig: y alma, az pedi
A legutolsó karakter: a

Dictionary

A beépített dict típus egy kulcs-érték párokat tartalmazó adatszerkezet. A kulcsok csak olyan objektumok lehetnek, amikből hash számolható (de ezt a hash függvényt mi magunk is definiálhatjuk), az értékekre nincs megkötés.


In [12]:
d = {'a': 1, 'b': 2}
d['c'] = 3
d


Out[12]:
{'a': 1, 'b': 2, 'c': 3}

In [13]:
try:
    d['d']
except KeyError:
    print("Upsz")


Upsz

Lista

A list típus az STL vectorhoz hasonló listát implementál, tehát a háttérben tömb van, nem pedig láncolt lista.

Lista létrehozása:


In [14]:
l = [1, 2, 3, 'négy', 'öt']  # az elemek tetszőleges típusúak lehetnek

Az str-hez hasonlóan címezhető:


In [15]:
print("Az első két elem: {}".format(l[:2]))
print("A kettes indexű elem: {}".format(l[2]))
print("Az 1-3-as indexű elem: {}".format(l[1:4]))


Az első két elem: [1, 2]
A kettes indexű elem: 3
Az 1-3-as indexű elem: [2, 3, 'négy']

Hatékonyan tudunk a végéhez új elemet fűzni:


In [16]:
l.append(6)
l


Out[16]:
[1, 2, 3, 'négy', 'öt', 6]

Számsorozatok

A beépített range függvénnyel lehet számsorozatokat generálni. Egy kötelező paramétere van: a tartomány vége.


In [17]:
print(list(range(5)))


[0, 1, 2, 3, 4]

Két dolgot is megfigyelhetünk:

  1. jobbról nyitott intervallumot generál, tehát a range(a) 0-tól a-1-ig generálja le az egészeket.
  2. list-té kellett konvertálni, mert range egy generátorral tér vissza. Részletekre most nem térünk ki.

További lehetőségek:


In [18]:
print("Számok -5-től 2-ig: {}".format(list(range(-5, 3))))
print("Számok kettesével: {}".format(list(range(0, 20, 2))))


Számok -5-től 2-ig: [-5, -4, -3, -2, -1, 0, 1, 2]
Számok kettesével: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

Operátorok

Az operátorok nem sokban térnek el a C/C++-ban megszokott operátoroktól, kivéve a következőket:

  • a logikai vagy és a logikai és ||, illetve && helyett az or és az end kulcsszavakkal használható

In [19]:
a = 2
b = 3
print(a == 2 and b == 3)
print(a == 1 or b < 2)


True
False
  • létezik egész osztás, ami két float hányadosának az egészrészét adja meg

In [20]:
3.2 / 1.1, 3.2 // 1.1


Out[20]:
(2.909090909090909, 2.0)

Létezik hatványozó-operátor


In [21]:
2 ** 4


Out[21]:
16

A bitwise ÉS és VAGY megegyezik a C-s operátorokkal.

Függvények

Függvényt a def kulcsszóval hozhatunk létre. A visszatérési érték típusát nem kell deklarálni és explicit return utasítás elhagyása esetén None-nal térnek vissza a függvények. Alapértelmezett értékek adhatók a paramétereknek, ahogy C++-ban megszoktuk:


In [22]:
def print_my_name(firstname, lastname, title='Ms.'):
    print('Hello {0} {1} {2}!'.format(title, firstname, lastname))  # format string, részletesebben ld. dokumentáció

Függvény hívásakor kétféleképpen adhatunk át paramétert:

  1. pozíciónálisan
  2. név szerint

In [23]:
print_my_name('Jakab', 'Gipsz', 'Mr')
print_my_name(lastname='Marga', firstname='Rita')


Hello Mr Jakab Gipsz!
Hello Ms. Rita Marga!

Osztályok

A Python támogatja a megszokott OOP funkciókat. Osztályok létrehozása a class kulcsszóval történik:


In [24]:
class A:
    pass  # ez a pythonos NOP

Konstruktort a init magic (tényleg!) függvénnyel írhatunk. Destruktort - garbage collectoros nyelv lévén - nincs. A del hívódik az objektum begyűjtésekor, azonban nem tudjuk, mikor fut le ez a függvény.


In [25]:
class A:
    def __init__(self, param=42):
        self.p = param

Minden metódusnak kötelező átvennie explicit a self paramétert, ezen keresztül fogja elérni az objektum attribútumait.


In [26]:
class NamePrinter:
    def __init__(self, firstname, lastname, title='Ms.'):
        self.firstname = firstname
        self.lastname = lastname
        self.title = title
        
    def greet_with_title(self):
        print('Hello {0} {1} {2}'.format(self.title, self.firstname, self.lastname, self.title))
        
        
    def greet_without_title(self):
        print('Hello {0} {1}'.format(self.firstname, self.lastname))

A példányosítás ugyanúgy paraméterezhető, mint a függvényhívás.


In [27]:
nm1 = NamePrinter('Jakab', 'Gipsz', 'Mr')
nm2 = NamePrinter(lastname='Marga', firstname='Rita')
nm1.greet_with_title()
nm2.greet_without_title()


Hello Mr Jakab Gipsz
Hello Rita Marga

Disclaimer

A Python nyelv funkcióinak gazdagsága miatt nincs lehetőség minden részletet bemutatni, nem is erre törekedtem. Igyekeztem a laborhoz hasznos információkra felhívni a figyelmeteket.

Az anyag folyamatosan bővül. Ha érdekel, kövesd a repositoryt (Watch gomb).

Az esetleges hibákat kérlek jelezd nekem a emailben [keresztnevem] at aut_bme-hu email címen vagy GitHub issue-ban.