Водич за Пајтон 2.6/Више са листама

Извор: Викикњиге

Већ смо видели листе и како се могу користити. Сада када имате мало више предзања ићи ћу у више детаља о листама. Прво ћемо погледати више начина да се добију елементи у листи, а онда ћемо причати о копирању.

Ево неких примера коришћења приступа индексирања једном елементу листе:

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

Сви ови примери треба да изгледају познато. Ако желите прву ставку у листи само погледајте индекс 0. Друга ставка је индекс 1 и тако даље кроз листу. Међутим шта ако желите последњу ставку у листи? Један начин би био коришћење len() функције као неки_бројеви[len(неки_бројеви) - 1]. Овај начин ради пошто len() функција увек враћа последњи индекс плус један. други би онда био неки_бројеви[len(неки_бројеви) - 2]. Постоји лакши начин да се ово уради. У Пајтону последња ставка је увек индекс -1. Претпоследњи је индекс -2 and и тако даље. Ево још неких примера:

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

Тако свака ставка у листи може бити индексирана на два начина: спреда и отпозади.

Други користан начин да се у деловима листе користи одсецање. Ево још једног примера који ће Вам дати идеју за шта може да се користи:

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

Пресецање се користи да се врати део листе. Оператор одсецање је у облику ствари[први_индекс:последњи_индекс]. Одсецање сече листу после први_индекс и пре последњи_индекс и враћа делове између. Можете користити оба типа индексирања:

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

Други трик је са осецањем неодређеног индекса. Ако први индекс није одређен почетак листе се претпоставља. Ако последњи индекс није наведен цео остатак листе се претпоставља. Овде су неки примери:

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

Овде је (HTML-ом инспирисан) пример програма (копирате у песми дефиниције ако желите):

песма = ["<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

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

са излазом:

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

Функција започни_затамњено() тражи у листи која је подељена на речи и знакове. Знаци које тражи су <B> где почиње затамњени текст и </B> где се завршава. Функција започни_затамњено() иде кроз код и тажи почетак и крај знакова.

Следећи карактеристика са листама је копирање. Ако покушате нешто једноставно као:

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

Ово вероватно изгледа изненађујуће с обзиром да је добро дошло до измене b резултата у a. Оно што се догађа је да наредба b = a прави b као референцу од a. Ово значи да се b може посматрати као друго име за a. Стога свака модификација b мења a исто тако. Међутим, неки задаци не стварају два имена за једној листи:

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

У овом случају b није референца од a пошто израз a * 2 ствара нову листу. Затим наредба b = a * 2 даје b референцу за a * 2 пре него референцу за a. Све доделе операција праве референцу. Када прођете листу као аргумент функције створили сте добро референце. Већину времена не морате да бринете о стварању референци уместо копија. Међутим, када треба да се промени једна листа без промене другог имена листе треба да се уверите да сте стварно створили копију.

Постоји неколико начина да направите копију листе. Најједноставнији који углавном ради да оператор одсеца јер то увек прави нову листу чак иако је тај део цела листа:

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

Узимањем дела [:] ствара се нова копија листе. Међутим то копира само спољашњу листу. Било која подлиста унутра је и даље референца подлисте у оригиналној листи. Стога, када листа садржи листе, унутрашње листе морају бити добро копиране. Можете то урадити ручно али Пајтон већ садржи режим за то. Би само користите deepcopy функцију из copy режима:

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

Пре свега приметите да је a листа листе. Затим да када се b[0][1] = 10 порену оба a и b су промењени, али c није. Ово се дешава зато што су унутрашњи низови и даље референце када се користи оператор одсецања. Међутим са deepcopy c је потпуно ископирано.

Па, да ли треба да бринем о овим референцама сваки пут када користим функцију или =? Добра вест је да само морате да бринете о референцама када користите речнике и листе. Бројеви и низови стварају референце када се додељује али свака операција над бројевима и низовима,која их мења, ствара нову копију па их никада не можете променити неочекивано. Ви морате да мислите о референцама само када мењате листу или речник.

До сада сте се вероватно запитали зашто се уопште користе референце? Основни разлог је брзина. Много је брже направити референцу за хиљаду елемената листе него да копирате сваки елемент листе. Други разлог је је тај што Вам дозвољава да имате функцију за мењање унете листе или речника. Само запамтите за референце, ако икад имате неки чудан проблем са измењеним податком који не би требало да буде такав.

Шаблон:Водич за Пајтон 2.6/Navigation