Informatika2-2014/Eloadas Python

A MathWikiből
(Változatok közti eltérés)
505. sor: 505. sor:
 
Az elif-ek száma tetszőleges, és ezzel elkerülhető a sok behúzás.
 
Az elif-ek száma tetszőleges, és ezzel elkerülhető a sok behúzás.
  
=== for ===
+
 
 +
=== for, break, else, continue ===
  
 
<python>
 
<python>
519. sor: 520. sor:
 
</python>
 
</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>
  
  

A lap 2014. február 12., 11:54-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: ", str(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: ", str(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, 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.


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észszerű 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), True (nem 0)

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)

A műveletek eredménye NaN (not a number) és infinity is lehet!

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 (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 ez 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:

x = [0, [4, 5], 3]
y = x       # hivatkozás
z = x[:]    # sekély másolás (shallow copy)
y[1] = 1
z[1] = 2

A range parancs is listát ad vissza:

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


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 a szökőéveket 1890 és 1915 között.

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 hasonló, nehezebb feladat: Hányféleképp lehet nyolc királynőt föltenni egy sakktáblára, hogy semelyik kettő ne üsse egymást?

Az ilyen bástyaelhelyezések száma 8! = 40320. A 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 királynő legyen az x[i]-edik oszlopban. Az i-edik és j-edik sorban lévő királynő 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. 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


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.


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! </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!

>>> 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

Személyes eszközök