Informatika2-2014/teszt

A MathWikiből
(Változatok közti eltérés)
(a pythononline.org tesztelése)
1. sor: 1. sor:
 +
=Bevezetés a Python nyelvbe=
 +
 +
Az előadáshoz elsőszámú olvasmány a [http://docs.python.org/2.7/tutorial/ Python tutorial].
 +
 +
A Pythont ismerjük a Sage-ből.
 +
Különbségek:
 +
* ^ helyett ∗∗, / osztást, // egészosztást jelöl.
 +
* [a..b] helyett range(a,b), vagy xrange(a,b)
 +
* A megszokott, beépített matematikai függvények hiányoznak (find_root, plot, is_prime), de különböző modulokban sokuk megtalálható.
 +
* Nincsenek szimbolikus változók
 +
 +
A Python egy olyan általános körben használható magas szintű programozási nyelv, aminek az egyik alapelve az olvasható kód írása egy nagyon tiszta szintaxis használatával. 1991-ben alkotta meg [http://en.wikipedia.org/wiki/Guido_van_Rossum Guido Van Rossum.]
 +
 +
További jellemzők
 +
* objektum orientált, procedurális, funkcionális
 +
* sok beépített modul a fejlesztés megkönnyítésére
 +
* dinamikus típus kezelés
 +
* automatikus memóriakezelés
 +
* többféle megvalósítás (CPython, Jython, IronPython, PyPy, Python for S60)
 +
* open-source a főbb platformokra
 +
* sokkal tömörebb sok más nyelvnél
 +
 +
Nevét a Monthy Python ihlette, nem az állat.
 +
 +
Filozófiája megkapható a 'this' modul betöltésével:
 +
 +
  import this
 +
 +
 +
== Python kód futtatása ==
 +
 +
=== Interaktív módon ===
 +
 +
Egyszerűen a python parancs terminálból indítva:
 +
 +
<bash>
 +
$ python
 +
Python 2.7.5+ (default, Sep 19 2013, 13:48:49)
 +
[GCC 4.8.1] on linux2
 +
Type "help", "copyright", "credits" or "license" for more information.
 +
>>>
 +
</bash>
 +
 +
=== Fájlból ===
 +
 +
* Nyiss egy új file-t pl. a ''gedit''-ben, mentsd el "kerdez.py" néven egy könyvtáradba!
 +
* Írd bele a következő python kódot (ne használj ékezeteket):
 +
<python>
 +
s = input("Mondj egy szamot: ")
 +
print "Ennel eggyel kisebbet mondtal: ", s + 1
 +
</python>
 +
* Mentsd el, és futtasd a scriptedet! (''python kerdez.py'')
 +
* Most kicsit kiegészítjük a scriptet, hogy tartalmazhasson ékezetes betűket, és hogy kényelmesebben futtatható legyen (a ''python'' parancs begépelése nélkül is):
 +
<python>
 +
#!/usr/bin/python
 +
#coding=UTF-8
 +
s = input("Mondj egy számot: ")
 +
print "Ennél eggyel kisebbet mondtál: ", s + 1
 +
</python>
 +
* Mentsd el, és adj rá  futtatási jogot csak magadnak (<code>chmod +x kerdez.py</code>)!
 +
* Futtasd így: <code>kerdez.py</code> vagy így: <code>./kerdez.py</code>
 +
* A kód második sora lehet ez is:
 +
<python>
 +
# -*- coding: utf-8 -*-
 +
</python>
 +
 +
=== Argumantum átadása ===
 +
 +
<python>
 +
#!/usr/bin/env python
 +
#coding=utf-8
 +
# Összead tetszőleges számú számot
 +
import sys  # modul a rendszerfüggő információkhoz
 +
 +
osszeg = sum(float(arg) for arg in sys.argv[1:])
 +
print 'Összeg =', osszeg
 +
</python>
 +
 +
Ha e fájl az osszeg.py nevű fájlba van mentve, akkor
 +
 +
<bash>
 +
$ ./osszeg.py 12 23.5 1
 +
36.5
 +
</bash>
 +
 +
== Kódolás stílusa ==
 +
 +
Stílus (code style) a [http://www.python.org/dev/peps/pep-0008 PEP 8 alapján]
 +
* használj mindig 4 space-t minden egyes szinthez, de a folytatósort kezd még beljebb,
 +
* a nagyobb kódrészeket tagold üres sorokkal (függvény, osztály, nagyobb kód blokk)
 +
* használj space-t a vesző után és a legmagasabb szinten lévő operátorok körül
 +
* használj docstring-et és ahol lehet a megjegyzés a saját sorára vonatkozzon, vagy azonos mértékben behúzva arra a blokkódra
 +
* ahol lehet használj ASCII karakterkódolást
 +
* 79 karakternél ne legyen hosszabb egy sor
 +
* CamelCase elnevezési konvenciót kövesse az osztályok neve és lower_case_with_underscores a függvények és változók nevei
 +
 +
Érdemes megnézni a Google [http://google-styleguide.googlecode.com/svn/trunk/pyguide.html python code style] ajánlását is.
 +
 +
== Docstring ==
 +
 +
A hivatkozás nélküli string elemet szokás használni megjegyzések írására és dokumentálásra.
 +
<python>
 +
"""This is a class of example.
 +
 +
TODO: needs implementation.
 +
"""
 +
</python>
 +
Első sort nagybetűvel kezdjük és pontal zárjuk. Egy összefoglaló mondat legyen. Majd egy üres sort hagyva részletesen leírhatunk minden funkciót amit az osztály vagy függvény tartalmaz. Megadhatjuk, hogy a függvény bizonyos hívásaira mi legyen a válasz,
 +
 +
Hasznos linkek:
 +
* [http://www.python.org/dev/peps/pep-0257/ hogyan érdemes használni a docstringet]
 +
* [http://docs.python.org/library/doctest.html tesztelés docstring segítségével]
 +
 +
<Python>
 +
#coding=utf-8
 +
def lnko(a, b):
 +
    """Kiszámolja két szám legnagyobb közös osztóját.
 +
 +
    >>> lnko(36, 8)
 +
    4
 +
    >>> lnko(-36, 4)
 +
    4
 +
    >>> lnko(3, 0)
 +
    3
 +
    """
 +
   
 +
    a, b = abs(a), abs(b)
 +
    while a != 0:
 +
        a, b = b%a, a
 +
    return b
 +
 +
if __name__ == "__main__":
 +
    import doctest
 +
    doctest.testmod()
 +
</Python>
 +
 +
Ha <code>lnko.py</code> a neve, akkor egy
 +
<bash>
 +
python lnko.py
 +
</bash>
 +
parancs után nem kapunk semmit (mert a teszt hiba nélkül lefutott), azonban a -v opciót is használva látjuk a részleteket is:
 +
<bash>
 +
$ python lnko.py -v
 +
Trying:
 +
    lnko(36, 8)
 +
Expecting:
 +
    4
 +
ok
 +
Trying:
 +
    lnko(-36, 4)
 +
Expecting:
 +
    4
 +
ok
 +
Trying:
 +
    lnko(3, 0)
 +
Expecting:
 +
    3
 +
ok
 +
1 items had no tests:
 +
    __main__
 +
1 items passed all tests:
 +
  3 tests in __main__.lnko
 +
3 tests in 2 items.
 +
3 passed and 0 failed.
 +
Test passed.
 +
</bash>
 +
 +
 +
== A Python, mint számológép ==
 +
 +
=== Azonosítók ===
 +
 +
Az adatokat többszöri felhasználásra ''azonosítóval'' (''névvel'') láthatjuk el.
 +
 +
* a név betűvel vagy aláhúzással kezdődhet: [_a-zA-Z]
 +
* a név további karakterei az előbbieken felül számok is lehetnek: [_a-zA-Z0-9]
 +
* elméletileg bármilyen hosszú lehet a név
 +
* név nem lehet foglalt szó
 +
* nagybetű-kisbetű érzékeny, tehát a val1 név nem azonos a Val1 névvel
 +
 +
Másképp, Backus–Naur formában leírva:
 +
<bnf>
 +
identifier ::=  (letter|"_") (letter | digit | "_")*
 +
letter    ::=  lowercase | uppercase
 +
lowercase  ::=  "a"..."z"
 +
uppercase  ::=  "A"..."Z"
 +
digit      ::=  "0"..."9"
 +
</bnf>
 +
 +
A foglalt szavak:
 +
<code>
 +
and      del      from      not      while
 +
as        elif      global    or        with
 +
assert    else      if        pass      yield
 +
break    except    import    print
 +
class    exec      in        raise
 +
continue  finally  is        return
 +
def      for      lambda    try
 +
</code>
 +
De ne használjuk a Python beépített neveinek, függvényeinek, kivételeinek neveit sem. Ezek megkaphatók a <code>dir(__builtins__)</code> paranccsal:
 +
<Python>
 +
>>> dir()
 +
['__builtins__', '__doc__', '__name__', '__package__']
 +
>>> dir(__builtins__)
 +
['ArithmeticError', 'AssertionError', ......
 +
</Python>
 +
 +
=== Egész szerű adattípusok: egész (int, long), logikai (bool) ===
 +
 +
'''int (egész) és hosszú egész (long)'''
 +
<python>
 +
>>> a = 12
 +
>>> b = 0b011101
 +
>>> c = 0o3701
 +
>>> d = 0xff0c
 +
>>> a, b, c, d
 +
(12, 29, 1985, 65292)
 +
>>> e = 22222222222222222222222222222222222222222
 +
>>> e
 +
22222222222222222222222222222222222222222L
 +
>>> type(a), type(b), type(e)
 +
(<type 'int'>, <type 'int'>, <type 'long'>)
 +
</python>
 +
 +
Műveletek egészekkel: +, -, *, / (float eredményt ad), //,
 +
% (maradék), **, abs, pow, round,
 +
| (OR butenként), ^ (XOR bitenként), & (AND bitenként), <<, >> (eltolás bitenként), ~ (bitenkénti NOT)
 +
 +
'''Logikai (bool)''' típus:
 +
 +
Logikai értékek: False (0 vagy 0 hosszúságú), True (nem 0 vagy nem 0 hosszúságú)
 +
 +
Logikai műveletek: and, or, not
 +
 +
<python>
 +
>>> True and False
 +
False
 +
>>> 1 and 0
 +
0
 +
>>> 3 and 0
 +
0
 +
>>> 3 or 1
 +
3
 +
>>> 1 or 3
 +
1
 +
>>> not 67
 +
False
 +
>>> not 0
 +
True
 +
</python>
 +
 +
=== Beépített lebegőpontos típusok (float, complex) ===
 +
 +
<!-- WF: PÉLDÁT IDE: A műveletek eredménye NaN (not a number) és infinity is lehet! -->
 +
 +
'''Lebegőpontos''' szám megadása:
 +
<python>
 +
>>> 2.3, -1.2e3, -1.2e-2
 +
(2.2999999999999998, -1200.0, -0.012)
 +
</python>
 +
Matematikai  függvények:
 +
<python>
 +
import math
 +
</python>
 +
után. Ld. [http://docs.python.org/2/library/math.html]
 +
 +
'''Komplex szám''' imaginárius része után '''j''' betű, de * nincs!
 +
Komplex '''jellemzői (attribute)''' a real és az imag,
 +
'''tagfüggvénye (method)''' conjugate():
 +
<python>
 +
>>> z = 3.1 + 2.2j
 +
>>> z
 +
(3.1000000000000001+2.2000000000000002j)
 +
>>> z.real
 +
3.1000000000000001
 +
>>> z.imag
 +
2.2000000000000002
 +
>>> z.conjugate()
 +
(3.1000000000000001-2.2000000000000002j)
 +
</python>
 +
 +
=== Karakterláncok (str) ===
 +
 +
'''A karakterláncok megadása''': "...", '...' vagy """...""" módon történhet:
 +
<python>
 +
>>> a="""itt 'ez' meg "az" van"""
 +
>>> a
 +
'itt \'ez\' meg "az" van'
 +
>>> print a
 +
itt 'ez' meg "az" van
 +
>>> type(a)
 +
<type 'str'>
 +
 +
>>> c = 'aa\nbb' 
 +
>>> c
 +
'aa\nbb'
 +
>>> print c
 +
aa
 +
bb
 +
 +
>>> d = r'aa\nbb'  # az r betű után minden karakter magát jelenti
 +
>>> d
 +
'aa\\nbb'
 +
>>> print d
 +
aa\nbb
 +
</python>
 +
 +
'''Védőkódok (eszkép karakterek, escape characters)''':
 +
\ (folytatás új sorban), \\ (\), \' ('), \" ("),
 +
\n (új sor), \t (tab). Ha a karakterlánc elé '''r''' betűt írunk, a védőkódok nem érvényesek.
 +
 +
'''Műveletek''' karakterláncokkal:
 +
indexelés és szeletelés:
 +
<python>
 +
lánc[sorszám]
 +
lánc[kezdet:vég]
 +
lánc[kezdet:vég:lépés]
 +
</python>
 +
továbbá az '''+''' (összefűzés) és a '''*''' (többszörözés) műveletek:
 +
<python>
 +
>>> a = "ho"
 +
>>> b = "rgasz"
 +
>>> 3*a + b
 +
'hohohorgasz'
 +
 +
>>> c = _      # _ az előző eredmény
 +
>>> c
 +
'hohohorgasz'
 +
>>> c[:2]+c[6:]
 +
'horgasz'
 +
>>> c[1:7:2]
 +
'ooo'
 +
>>> c[1:6:2]
 +
'ooo'
 +
>>> c[-1::-1]
 +
'zsagrohohoh'
 +
>>> c[-3:4:-1]
 +
'agro'
 +
</python>
 +
 +
Az indexekre kétféleképp gondolhatunk:
 +
1. a második index már nincs (ennek pl. az az értelme, hogy egy intervallum végét, és a következő elejét azonos érték jelzi, nem kell 1-et hozzáadni),
 +
2. az indexeket az elemek közé képzeljük, vagyis az elemek határait indexeljük:
 +
 +
<bash>
 +
+---+---+---+---+---+---+---+
 +
| h | o | r | g | a | s | z |
 +
+---+---+---+---+---+---+---+
 +
0  1  2  3  4  5  6  7
 +
-5  -6  -5  -4  -3  -2  -1
 +
</bash>
 +
 +
Metódusok (tagfüggvények, methods): részletesen lásd
 +
[http://docs.python.org/release/2.5.2/lib/string-methods.html]. Folytatva az előző példát:
 +
<python>
 +
>>> c.capitalize()
 +
'Hohohorgasz'
 +
>>> c.upper()
 +
'HOHOHORGASZ'
 +
>>> c.index('o')
 +
1
 +
>>> c.count('o')
 +
3
 +
</python>
 +
 +
'''A karakterláncok nem változtatható (immutable) objektumok''', vagyis a műveletek, tagfüggvények alkalmazása után új karakterlánc keletkezik:
 +
<python>
 +
>>> a = "aaaa"
 +
>>> a[1] = b
 +
Traceback (most recent call last):
 +
  File "<stdin>", line 1, in <module>
 +
TypeError: 'str' object does not support item assignment
 +
</python>
 +
 +
 +
=== Objektumhivatkozások ===
 +
 +
Az értékadás (=) esetén valójában '''objektumhivatkozás''' történik, azaz az egyenlőség bal oldalán álló névhez egy hivatkozás kapcsolódik, mely az egyenlőség jobb oldalán álló objektumra mutat. Ez érthetővé teszi a következő kódot:
 +
<python>
 +
>>> a = 1
 +
>>> b = a
 +
>>> a = 2
 +
>>> a
 +
2
 +
>>> b
 +
1
 +
</python>
 +
A Python '''dinamikusan típusos''' nyelv, azaz az objektum, amire egy objektumhivatkozás mutat, lecserélhető egy más típusú objektumra (nem kell a változók típusát deklarálni).
 +
<python>
 +
>>> a = 1
 +
>>> type(a)
 +
<type 'int'>
 +
>>> a = "b"
 +
>>> type(a)
 +
<type 'str'>
 +
</python>
 +
 +
 +
 +
=== Listák ===
 +
 +
Ugyanúgy lehet '''szeletelni (slice)''', összeadni, többszörözni, mint a karakterláncot, de '''a lista változtatható (mutable)''':
 +
 +
<python>
 +
>>> x = [1, 2, 3, 4]
 +
>>> x[:2]*2 + x[-1:]
 +
[1, 2, 1, 2, 4]
 +
>>> x[:2]*2 + x[-1]
 +
Traceback (most recent call last):
 +
  File "<stdin>", line 1, in <module>
 +
TypeError: can only concatenate list (not "int") to list
 +
>>> x[0::2]
 +
[1, 3]
 +
>>> x[-1::-1]
 +
[4, 3, 2, 1]
 +
</python>
 +
 +
Objektumhivatkozás átadása, és '''sekély másolás (shallow copy)''', azaz a belső szinteken nem történik másolás, csak a hivatkozások másolódnak:
 +
 +
<wikiframe width="800" frameborder="0" src="http://pythontutor.com/iframe-embed.html#code=x+%3D+%5B0,+%5B4,+5%5D,+3%5D%0Ay+%3D+x+++++++%23+hivatkoz%C3%A1s%0Az+%3D+x%5B%3A%5D++++%23+sek%C3%A9ly+m%C3%A1sol%C3%A1s+(shallow+copy)%0Ay%5B1%5D+%3D+1%0Az%5B1%5D+%3D+2%0Aprint+%22x+%3D%22,+x%0Aprint+%22y+%3D%22,+y%0Aprint+%22z+%3D%22,+z%0A&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&curInstr=0&codeDivWidth=350&codeDivHeight=400"> </wikiframe>
 +
 +
 +
A range parancs is listát ad vissza:
 +
<python>
 +
>>> range(3)
 +
[0, 1, 2]
 +
>>> range(3, 6)
 +
[3, 4, 5]
 +
>>> range(1,10,3)
 +
[1, 4, 7]
 +
</python>
 +
 +
 +
=== Lista létrehozása, listaértelmezés (list comprehension) ===
 +
 +
Rövid listák létrehozásának egyszerű módja. Általános alakja:
 +
<python>
 +
[expression for expr in sequence1
 +
           if condition1
 +
           for expr2 in sequence2
 +
           if condition2
 +
            ...
 +
           for exprN in sequenceN
 +
           if conditionN]
 +
</python>
 +
Kis programrészek helyettesíthetők vele. Például '''''soroljuk fel az 1890 és 1915 közé eső szökőéveket!'''''
 +
 +
<python>
 +
szoko = []
 +
for ev in range(1890, 1922):
 +
    if (ev%4 == 0 and ev%100 != 0) or (ev%400 == 0):
 +
        szoko.append(ev)
 +
print szoko
 +
[1892, 1896, 1904, 1908, 1912, 1916, 1920]
 +
</python>
 +
Lépésenként egyre összetettebb listaértelmezéssel állítsuk elő ugyanezt:
 +
<python>
 +
>>> szoko = [ev for ev in range(1890, 1915)]
 +
>>> szoko    # ez még az összes év
 +
[1890, 1891, 1892, 1893, 1894, 1895, 1896, 1897, 1898, 1899, 1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914]
 +
>>> szoko = [ev for ev in range(1890, 1915) if ev%4 == 0]
 +
>>> szoko    # ez a 4-gyel osztható évek listája
 +
[1892, 1896, 1900, 1904, 1908, 1912]
 +
>>> szoko = [ev for ev in range(1890, 1915)
 +
                if (ev%4 == 0 and ev%100 != 0) or ev%400 == 0]
 +
>>> szoko
 +
[1892, 1896, 1904, 1908, 1912]
 +
</python>
 +
 +
Egy egyszerű algoritmus egy különböző elemekből álló lista összes permutációja listájának előállítására:
 +
 +
<python>
 +
def perm(lista):
 +
    if lista:
 +
        return [[x] + p
 +
                for x in lista
 +
                for p in perm([y for y in lista if y != x])]
 +
    else:
 +
        return [[]]
 +
</python>
 +
 +
Például:
 +
<python>
 +
>>> perm([1, 2, 3])
 +
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
 +
</python>
 +
 +
 +
'''*''' Egy nehezebb feladat: '''''Tegyünk fel nyolc vezért egy sakktáblára úgy, hogy semelyik kettő ne üsse egymást! Soroljuk fel az összes ilyen vezérelhelyezést!'''''
 +
 +
Az ilyen bástyaelhelyezések száma 8! = 40320. A vezérek (királynők) azonban átlósan is üthetik egymást. Legyen x egy permutációja a [0, 1, 2, 3, 4, 5, 6, 7] számoknak. Az i-edik sorban a vezér legyen az x[i]-edik oszlopban. Az i-edik és j-edik sorban lévő vezér pontosan akkor üti egymást, ha abs(i - j) != abs(x[i] - x[j]). A permutációk listázásához töltsük be az itertools csomag permutations függvényét, mely a for ciklus minden ciklusában ad egy következő permutációt, amíg a végére nem ér (így nem kell felsorolni mind a 8! permutációt egyetlen listában). Az all függvény igaz, ha az argumentumában lévő lista minden eleme igaz. 
 +
Így a megoldás:
 +
 +
<python>
 +
from itertools import permutations
 +
for x in permutations(range(8)):
 +
    if all([abs(i - j) != abs(x[i] - x[j]) for i in range(8) for j in range(i)]):
 +
        print x
 +
</python>
 +
 +
 +
= A procedurális programozás elemei =
 +
 +
== Vezérlő utasítások ==
 +
 +
=== if ===
 +
 +
<python>
 +
>>> x = int(raw_input("Adj meg egy egész számot: "))
 +
Adj meg egy egész számot: 42
 +
>>> if x < 0:
 +
...    print "ez negatív"
 +
... elif x == 0:
 +
...    print "ez nulla"
 +
... elif x == 1:
 +
...    print "ez egy"
 +
... else:
 +
...    print "ez sok"
 +
...
 +
ez sok
 +
</python>
 +
 +
Az elif-ek száma tetszőleges, és ezzel elkerülhető a sok behúzás.
 +
 +
A következő kóddal tesztelhető, hogy milyen kifejezéseket tekint a python igaznak:
 +
<python>
 +
x = 5
 +
y = 5.0
 +
if x == y:          # if x is 5:
 +
    # True, 1, 2, 0.00001, [[]], ((),),
 +
    print "igaz, nem 0"
 +
else:
 +
    # False, None, 0, 0.0, 0 + 0j, [], (), (()), {}
 +
    print "hamis, 0, a hossza 0"
 +
</python>
 +
 +
 +
=== for, break, else, continue ===
 +
 +
<python>
 +
>>> long_words = [u"Antidisestablishmentarianism", u"Donaudampfschiffahrtselektrizitätenhauptbetriebswerkbauunterbeamtengesellschaft", u"bejelentkezésszabályozási", u"fosszilisdinoszauruszhányásvilágranglista-megdöntés", u"folyamatellenőrzésiügyosztályvezetőhelyettesképesítésvizsgálat-szervezéseitekkel"]
 +
>>> for i in long_words:
 +
...    print i, len(i)
 +
...
 +
Antidisestablishmentarianism 28
 +
Donaudampfschiffahrtselektrizitätenhauptbetriebswerkbauunterbeamtengesellschaft 79
 +
bejelentkezésszabályozási 25
 +
fosszilisdinoszauruszhányásvilágranglista-megdöntés 51
 +
folyamatellenőrzésiügyosztályvezetőhelyettesképesítésvizsgálat-szervezéseitekkel 80
 +
</python>
 +
 +
'''''Döntsük el 10-ig minden egészről, hogy prím vagy összetett szám!'''''
 +
<python>
 +
>>> for n in range(2, 10):
 +
...    for x in range(2, n):
 +
...        if n % x == 0:
 +
...            print n, '=', x, '*', n/x
 +
...            break
 +
...    else:
 +
...        # ha a ciklusban nem talált osztót (nem volt break)
 +
...        print n, 'prím'
 +
...
 +
2 prím
 +
3 prím
 +
4 = 2 * 2
 +
5 prím
 +
6 = 2 * 3
 +
7 prím
 +
8 = 2 * 4
 +
9 = 3 * 3
 +
</python>
 +
 +
 +
'''''Írjuk ki az 50 alatti páros számokat, de a 3-mal oszthatók helyett *-ot tegyünk!'''''
 +
<python>
 +
>>> for n in range(2, 50, 2):
 +
...    if n % 3 == 0:
 +
...        print "*",
 +
...        continue
 +
...    print n,
 +
...
 +
2 4 * 8 10 * 14 16 * 20 22 * 26 28 * 32 34 * 38 40 * 44 46 *
 +
</python>
 +
 +
=== while, braek, else ===
 +
 +
'''''Írjuk ki az 1000 alatti Fibonacci-számokat:'''''
 +
<python>
 +
>>> n = 1000
 +
>>> a, b = 0, 1
 +
>>> while b < n:
 +
...    print b,  # a vessző miatt egy sorba kerülnek
 +
...    a, b = b, a + b
 +
...
 +
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
 +
</python>
 +
 +
A while-nak is lehet else-ága és használható a break.
 +
 +
=== pass ===
 +
 +
Nem csinál semmit, ami sokszor nagyon jól jöhet:
 +
 +
<python>
 +
while True:
 +
    pass  # Várunk egy billentyűzet interruptot (Ctrl+C)
 +
</python>
 +
 +
 +
<python>
 +
def func(*args):
 +
    pass  # megírandó
 +
</python>
 +
 +
 +
 +
 +
== Adatstruktúrák ==
 +
 +
 +
 +
 +
 +
<!--
 +
 +
<python>
 +
</python>
 +
 +
 +
= A Python eljárásközpontú (procedurális) programozása =
 +
 +
== Adattípusok ==
 +
 +
 +
== Gyűjteményes adattípusok ==
 +
 +
=== Sorozatszerű típusok: str, list, tuple ===
 +
 +
Tuladonságaik: bejárhatók, in, len(), []
 +
 +
'''Sorozat (tuple)''' változtathatatlan (immutable), mint a karakterlánc, műveletei:
 +
szeletelés [], összefűzés (+), szorzás (*), összehasonlítás, tagsági viszony (in, not in)
 +
<python>
 +
>>> t = ()
 +
>>> t
 +
()
 +
>>> t = 1, 5, 5, 5, 3  # itt elhagyható a zárójel
 +
>>> t
 +
(1, 5, 5, 5, 3)
 +
>>> t[1]
 +
5
 +
>>> t.index(3)
 +
4
 +
>>> t.count(5)
 +
3
 +
</python>
 +
 +
 +
'''lista''' - változtatható (mutable)
 +
[http://docs.python.org/release/2.5.2/lib/typesseq-mutable.html]
 +
<python>
 +
>>> l[1:4:2] = [7, 8]
 +
>>> l
 +
[1, 7, 3, 8, 5]
 +
>>> l.remove(7); l
 +
[1, 3, 8, 5]
 +
>>> l.reverse(); l
 +
[5, 8, 3, 1]
 +
>>> l.append(99); l
 +
[5, 8, 3, 1, 99]
 +
>>> l += [55, 66]
 +
>>> l
 +
[5, 8, 3, 1, 99, 55, 66]
 +
>>> l.pop()
 +
66
 +
>>> l
 +
[5, 8, 3, 1, 99, 55]
 +
</python>
 +
 +
=== Halmaztípusok: halmaz (set) ===
 +
 +
Lásd
 +
[http://docs.python.org/release/2.5.2/lib/types-set.html]
 +
<python>
 +
>>> s = set([5,6,7,8,6])
 +
>>> s
 +
set([8, 5, 6, 7])
 +
>>> s2 = set()
 +
>>> s2
 +
set([])
 +
>>> s2 = s.copy()
 +
>>> s2
 +
set([8, 5, 6, 7])
 +
>>> s2.add(6)
 +
>>> s2.add(11)
 +
>>> s2
 +
set([8, 11, 5, 6, 7])
 +
>>> s2.difference(s)
 +
set([11])
 +
>>> s2.discard(11)
 +
>>> s2.difference(s)
 +
set([])
 +
>>> s2.intersection(s)
 +
set([8, 5, 6, 7])
 +
>>> s2.update([5,4,3])
 +
>>> s2
 +
set([3, 4, 5, 6, 7, 8])
 +
>>> s2.discard(2)
 +
>>> s2
 +
set([3, 4, 5, 6, 7, 8])
 +
>>> s2.remove(3)
 +
>>> s2
 +
set([4, 5, 6, 7, 8])
 +
>>> s2.remove(3)
 +
Traceback (most recent call last):
 +
  File "<stdin>", line 1, in <module>
 +
KeyError: 3
 +
>>> s
 +
set([8, 5, 6, 7])
 +
>>> s.union(set([56,5]))
 +
set([56, 5, 6, 7, 8])
 +
>>> s
 +
set([8, 5, 6, 7])
 +
>>> s2
 +
set([4, 5, 6, 7, 8])
 +
>>> s.clear()
 +
>>> s
 +
set([])
 +
</python>
 +
 +
=== Megfeleltetési típusok: szótár (dict) ===
 +
 +
Lásd
 +
[http://docs.python.org/release/2.5.2/lib/typesmapping.html]
 +
<python>
 +
>>> d = dict()
 +
>>> d
 +
{}
 +
>>> d = {}
 +
>>> d
 +
{}
 +
>>> d = {'fn':'Marci', 'ln':'Pala', 2:89}
 +
>>> d
 +
{'ln': 'Pala', 2: 89, 'fn': 'Marci'}
 +
>>> d[2]
 +
89
 +
>>> d['ln']
 +
'Pala'
 +
>>> d2 = d.copy()
 +
>>> d2
 +
{'ln': 'Pala', 2: 89, 'fn': 'Marci'}
 +
>>> d2[2] = 8
 +
>>> d2
 +
{'ln': 'Pala', 2: 8, 'fn': 'Marci'}
 +
>>> d
 +
{'ln': 'Pala', 2: 89, 'fn': 'Marci'}
 +
>>> d.update([("t",3),('b',6)])
 +
>>> d
 +
{'ln': 'Pala', 2: 89, 'b': 6, 't': 3, 'fn': 'Marci'}
 +
>>> d2
 +
{'ln': 'Pala', 2: 8, 'fn': 'Marci'}
 +
>>> d.values()
 +
['Pala', 89, 6, 3, 'Marci']
 +
>>> d.pop('b')
 +
6
 +
>>> d
 +
{'ln': 'Pala', 2: 89, 't': 3, 'fn': 'Marci'}
 +
>>> d.keys()
 +
['ln', 2, 't', 'fn']
 +
>>> d.items()
 +
[('ln', 'Pala'), (2, 89), ('t', 3), ('fn', 'Marci')]
 +
>>> d.clear()
 +
>>> d
 +
{}
 +
>>> len(d)
 +
0
 +
>>> d2
 +
{'ln': 'Pala', 2: 8, 'fn': 'Marci'}
 +
</python>
 +
 +
=== Listaértelmezések (list comprehension) ===
 +
 +
 +
 +
=== Gyűjtemények másolása (sekély és mély másolás) ===
 +
 +
Az értékadás (=) csak objektumhivatkozással jár, nem történik adatmásolás. Ennek következtében egy <code>y = x</code> parancs után, ahol x gyűjteményes adattípus, az y ugyanarra az objektumra fog mutatni. Így ha megváltoztatjuk x-et vagy y-t, változik a másik is. Az objektumhivatkozások megtörténhetnek egy szinttel mélyebben is, a (<code>z = x[:]</code> kód esetén az x elemeire mutató hivatkozások másolódnak, de ekkor sem jön létre a teljes objektumról másolat. Ezt hívjuk
 +
'''sekély másolásnak (shallow copy)'''.
 +
<python>
 +
>>> x = [1, 2, ["a","b"]]
 +
>>> y = x
 +
>>> z = x[:]
 +
>>> y[0] = 0
 +
>>> x, y, z
 +
([0, 2, ['a', 'b']], [0, 2, ['a', 'b']], [1, 2, ['a', 'b']])
 +
>>> z[0] = 5
 +
>>> x, y, z
 +
([0, 2, ['a', 'b']], [0, 2, ['a', 'b']], [5, 2, ['a', 'b']])
 +
>>> x[2][0] = "X"
 +
>>> x, y, z
 +
([0, 2, ['X', 'b']], [0, 2, ['X', 'b']], [5, 2, ['X', 'b']])
 +
</python>
 +
'''Mély másolás (deep copy)''', amikor valóban új példány keletkezik az objektumból:
 +
<python>
 +
import copy
 +
w = copy.deepcopy(x)
 +
</python>
 +
 +
== Műveletek, operátorok ==
 +
 +
=== Logikai értéket visszaadó műveletek ===
 +
 +
==== Azonossági művelet ====
 +
 +
Az alábbi példában a és b még azonos, mert ugyanarra az objektumra hivatkoznak, de a c és d már '''nem azonosak''', bár egyenlők:
 +
<python>
 +
>>> a = 2
 +
>>> b = 2
 +
>>> a is b
 +
True
 +
>>> c = [1, 2, 3]
 +
>>> d = [1, 2, 3]
 +
>>> c is d
 +
False
 +
>>> c == d
 +
True
 +
</python>
 +
 +
==== Összehasonlító műveletek ====
 +
 +
Nem csak a számok, de karakterláncok, sorozatok, listák... is összehasonlíthatók (==, !=, <, >, <=, >=):
 +
<python>
 +
>>> a = 23
 +
>>> b = 56
 +
>>> a == b
 +
False
 +
>>> a != b
 +
True
 +
>>> a <= b
 +
True
 +
>>> c = "abc"
 +
>>> d = "abcd"
 +
>>> c == d[:3]
 +
True
 +
>>> c < d
 +
True
 +
>>> (2, 1, 3) <= (2, 1, 4)
 +
True
 +
</python>
 +
 +
==== Tagsági műveletek ====
 +
 +
in, not in:
 +
<python>
 +
>>> l = [1, 2, "cica"]
 +
>>> 2 in l
 +
True
 +
>>> "macska" not in l
 +
True
 +
>>> "c" in l[2]
 +
True
 +
>>> "ci" in l[2]
 +
True
 +
>>> "ci" in l
 +
False
 +
</python>
 +
 +
 +
==== Logikai műveletek ====
 +
 +
and, or, not (ld. fönt)
 +
 +
=== Operátorok precedenciája ===
 +
 +
Az operátorok között, mint a matematikában itt is, van precedencia sorrend:
 +
 +
{| class="wikitable" style="text-align: center; color: green;"
 +
! Operator
 +
! Description
 +
|-
 +
|lambda
 +
|Lambda expression
 +
|-
 +
| if – else
 +
| Conditional expression
 +
|-
 +
| or
 +
| Boolean OR
 +
|-
 +
| and
 +
| Boolean AND
 +
|-
 +
| not x
 +
| Boolean NOT
 +
|-
 +
| in, not in, is, is not, <, <=, >, >=, <>, !=, ==
 +
| Comparisons, identity test, including membership test
 +
|-
 +
| &#124;
 +
| Bitwise OR
 +
|-
 +
| ^
 +
| Bitwise XOR
 +
|-
 +
| &
 +
| Bitwise AND
 +
|-
 +
| <<, >>
 +
| Shifts
 +
|-
 +
|<code>+, -</code>
 +
|Addition and subtraction
 +
|-
 +
|*, //, /, %
 +
|Multiplication, division, remainder
 +
|-
 +
|<code>+x, -x, ~x</code>
 +
|Positive, negative, bitwise not
 +
|-
 +
|**
 +
|Exponentiation
 +
|-
 +
|x[index], x[index:index], x(arguments...), x.attribute
 +
|Subscription, slicing, call, attribute reference
 +
|-
 +
|(expressions...), [expressions...], {key:datum...}, `expressions...`
 +
|Binding or tuple display, list display, dictionary display, string conversion
 +
|}
 +
 +
A sage, python a kifejezéseket balról jobbra értékeli ki, kivéve az értékadásnál, amikor előbb a jobb oldalt értékeli ki, majd a bal oldalt.
 +
Pl. a logikai kifejezés elemeit ha mar felesleges nem értékeli ki.
 +
 +
== Vezérlési szerkezetek ==
 +
*Elágazás
 +
**if (elif, else)
 +
*Ciklusok
 +
**while (else)
 +
**for (else)
 +
**break, continue
 +
 +
* Lényeges, hogy a while és for ciklusokhoz itt hozzárendelhető else ág. Ezek használatát mutatja be az alábbi két példa:
 +
<python>
 +
while condition:
 +
    handle_true()
 +
else:
 +
    # condition is false now, handle and go on with the rest of the program
 +
    handle_false()
 +
</python>
 +
 +
<python>
 +
for value in values:
 +
    if value == 5:
 +
        print "Found it!"
 +
        break
 +
else:
 +
    print "Nowhere to be found. :-("
 +
</python>
 +
 +
 +
== Függvények ==
 +
 +
* Python ban is van lehetőség függvények definiálására és hívására.
 +
* Függvényeknek itt is lehetnek paraméterei
 +
* Ha rögzítjük a paraméterszámot, akkor ennek megfelelően kell hívnunk a függvényt.
 +
* Lehetséges előre beállított paraméterekkel való hívás is. Ebben az esetben, az egyértelműség miatt a definiáláskor hátul adunk meg minen előre is definiált paramétert.
 +
* Példa
 +
<python>
 +
def a_d_test(fv, vert = 1):
 +
  return fv * vert
 +
 +
a_d_test(5,2)
 +
10
 +
a_d_test(5)
 +
5
 +
</python>
 +
* Pararméterek nevének különákülön való megadásával is átadhatjuk azok értékeit híváskor.
 +
<python>
 +
a_d_test(vert=2, fv=2)
 +
</python>
 +
* Speciálisan megadhatunk tetszőleges paraméterszámú függvényeket.
 +
<python>
 +
def as_many(*args):
 +
  for i in args:
 +
    print i,
 +
 +
as_many('trali', 'fari')
 +
trali fari
 +
</python>
 +
 +
== Láthatóságról ==
 +
* A kód itt is blokkokba rendeződik és egy változó befelé látszik, kifelé nem.
 +
* A belső deklaráció "leárnyékol".
 +
* Ez a küd tehát hibás, mert a b=a utasítás blokkján belül az a=6 utasítással létrehozzuk az a lokális változót. Emiatt leárnyékoljuk a külső a változót, és a b=a utasításnál így hibát kapunk.
 +
<python>
 +
a=7
 +
def sz3():
 +
  b=a
 +
  a=6
 +
  return b
 +
 +
Traceback (click to the left of this block for traceback)
 +
...
 +
UnboundLocalError: local variable 'a' referenced before assignment
 +
</python>
 +
 +
== Kivételkezelés ==
 +
* Lehetőségünk van kivételek, hibák kezelésére.
 +
* '''try''' és '''except''' blokkok használatával kezelhetjük a hibát adható részeit a kódnak.
 +
* '''A try blokkon belül megpróbáljuk végrehajtani az ott felsorolt utasításokat.'''
 +
* '''Ha ez nem sikerül, akkor a felmerülő hibát az except blokkal "kapjuk el".'''
 +
* Példa, alább magyarázattal:
 +
<python>
 +
while True:
 +
...    try:
 +
...        x = int(raw_input("Please enter a number: "))
 +
...        break
 +
...    except ValueError:
 +
...        print "Oops!  That was no valid number.  Try again..."
 +
</python>
 +
* A while True egy végtelen ciklus, mellyel break utasítással léphetünk ki. A break utasítás csak akkor fut le, ha előtte a felhasználótól hibátlanul bekértünk egy számot. Ha ez nem sikerült, akkor a try blokkból kilépünk a break utasíts előtt és ugrunk az except részre. Mivel mindez egy végtelen while ciklusban van, ezért ezt addig filytatjuk, amíg helyes bemenetet nem kapunk.
 +
* '''Tehát megpróbáljuk végrehajtani a try blokkon belüli utasításokat, de amint hibát észlelünk, kilépünk a try blokkból.'''
 +
* A hibát az except blokkal kezeljük.
 +
* Az except után megadhatjuk a hiba típusát, így a különböző hibákat különbözőféleképp kezelhetjük:
 +
<python>
 +
try:
 +
  z = x/y
 +
except ZeroDivisionError, e:
 +
  z = e # representation: "<exceptions.ZeroDivisionError instance at 0x817426c>"
 +
print z
 +
</python>
 +
== Bemenet, kimenet ==
 +
 +
Lsd. gyakorlaton
 +
 +
= A Python objektumorientált programozása =
 +
* Ez a wiki szintén jól használható: http://en.wikibooks.org/wiki/Python_Programming/Classes
 +
== Osztályok, objektumok ==
 +
* Az osztályok egységbe zárnak és a elrejtik a felesleges információt.
 +
* Egy lehetséges nézőpont: a kód egy részét (mind tárolókat, mind a függvényeket nézve) összefogjuk, és a kifelé felesleges műveleteket és változókat elrejtjük.
 +
* Egy objektum egy osztály konkrét megvalósítása. Egy osztályban definiáljuk az objektum jellemzőit.
 +
* Egy osztály metódusokból és változókból áll.
 +
* Egy másik nézőpont: Az osztályon belül változókkal hozunk létre adattárolókat. Metódusokkal ezeket az adattárolókat érjük el kívülről.
 +
* Példa osztály definiálásra pythonban:
 +
<python>
 +
class Osztaly:
 +
    "Ez az uj csodafegyver"
 +
    pass
 +
</python>
 +
A feni osztály még csak egy üres osztály. Ennek az egyszerű osztálynak egy objektum megvalósítása:
 +
<python>
 +
>>> o=Osztaly()
 +
</python>
 +
* Másszóval az o objektum az Osztaly osztály egy '''példánya'''.
 +
A következő kódrészlet metódus definiálására példa:
 +
<python>
 +
class Osztaly:
 +
...  def make_sandwich(self):
 +
...      self.sandwich=6
 +
>>> x=Osztaly()
 +
>>> x.make_sandwich()
 +
</python>
 +
* Ebben a példában az Osztaly osztályban  definiáljuk a make_sandwitch() metódust. Az x objektum példányoztatása után  az x objektumhoz tartozó make_sandwich() metódust hívjuk meg az utolsó sorban.
 +
* Így kap értelmet a 'self' kifejezés. A metódusoknál az osztálydefinícióban jeleznünk kell, hogy az adott objektumon dolgozunk, és annak változóival hajtunk végre műveletet.
 +
* Emiatt minden metódus első paramétere a 'self', ami mindig az osztály egy példányára ( megvalósított objektum) hivatkozik.
 +
* A self.sandwich emiatt az adott objektum változója lesz.
 +
* Ha tehát meghívjuk a make_sandwich() metódust, akkor az az adott objektumon belül létrehozza a sandwich változót kezdeti 6 értékkel.
 +
== Láthatóság ==
 +
* Említettük, hogy az osztályok egységbe zárnak és elrejtik a felesleges információt. Az "elrejtés" azt jelenti, hogy valamilyen módon korlátoznunk kell az osztály változóira és metódusaira (továbbiakban elemek) vonatkozó hozzáférést.
 +
* Az osztály egy eleme lehet: public, protected, private:
 +
** public: publikus elem hozzáférhető az objektumon kívülről is.
 +
** private: privát elem csak az osztályon (objektumon) belül érhető el.
 +
** protected: alosztályok ( lsd. később) és az eredeti osztály számára elérhető elem.
 +
* Pythonban '''minden változó és metódus publikus'''
 +
* A fenti szabály ellenére érdemes bizonyos dolgokat privát módon kezelni a kódban (annak ellenére, hogy lehetőségünk lenne őket kívülről elérni). Emiatt a változók és metódusok elnevezésében a következő konvenciót használjuk:
 +
** _ha_muszaj_elerem
 +
** __soha_nem_irom_felul__
 +
* Változók:
 +
** osztály szintű: ha megváltoztatjuk az értékét az osztályon belül, akkor minden egyes objektumban megváltozik az értéke.
 +
** objektum szintű: adott objektumhoz tartozó változó
 +
* Példa változókra:
 +
<python>
 +
class A:
 +
...  u=8
 +
...  def make_v(self):
 +
...      self.v=6
 +
>>> x=A()
 +
>>> y=A()
 +
>>> y.make_v()
 +
</python>
 +
* A fenti példában az x és y objektumok az A osztály példányai. Mindkettőben megjelenik az osztály szintű u változó. Az y objektum make_v() metódusánk meghívása után (csak!) az y objektumban megjelenik a v változó.
 +
 +
== Konstruktor és destruktor ==
 +
 +
* Azt az adott osztályhoz tartozó szubrutint, melynek feladata az osztály egy konkrét objektumának megvalósítása, konstruktornak hívjuk.
 +
* Ehhez hasonló az objektum törlésekor hívódó destruktor.
 +
* Pythonban külön nincs lehetőség ezek felüldefiniálására. A Python szokásos értelemben nem használ konstruktorokat és destruktorokat.
 +
* Azonban létezik olyan speciális metódus, mely az objektum létrehozása után közvetlenül lefut, ez az __init__():
 +
* Az inithez hasonló a __del__().
 +
* Példa az __init__()-re:
 +
<python>
 +
 +
>>> class Test:
 +
...    def __init__(self):
 +
...       
 +
...        print "Mostmar elhiszed?"
 +
... 
 +
>>> x=Test()
 +
Mostmar elhiszed?
 +
</python>
 +
* A Test osztály megvalósítása az x objektum. Az x objektum létrejöttekor az __init__() azonnal lefut, emiatt jelenik meg rögtön a kimeneten a "Mostmar elhiszed?" felirat.
 +
== Speciális metódusok pythonban ==
 +
 +
* az __init__() és __del__() metódusok mellett további speciális metódusok is elemei a nyelvnek.
 +
* Ilyen például a __repr__() és az __str__(), melyek az adott osztály (objektum) leírását adják.
 +
* Alapelv, hogy az __str__() legyen egyszerű, míg a __repr__() legyen egyértelmű.
 +
* Példa:
 +
<python>
 +
>>> class A:
 +
...  x=5
 +
...
 +
>>> a=A()
 +
>>> a
 +
<__main__.A instance at 0x7f1563927b90>
 +
>>> class B:
 +
...  x=5
 +
...  def __repr__(self):
 +
...    return "ez egy okos osztaly"
 +
...
 +
>>> b=B()
 +
>>> b
 +
ez egy okos osztaly
 +
</python>
 +
* A fenti példákon túl még több speciális metódus létezik. Lényegesek azon metódusok, melyekkel objektumokhoz tartozó operátorokat definiálhatunk.
 +
* Mindezekről részletesen a [http://wiki.math.bme.hu/view/Informatika2-2013/Gyakorlat11 gyakorlaton esett szó].
 +
* Egy példa az előadás anyagához:
 +
 +
<python>
 +
class Word(str):
 +
    '''Class for words, defining comparison based on word length.'''
 +
    def __new__(cls, word):
 +
        return str.__new__(cls, word)
 +
    def __gt__(self, other):
 +
        return len(self) > len(other)
 +
    def __lt__(self, other):
 +
        return len(self) < len(other)
 +
    def __ge__(self, other):
 +
        return len(self) >= len(other)
 +
    def __le__(self, other):
 +
        return len(self) <= len(other)
 +
</python>
 +
* A fenti példával stringeket hasonlíthatunk össze hosszuk alapján.
 +
== Öröklődés, leszármaztatás ==
 +
* Öröklődés (leszármaztatás) esetén egy osztályból származtatunk le egy másik osztályt. Az ősosztály leszármazottja (alosztály) örökli az ősosztály tulajdonságait.
 +
* Itt kap értelmet a "private" és "public" típusok mellett a "protected" típus. Minden ami publikus vagy protected az ősosztályban, az szintén eleme lesz a származtatott osztálynak. Ne feledjük, hogy pythonban minden változó és metódus publikus.
 +
* A fentiek már majdnem egyértelmű szabályokat adnak. Kérdés még, hogy abban az esetben, ha azonos metódusokat definiálunk az ős és az alosztályban, akkor melyik lesz érvényes az alosztályban?
 +
* Pythonban minden metódus virtuális. Ez azt jelenti, hogy az előző kettős definiálás esetén az alosztály definíciója lesz érvényes, tehát '''felüldefiniáljuk''' az eredeti metódust.
 +
Példák:
 +
<python>
 +
>>> class A:
 +
...  x=8
 +
...  def __init__(self):
 +
...      self.u=6
 +
>>> class B(A):
 +
...  y=5
 +
...  def __init__(self):
 +
...      self.v=7
 +
>>> a=A()
 +
>>> b=B()
 +
</python>
 +
* A fenti példában az a onjektum x és u, mg a b objektum x,y és v változókat fog magába foglalni.
 +
* Előfordulhat, hogy az ősosztály egy metódusára szeretnénk hivatkozni az alosztály egy metódusában. Ezt a következőképp tehetjük meg:
 +
<python>
 +
class A(object):
 +
    def proba(self):
 +
      print "A osztaly"
 +
 +
class B(A):
 +
    def proba2(self):
 +
      super(B, self).proba()
 +
      print "B osztaly"
 +
</python>
 +
* A fenti példában a proba2() metódus meghívja az A osztályban definiált proba() metódust.
 +
 +
-->
 +
 +
 +
 +
 
== a pythononline.org tesztelése ==
 
== a pythononline.org tesztelése ==
  
 
Lássuk, hogy néz ki: példa a sekély másolásra:
 
Lássuk, hogy néz ki: példa a sekély másolásra:
  
<wikiframe width="800" frameborder="0" src="http://pythontutor.com/iframe-embed.html#code=x+%3D+%5B0,+%5B4,+5%5D,+3%5D%0Ay+%3D+x+++++++%23+hivatkoz%C3%A1s%0Az+%3D+x%5B%3A%5D++++%23+sek%C3%A9ly+m%C3%A1sol%C3%A1s+(shallow+copy)%0Ay%5B1%5D+%3D+1%0Az%5B1%5D+%3D+2%0Aprint+%22x+%3D%22,+x%0Aprint+%22y+%3D%22,+y%0Aprint+%22z+%3D%22,+z%0A&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&curInstr=0&codeDivWidth=350&codeDivHeight=400"> </wikiframe>
 
  
 
Idáig tart a beágyazás!
 
Idáig tart a beágyazás!

A lap 2014. február 18., 23:26-kori változata

Tartalomjegyzék

Bevezetés a Python nyelvbe

Az előadáshoz elsőszámú olvasmány a Python tutorial.

A Pythont ismerjük a Sage-ből. Különbségek:

  • ^ helyett ∗∗, / osztást, // egészosztást jelöl.
  • [a..b] helyett range(a,b), vagy xrange(a,b)
  • A megszokott, beépített matematikai függvények hiányoznak (find_root, plot, is_prime), de különböző modulokban sokuk megtalálható.
  • Nincsenek szimbolikus változók

A Python egy olyan általános körben használható magas szintű programozási nyelv, aminek az egyik alapelve az olvasható kód írása egy nagyon tiszta szintaxis használatával. 1991-ben alkotta meg Guido Van Rossum.

További jellemzők

  • objektum orientált, procedurális, funkcionális
  • sok beépített modul a fejlesztés megkönnyítésére
  • dinamikus típus kezelés
  • automatikus memóriakezelés
  • többféle megvalósítás (CPython, Jython, IronPython, PyPy, Python for S60)
  • open-source a főbb platformokra
  • sokkal tömörebb sok más nyelvnél

Nevét a Monthy Python ihlette, nem az állat.

Filozófiája megkapható a 'this' modul betöltésével:

 import this


Python kód futtatása

Interaktív módon

Egyszerűen a python parancs terminálból indítva:

$ python
Python 2.7.5+ (default, Sep 19 2013, 13:48:49) 
[GCC 4.8.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

Fájlból

  • Nyiss egy új file-t pl. a gedit-ben, mentsd el "kerdez.py" néven egy könyvtáradba!
  • Írd bele a következő python kódot (ne használj ékezeteket):
s = input("Mondj egy szamot: ")
print "Ennel eggyel kisebbet mondtal: ", s + 1
  • Mentsd el, és futtasd a scriptedet! (python kerdez.py)
  • Most kicsit kiegészítjük a scriptet, hogy tartalmazhasson ékezetes betűket, és hogy kényelmesebben futtatható legyen (a python parancs begépelése nélkül is):
#!/usr/bin/python
#coding=UTF-8
s = input("Mondj egy számot: ")
print "Ennél eggyel kisebbet mondtál: ", s + 1
  • Mentsd el, és adj rá futtatási jogot csak magadnak (chmod +x kerdez.py)!
  • Futtasd így: kerdez.py vagy így: ./kerdez.py
  • A kód második sora lehet ez is:
# -*- coding: utf-8 -*-

Argumantum átadása

#!/usr/bin/env python
#coding=utf-8
# Összead tetszőleges számú számot
import sys  # modul a rendszerfüggő információkhoz
 
osszeg = sum(float(arg) for arg in sys.argv[1:])
print 'Összeg =', osszeg

Ha e fájl az osszeg.py nevű fájlba van mentve, akkor

$ ./osszeg.py 12 23.5 1
36.5

Kódolás stílusa

Stílus (code style) a PEP 8 alapján

  • használj mindig 4 space-t minden egyes szinthez, de a folytatósort kezd még beljebb,
  • a nagyobb kódrészeket tagold üres sorokkal (függvény, osztály, nagyobb kód blokk)
  • használj space-t a vesző után és a legmagasabb szinten lévő operátorok körül
  • használj docstring-et és ahol lehet a megjegyzés a saját sorára vonatkozzon, vagy azonos mértékben behúzva arra a blokkódra
  • ahol lehet használj ASCII karakterkódolást
  • 79 karakternél ne legyen hosszabb egy sor
  • CamelCase elnevezési konvenciót kövesse az osztályok neve és lower_case_with_underscores a függvények és változók nevei

Érdemes megnézni a Google python code style ajánlását is.

Docstring

A hivatkozás nélküli string elemet szokás használni megjegyzések írására és dokumentálásra.

"""This is a class of example.
 
TODO: needs implementation.
"""

Első sort nagybetűvel kezdjük és pontal zárjuk. Egy összefoglaló mondat legyen. Majd egy üres sort hagyva részletesen leírhatunk minden funkciót amit az osztály vagy függvény tartalmaz. Megadhatjuk, hogy a függvény bizonyos hívásaira mi legyen a válasz,

Hasznos linkek:

#coding=utf-8
def lnko(a, b):
    """Kiszámolja két szám legnagyobb közös osztóját.
 
    >>> lnko(36, 8)
    4
    >>> lnko(-36, 4)
    4
    >>> lnko(3, 0)
    3
    """
 
    a, b = abs(a), abs(b)
    while a != 0:
        a, b = b%a, a
    return b
 
if __name__ == "__main__":
    import doctest
    doctest.testmod()

Ha lnko.py a neve, akkor egy

python lnko.py

parancs után nem kapunk semmit (mert a teszt hiba nélkül lefutott), azonban a -v opciót is használva látjuk a részleteket is:

$ python lnko.py -v
Trying:
    lnko(36, 8)
Expecting:
    4
ok
Trying:
    lnko(-36, 4)
Expecting:
    4
ok
Trying:
    lnko(3, 0)
Expecting:
    3
ok
1 items had no tests:
    __main__
1 items passed all tests:
   3 tests in __main__.lnko
3 tests in 2 items.
3 passed and 0 failed.
Test passed.


A Python, mint számológép

Azonosítók

Az adatokat többszöri felhasználásra azonosítóval (névvel) láthatjuk el.

  • a név betűvel vagy aláhúzással kezdődhet: [_a-zA-Z]
  • a név további karakterei az előbbieken felül számok is lehetnek: [_a-zA-Z0-9]
  • elméletileg bármilyen hosszú lehet a név
  • név nem lehet foglalt szó
  • nagybetű-kisbetű érzékeny, tehát a val1 név nem azonos a Val1 névvel

Másképp, Backus–Naur formában leírva:

identifier ::=  (letter|"_") (letter | digit | "_")*
letter     ::=  lowercase | uppercase
lowercase  ::=  "a"..."z"
uppercase  ::=  "A"..."Z"
digit      ::=  "0"..."9"

A foglalt szavak: and del from not while as elif global or with assert else if pass yield break except import print class exec in raise continue finally is return def for lambda try De ne használjuk a Python beépített neveinek, függvényeinek, kivételeinek neveit sem. Ezek megkaphatók a dir(__builtins__) paranccsal:

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']
>>> dir(__builtins__)
['ArithmeticError', 'AssertionError', ......

Egész szerű adattípusok: egész (int, long), logikai (bool)

int (egész) és hosszú egész (long)

>>> a = 12
>>> b = 0b011101
>>> c = 0o3701
>>> d = 0xff0c
>>> a, b, c, d
(12, 29, 1985, 65292)
>>> e = 22222222222222222222222222222222222222222
>>> e
22222222222222222222222222222222222222222L
>>> type(a), type(b), type(e)
(<type 'int'>, <type 'int'>, <type 'long'>)

Műveletek egészekkel: +, -, *, / (float eredményt ad), //, % (maradék), **, abs, pow, round, | (OR butenként), ^ (XOR bitenként), & (AND bitenként), <<, >> (eltolás bitenként), ~ (bitenkénti NOT)

Logikai (bool) típus:

Logikai értékek: False (0 vagy 0 hosszúságú), True (nem 0 vagy nem 0 hosszúságú)

Logikai műveletek: and, or, not

>>> True and False
False
>>> 1 and 0
0
>>> 3 and 0
0
>>> 3 or 1
3
>>> 1 or 3
1
>>> not 67
False
>>> not 0
True

Beépített lebegőpontos típusok (float, complex)

Lebegőpontos szám megadása:

>>> 2.3, -1.2e3, -1.2e-2
(2.2999999999999998, -1200.0, -0.012)

Matematikai függvények:

import math

után. Ld. [1]

Komplex szám imaginárius része után j betű, de * nincs! Komplex jellemzői (attribute) a real és az imag, tagfüggvénye (method) conjugate():

>>> z = 3.1 + 2.2j
>>> z
(3.1000000000000001+2.2000000000000002j)
>>> z.real
3.1000000000000001
>>> z.imag
2.2000000000000002
>>> z.conjugate()
(3.1000000000000001-2.2000000000000002j)

Karakterláncok (str)

A karakterláncok megadása: "...", '...' vagy """...""" módon történhet:

>>> a="""itt 'ez' meg "az" van"""
>>> a
'itt \'ez\' meg "az" van'
>>> print a
itt 'ez' meg "az" van
>>> type(a)
<type 'str'>
 
>>> c = 'aa\nbb'   
>>> c
'aa\nbb'
>>> print c
aa
bb
 
>>> d = r'aa\nbb'  # az r betű után minden karakter magát jelenti
>>> d
'aa\\nbb'
>>> print d
aa\nbb

Védőkódok (eszkép karakterek, escape characters): \ (folytatás új sorban), \\ (\), \' ('), \" ("), \n (új sor), \t (tab). Ha a karakterlánc elé r betűt írunk, a védőkódok nem érvényesek.

Műveletek karakterláncokkal: indexelés és szeletelés:

lánc[sorszám]
lánc[kezdet:vég]
lánc[kezdet:vég:lépés]

továbbá az + (összefűzés) és a * (többszörözés) műveletek:

>>> a = "ho"
>>> b = "rgasz"
>>> 3*a + b
'hohohorgasz'
 
>>> c = _       # _ az előző eredmény
>>> c
'hohohorgasz'
>>> c[:2]+c[6:]
'horgasz'
>>> c[1:7:2]
'ooo'
>>> c[1:6:2]
'ooo'
>>> c[-1::-1]
'zsagrohohoh'
>>> c[-3:4:-1]
'agro'

Az indexekre kétféleképp gondolhatunk: 1. a második index már nincs (ennek pl. az az értelme, hogy egy intervallum végét, és a következő elejét azonos érték jelzi, nem kell 1-et hozzáadni), 2. az indexeket az elemek közé képzeljük, vagyis az elemek határait indexeljük:

 +---+---+---+---+---+---+---+
 | h | o | r | g | a | s | z |
 +---+---+---+---+---+---+---+
 0   1   2   3   4   5   6   7
-5  -6  -5  -4  -3  -2  -1

Metódusok (tagfüggvények, methods): részletesen lásd [2]. Folytatva az előző példát:

>>> c.capitalize()
'Hohohorgasz'
>>> c.upper()
'HOHOHORGASZ'
>>> c.index('o')
1
>>> c.count('o')
3

A karakterláncok nem változtatható (immutable) objektumok, vagyis a műveletek, tagfüggvények alkalmazása után új karakterlánc keletkezik:

>>> a = "aaaa"
>>> a[1] = b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment


Objektumhivatkozások

Az értékadás (=) esetén valójában objektumhivatkozás történik, azaz az egyenlőség bal oldalán álló névhez egy hivatkozás kapcsolódik, mely az egyenlőség jobb oldalán álló objektumra mutat. Ez érthetővé teszi a következő kódot:

>>> a = 1
>>> b = a
>>> a = 2
>>> a
2
>>> b
1

A Python dinamikusan típusos nyelv, azaz az objektum, amire egy objektumhivatkozás mutat, lecserélhető egy más típusú objektumra (nem kell a változók típusát deklarálni).

>>> a = 1
>>> type(a)
<type 'int'>
>>> a = "b"
>>> type(a)
<type 'str'>


Listák

Ugyanúgy lehet szeletelni (slice), összeadni, többszörözni, mint a karakterláncot, de a lista változtatható (mutable):

>>> x = [1, 2, 3, 4]
>>> x[:2]*2 + x[-1:]
[1, 2, 1, 2, 4]
>>> x[:2]*2 + x[-1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "int") to list
>>> x[0::2]
[1, 3]
>>> x[-1::-1]
[4, 3, 2, 1]

Objektumhivatkozás átadása, és sekély másolás (shallow copy), azaz a belső szinteken nem történik másolás, csak a hivatkozások másolódnak:


A range parancs is listát ad vissza:

>>> range(3)
[0, 1, 2]
>>> range(3, 6)
[3, 4, 5]
>>> range(1,10,3)
[1, 4, 7]


Lista létrehozása, listaértelmezés (list comprehension)

Rövid listák létrehozásának egyszerű módja. Általános alakja:

[expression for expr in sequence1
            if condition1
            for expr2 in sequence2
            if condition2 
            ...
            for exprN in sequenceN
            if conditionN]

Kis programrészek helyettesíthetők vele. Például soroljuk fel az 1890 és 1915 közé eső szökőéveket!

szoko = []
for ev in range(1890, 1922):
    if (ev%4 == 0 and ev%100 != 0) or (ev%400 == 0):
        szoko.append(ev)
print szoko
[1892, 1896, 1904, 1908, 1912, 1916, 1920]

Lépésenként egyre összetettebb listaértelmezéssel állítsuk elő ugyanezt:

>>> szoko = [ev for ev in range(1890, 1915)]
>>> szoko    # ez még az összes év
[1890, 1891, 1892, 1893, 1894, 1895, 1896, 1897, 1898, 1899, 1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914]
>>> szoko = [ev for ev in range(1890, 1915) if ev%4 == 0]
>>> szoko    # ez a 4-gyel osztható évek listája
[1892, 1896, 1900, 1904, 1908, 1912]
>>> szoko = [ev for ev in range(1890, 1915) 
                if (ev%4 == 0 and ev%100 != 0) or ev%400 == 0]
>>> szoko
[1892, 1896, 1904, 1908, 1912]

Egy egyszerű algoritmus egy különböző elemekből álló lista összes permutációja listájának előállítására:

def perm(lista):
    if lista:
        return [[x] + p
                for x in lista
                for p in perm([y for y in lista if y != x])]
    else:
        return [[]]

Például:

>>> perm([1, 2, 3])
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]


* Egy nehezebb feladat: Tegyünk fel nyolc vezért egy sakktáblára úgy, hogy semelyik kettő ne üsse egymást! Soroljuk fel az összes ilyen vezérelhelyezést!

Az ilyen bástyaelhelyezések száma 8! = 40320. A vezérek (királynők) azonban átlósan is üthetik egymást. Legyen x egy permutációja a [0, 1, 2, 3, 4, 5, 6, 7] számoknak. Az i-edik sorban a vezér legyen az x[i]-edik oszlopban. Az i-edik és j-edik sorban lévő vezér pontosan akkor üti egymást, ha abs(i - j) != abs(x[i] - x[j]). A permutációk listázásához töltsük be az itertools csomag permutations függvényét, mely a for ciklus minden ciklusában ad egy következő permutációt, amíg a végére nem ér (így nem kell felsorolni mind a 8! permutációt egyetlen listában). Az all függvény igaz, ha az argumentumában lévő lista minden eleme igaz. Így a megoldás:

from itertools import permutations
for x in permutations(range(8)):
    if all([abs(i - j) != abs(x[i] - x[j]) for i in range(8) for j in range(i)]):
        print x


A procedurális programozás elemei

Vezérlő utasítások

if

>>> x = int(raw_input("Adj meg egy egész számot: "))
Adj meg egy egész számot: 42
>>> if x < 0:
...     print "ez negatív"
... elif x == 0:
...     print "ez nulla"
... elif x == 1:
...     print "ez egy"
... else:
...     print "ez sok"
... 
ez sok

Az elif-ek száma tetszőleges, és ezzel elkerülhető a sok behúzás.

A következő kóddal tesztelhető, hogy milyen kifejezéseket tekint a python igaznak:

x = 5
y = 5.0
if x == y:           # if x is 5:
    # True, 1, 2, 0.00001, [[]], ((),), 
    print "igaz, nem 0" 
else:
    # False, None, 0, 0.0, 0 + 0j, [], (), (()), {}
    print "hamis, 0, a hossza 0"


for, break, else, continue

>>> long_words = [u"Antidisestablishmentarianism", u"Donaudampfschiffahrtselektrizitätenhauptbetriebswerkbauunterbeamtengesellschaft", u"bejelentkezésszabályozási", u"fosszilisdinoszauruszhányásvilágranglista-megdöntés", u"folyamatellenőrzésiügyosztályvezetőhelyettesképesítésvizsgálat-szervezéseitekkel"]
>>> for i in long_words:
...     print i, len(i)
... 
Antidisestablishmentarianism 28
Donaudampfschiffahrtselektrizitätenhauptbetriebswerkbauunterbeamtengesellschaft 79
bejelentkezésszabályozási 25
fosszilisdinoszauruszhányásvilágranglista-megdöntés 51
folyamatellenőrzésiügyosztályvezetőhelyettesképesítésvizsgálat-szervezéseitekkel 80

Döntsük el 10-ig minden egészről, hogy prím vagy összetett szám!

>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...             print n, '=', x, '*', n/x
...             break
...     else:
...         # ha a ciklusban nem talált osztót (nem volt break)
...         print n, 'prím'
... 
2 prím
3 prím
4 = 2 * 2
5 prím
6 = 2 * 3
7 prím
8 = 2 * 4
9 = 3 * 3


Írjuk ki az 50 alatti páros számokat, de a 3-mal oszthatók helyett *-ot tegyünk!

>>> for n in range(2, 50, 2):
...     if n % 3 == 0:
...         print "*",
...         continue
...     print n,
... 
2 4 * 8 10 * 14 16 * 20 22 * 26 28 * 32 34 * 38 40 * 44 46 *

while, braek, else

Írjuk ki az 1000 alatti Fibonacci-számokat:

>>> n = 1000
>>> a, b = 0, 1
>>> while b < n:
...     print b,  # a vessző miatt egy sorba kerülnek
...     a, b = b, a + b
... 
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

A while-nak is lehet else-ága és használható a break.

pass

Nem csinál semmit, ami sokszor nagyon jól jöhet:

while True:
    pass  # Várunk egy billentyűzet interruptot (Ctrl+C)


def func(*args):
    pass   # megírandó



Adatstruktúrák

a pythononline.org tesztelése

Lássuk, hogy néz ki: példa a sekély másolásra:


Idáig tart a beágyazás!

Idáig meg a másik, minden átszerkesztés nélkül.

Személyes eszközök