Vodič za Pajton 2.6/Više sa listama

Već smo videli liste i kako se mogu koristiti. Sada kada imate malo više predzanja ići ću u više detalja o listama. Prvo ćemo pogledati više načina da se dobiju elementi u listi, a onda ćemo pričati o kopiranju.

Evo nekih primera korišćenja pristupa indeksiranja jednom elementu liste:

>>> неки_бројеви = ['нула', 'један', 'два', 'три', 'четири', 'пет']
>>> неки_бројеви[0]
'нула'
>>> неки_бројеви[4]
'четири'
>>> неки_бројеви[5]
'пет'

Svi ovi primeri treba da izgledaju poznato. Ako želite prvu stavku u listi samo pogledajte indeks 0. Druga stavka je indeks 1 i tako dalje kroz listu. Međutim šta ako želite poslednju stavku u listi? Jedan način bi bio korišćenje len() funkcije kao неки_бројеви[len(неки_бројеви) - 1]. Ovaj način radi pošto len() funkcija uvek vraća poslednji indeks plus jedan. drugi bi onda bio неки_бројеви[len(неки_бројеви) - 2]. Postoji lakši način da se ovo uradi. U Pajtonu poslednja stavka je uvek indeks -1. Pretposlednji je indeks -2 and i tako dalje. Evo još nekih primera:

>>> неки_бројеви[len(неки_бројеви) - 1]
'пет'
>>> неки_бројеви[len(неки_бројеви) - 2]
'четири'
>>> неки_бројеви[-1]
'пет'
>>> неки_бројеви[-2]
'четири'
>>> неки_бројеви[-6]
'нула'

Tako svaka stavka u listi može biti indeksirana na dva načina: spreda i otpozadi.

Drugi koristan način da se u delovima liste koristi odsecanje. Evo još jednog primera koji će Vam dati ideju za šta može da se koristi:

>>> ствари = [0, 'Фред', 2, 'С.П.А.М.', 'Чарапа', 42, "Џек", "Џил"]
>>> ствари[0]
0
>>> ствари[7]
'Џил'
>>> ствари[0:8]
[0, 'Фред', 2, 'С.П.А.М.', 'Чарапа', 42, 'Џек', 'Џил']
>>> ствари[2:4]
[2, 'С.П.А.М.']
>>> ствари[4:7]
['Чарапа', 42, 'Џек']
>>> ствари[1:5]
['Фред', 2, 'С.П.А.М.', 'Чарапа']

Presecanje se koristi da se vrati deo liste. Operator odsecanje je u obliku ствари[први_индекс:последњи_индекс]. Odsecanje seče listu posle први_индекс i pre последњи_индекс i vraća delove između. Možete koristiti oba tipa indeksiranja:

>>> ствари[-4:-2]
['Чарапа', 42]
>>> ствари[-4]
'Чарапа'
>>> ствари[-4:6]
['Чарапа', 42]

Drugi trik je sa osecanjem neodređenog indeksa. Ako prvi indeks nije određen početak liste se pretpostavlja. Ako poslednji indeks nije naveden ceo ostatak liste se pretpostavlja. Ovde su neki primeri:

>>> ствари[:2]
[0, 'Фред']
>>> ствари[-2:]
['Џек', 'Џил']
>>> ствари[:3]
[0, 'Фред', 2]
>>> ствари[:-5]
[0, 'Фред', 2]

Ovde je (HTML-om inspirisan) primer programa (kopirate u pesmi definicije ako želite):

песма = ["<B>", "Џек", "и", "Џил", "</B>", "су", "отишли", "уз",
        "брдо", "да", "<B>", "донесу", "кофу", "</B>",
        "воде.", "Џек", "је пао", "<B>", "доле", "и", "разбио",
        "</B>", "његову", "круницу", "и", "<B>", "Џил", "се",
        "</B>", "преврнула", "после"]

def започни_затамњено(текст):
    true = 1
    false = 0
    ## затамњено говори да ли тренутно гледамо или не
    ## затамњени део текста.
    затамњено = false
    ## почетак_блок је индекс почетка неког незатмњеног 
    ## дела текста или затамњеног.
    почетак_блок = 0
    for идекс in range(len(текст)):
        ## Рукује са покретањем затамњеног текста
        if текст[индекс] == "<B>":
            if затамњено:
                print "Грешка: Додатно затамњено"
            ## print "Није затамњено:", тектс[почетак_блок:индекс]
            затамњено = true
            почетак_блок = индекс + 1
        ## Рукује крајем затамњених слова
        ## Не заборавите да је последњи број у делу индекс 
        ## након што је последњи индекс коришћен.
        if текст[индекс] == "</B>":
            if not затамњено:
                print "Грешка: сувише близу затамњеног"
            print "Затамњено[", почетак_блок, ":", индекс, "]", текст[почетак_блок:индекс]
            затамњено = false
            почетак_блок = индекс + 1

започни_затамњено(песма)

sa izlazom:

Затамњено [ 1 : 4 ] ['Џек', 'и', 'Џил']
Затамњено [ 11 : 15 ] ['да', 'донесу', 'кофу']
Затамњено [ 20 : 23 ] ['доле', 'и', 'разбио']
Затамњено [ 28 : 30 ] ['Џил', 'се']

Funkcija започни_затамњено() traži u listi koja je podeljena na reči i znakove. Znaci koje traži su <B> gde počinje zatamnjeni tekst i </B> gde se završava. Funkcija започни_затамњено() ide kroz kod i taži početak i kraj znakova.

Sledeći karakteristika sa listama je kopiranje. Ako pokušate nešto jednostavno kao:

>>> a = [1, 2, 3]
>>> b = a
>>> print b
[1, 2, 3]
>>> b[1] = 10
>>> print b
[1, 10, 3]
>>> print a
[1, 10, 3]

Ovo verovatno izgleda iznenađujuće s obzirom da je dobro došlo do izmene b rezultata u a. Ono što se događa je da naredba b = a pravi b kao referencu od a. Ovo znači da se b može posmatrati kao drugo ime za a. Stoga svaka modifikacija b menja a isto tako. Međutim, neki zadaci ne stvaraju dva imena za jednoj listi:

>>> a = [1, 2, 3]
>>> b = a * 2
>>> print a
[1, 2, 3]
>>> print b
[1, 2, 3, 1, 2, 3]
>>> a[1] = 10
>>> print a
[1, 10, 3]
>>> print b
[1, 2, 3, 1, 2, 3]

U ovom slučaju b nije referenca od a pošto izraz a * 2 stvara novu listu. Zatim naredba b = a * 2 daje b referencu za a * 2 pre nego referencu za a. Sve dodele operacija prave referencu. Kada prođete listu kao argument funkcije stvorili ste dobro reference. Većinu vremena ne morate da brinete o stvaranju referenci umesto kopija. Međutim, kada treba da se promeni jedna lista bez promene drugog imena liste treba da se uverite da ste stvarno stvorili kopiju.

Postoji nekoliko načina da napravite kopiju liste. Najjednostavniji koji uglavnom radi da operator odseca jer to uvek pravi novu listu čak iako je taj deo cela lista:

>>> a = [1, 2, 3]
>>> b = a[:]
>>> b[1] = 10
>>> print a
[1, 2, 3]
>>> print b
[1, 10, 3]

Uzimanjem dela [:] stvara se nova kopija liste. Međutim to kopira samo spoljašnju listu. Bilo koja podlista unutra je i dalje referenca podliste u originalnoj listi. Stoga, kada lista sadrži liste, unutrašnje liste moraju biti dobro kopirane. Možete to uraditi ručno ali Pajton već sadrži režim za to. Bi samo koristite deepcopy funkciju iz copy režima:

>>> import copy
>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = a[:]
>>> c = copy.deepcopy(a)
>>> b[0][1] = 10
>>> c[1][1] = 12
>>> print a
[[1, 10, 3], [4, 5, 6]]
>>> print b
[[1, 10, 3], [4, 5, 6]]
>>> print c
[[1, 2, 3], [4, 12, 6]]

Pre svega primetite da je a lista liste. Zatim da kada se b[0][1] = 10 porenu oba a i b su promenjeni, ali c nije. Ovo se dešava zato što su unutrašnji nizovi i dalje reference kada se koristi operator odsecanja. Međutim sa deepcopy c je potpuno iskopirano.

Pa, da li treba da brinem o ovim referencama svaki put kada koristim funkciju ili =? Dobra vest je da samo morate da brinete o referencama kada koristite rečnike i liste. Brojevi i nizovi stvaraju reference kada se dodeljuje ali svaka operacija nad brojevima i nizovima,koja ih menja, stvara novu kopiju pa ih nikada ne možete promeniti neočekivano. Vi morate da mislite o referencama samo kada menjate listu ili rečnik.

Do sada ste se verovatno zapitali zašto se uopšte koriste reference? Osnovni razlog je brzina. Mnogo je brže napraviti referencu za hiljadu elemenata liste nego da kopirate svaki element liste. Drugi razlog je je taj što Vam dozvoljava da imate funkciju za menjanje unete liste ili rečnika. Samo zapamtite za reference, ako ikad imate neki čudan problem sa izmenjenim podatkom koji ne bi trebalo da bude takav.

Šablon:Vodič za Pajton 2.6/Navigation