.:: KURS PROGRAMOWANIA W JĘZYKU PYTHON ::.




- Typy sekwencyjne


Po uruchomieniu IDLEa zgłasza się tryb interaktywny Pythona.
Wykorzystamy go do poznania Pythonowskich sekwencyjnych typów danych.
Sekwencyjne typy danych służą do zapamiętywania wielu wartości w pojedynczej zmiennej, w odróżnieniu od typów prostych, takich jak int, które w pojedynczej zmiennej mogą zachować tylko jedną wartość.



- Typy napisowy


Do tej pory poznaliśmy już jeden typ sekwencyjny. Jest nim typ napisowy (string). Przypomnijmy, że wartości napisów podajemy w cudzysłowach lub apostrofach:


>>> txt="napis"
>>> txt2='napis'


I, że możemy na nich wykonywać pewne operacje, np.:


>>> txt2+='owi nierówny'
>>> print txt2
napisowi nierówny


Napisy są sekwencjami znaków. Każdy typ sekwencyjny pozwala na dostęp do każdego swojego elementu z osobna.
Aby uzyskać dostęp do znaku na określonej pozycji podajemy jej indeks (numer porządkowy liczony od lewej, zero oznacza pierwszy znak napisu) w nawiasach kwadratowych bezpośrednio po napisie:


>>> "abc"[0]
'a'
>>> "abc"[1]
'b'
>>> "abc"[2]
'c'
>>> txt[0]
'n'
>>> txt[1]
'a'
>>> txt[2]
'p'
>>> txt[3]
'i'
>>> txt[4]
's'
>>> txt[5]

Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
    txt[5]
IndexError: string index out of range
>>> 


Powodem błędu była próba odczytania znaku o zbyt wysokim numerze, którego w napisie nie ma. Aby poznać długość napisu, posługujemy się "funkcją len":


>>> len("abc")
3
>>> len(txt)
5
>>> len(txt2)
17
>>> len(txt*20)
100 
>>>


Zliczać znaki możemy także od końca napisu w prawo. Używamy w tym celu indeksów ujemnych (-1 oznacza ostatni znak napisu):


>>> "abc"[-1]
'c'
>>> "abc"[-2]
'b'
>>> "abc"[-3]
'a'
>>> txt[-1]
's'
>>>



- Kody ASCII


Pojedynczy znak zapisany jest jako liczba odpowiadająca kodowi ASCII określonego symbolu graficznego.
Aby poznać kod ASCII określonego znaku, należy użyć "funkcji ord":


>>> ord('A')
65
>>> ord('a')
97
>>> ord("1")
49
>>> ord("2")
50


Parametrem "funkcji ord" musi być pojedynczy znak, a nie wieloznakowy napis:


>>> ord(txt[0])
110
>>> ord(txt)

Traceback (most recent call last):
  File "&<pyshell-52>", line 1, in -toplevel-
    ord(txt)
TypeError: ord() expected a character, but string of length 5 found
>>>


Aby zamienić kod ASCII na odpowiadający mu znak, używamy "funkcji chr":


>>> chr(65)
'A'
>>> chr(32)
' '
>>> chr(10)
'\n'
>>> chr(49)+chr(48)+chr(50)
'102'
>>>



- Fragmenty napisu


Czasami interesuje nas nie pobranie z napisu pojedynczego znaku, ale wykrojenie ciągu znaków. Do wykrajania fragmentów napisów używamy zapisu z dwukropkiem:
Fragment napisu do ósmego znaku:


>>> txt2[:8]
'napisowi'


Fragment napisu od dziesiątego znaku:


>>> print txt2[9:]
nierówny


Fragment napisu od szóstego do dwunastego znaku:


>>> txt2[5:12]
'owi nie'


Co drugi znak z fragmentu napisu od szóstego do dwunastego znaku:


>>> txt2[5:12:2]
'oine'


Możemy także używać indeksów ujemnych:


>>> txt2[:-9]
'napisowi'
>>> txt2[-8:]
'nier\xf3wny'
>>> txt2[-12:-5]
'owi nie'
>>> txt2[-12:-5:2]
'oine'



- Typ napisowy jako typ niezmienny


Sekwencyjne typy danych w Pythonie dzielimy na zmienne (mutable) i niezmienne (immutable). Typ napisowy należy do typów niezmiennych.
Typy niezmienne nie mogą zmieniać swojej wartości. A zatem zapis:


>>> txt+=chr(32)+txt2
>>> print txt
napis napisowi nierówny


tak naprawdę nie zmienia wartości zmiennej txt, ale tworzy nową zmienną o tej samej nazwie, a innej wartości, starą usuwając.
Konsekwencją niezmienności typu napisowego jest niemożność zmiany jego elementu:


>>> txt[2]='w'

Traceback (most recent call last):
  File "&<pyshell-41>", line 1, in -toplevel-
    txt[2]='w'
TypeError: object does not support item assignment
>>>


ani fragmentu:


>>> txt[2:4]='wis'

Traceback (most recent call last):
  File "&<pyshell-93>", line 1, in -toplevel-
    txt[2:4]='wis'
TypeError: object doesn't support slice assignment
>>>


Oczywiście, pożądaną operację możemy wykonać, inaczej formułując polecenie:


>>> txt2=txt[:2]+"w"+txt[3:]
>>> print txt2
nawis napisowi nierówny
>>>



- Inne typy sekwencyjne


Napisy mogą przechowywać sekwencje znaków. Czasami potrzebujemy jednak zapamiętać sekwencje danych nie będących znakami, ale np. liczbami lub innymi sekwencjami.
Do przechowywania takich sekwencji służą w Pythonie: krotki (tuples) i listy (lists).
Elementy zarówno krotek, jak i list mogą być dowolnego typu. Krotki są typem niezmiennym. Oznacza to, że mają z góry ustaloną długość, a zmiana wartości poszczególnych elementów z osobna nie jest możliwa.
Listy są typem zmiennym. Oznacza to, że można je łatwo skracać i wydłużać i jest możliwa zmiana wartości poszczególnych elementów z osobna.



- Tworzenie i używanie list


Listy tworzymy używając nawiasów kwadratowych, rozdzielając ich elementy przecinkami.
Aby stworzyć listę trzech liczb naturalnych, napiszemy:


>>> lista1 = [1, 2, 3]
>>> lista1
[1, 2, 3]


Aby stworzyć listę złożoną z czterech napisów, napiszemy:


>>> lista2 = ["pierwszy", txt, txt2, "ostatni"]
>>> lista2
['pierwszy', 'napis napisowi nier\xf3wny', 'nawis napisowi nier\xf3wny', 'ostatni']


Listy mogą zawierać elementy różnych typów:


>>> lista3 = [1.0, 2, "trzy"]
>>> lista3
[1.0, 2, 'trzy']


Listy mogą zawierać inne listy:


>>> lista4=[ [1, 2, 3], ["Nocny", "Dzienny"] ]
>>> lista4
[[1, 2, 3], ['Nocny', 'Dzienny']]


Listy mogą być puste:


>>> lista_pusta = []
>>> lista_pusta
[]
>>> len(lista_pusta)
0


Listy mogą zawierać tylko jeden element:


>>> lista_jednoelementowa = [1]
>>> lista_jednoelementowa
[1]


Można odczytywać wybiórczo zawartość poszczególnych elementów listy:


>>> lista1[0]
1
>>> lista2[-1]
'ostatni'


Lub ich ciągów:


>>> lista1[1:]
[2, 3]
>>> lista2[0::3] - co trzeci element listy
['pierwszy', 'ostatni']
>>> lista4[1:]
[['Nocny', 'Dzienny']]


Listy można powielać:


>>> lista2*=2
>>> lista2
['pierwszy', 'napis napisowi nier\xf3wny', 'nawis napisowi nier\xf3wny', 'ostatni', 'pierwszy', 'napis napisowi nier\xf3wny', 
'nawis napisowi nier\xf3wny', 'ostatni'] >>> []*1000 [] >>> [1,2,3]*0 []


Określać ich długość:


>>> len(lista2)
8


Skracać:


>>> lista2=lista2[:3]
>>> lista2
['pierwszy', 'napis napisowi nier\xf3wny', 'nawis napisowi nier\xf3wny']


Wydłużać:


>>> lista2+=['ostatni']
>>> lista2
['pierwszy', 'napis napisowi nier\xf3wny', 'nawis napisowi nier\xf3wny', 'ostatni']



- Modyfikacja list


Listy są sekwencjami zmiennymi, można więc modyfikować ich fragmenty:


>>> lista3
[1.0, 2, 'trzy']
>>> lista3[0:2]=["jeden","dwa"]
>>> lista3
['jeden', 'dwa', 'trzy']


lub pojedyncze elementy:


>>> lista1
[1, 2, 3, 4]
>>> lista1[2]+=1
>>> lista1
[1, 2, 4, 4]


Można też usuwać elementy ze środka listy, tak samo jak w sekwencjach niezmiennych:


>>> lista2=lista2[:2]+lista2[3:]
>>> lista2
['pierwszy', 'napis napisowi nier\xf3wny', 'ostatni']


Lub prościej, z użyciem instrukcji del, np.:


>>> del lista2[1]
>>> lista2
['pierwszy', 'ostatni']



- Porównywanie list


Porównywanie list odbywa się na zasadzie porównywania poszczególnych elementów:

- jeżeli elementy obu list są sobie równe, listy są równe

- jeżeli listy różnią się choć jednym elementem, to są nierówne

- jeżeli pierwszy element pierwszej listy jest większy od pierwszego elementu drugiej listy, to pierwsza lista jest większa od drugiej

- jeżeli pierwszy element pierwszej listy jest taki sam jak pierwszy element drugiej listy, decyduje porównanie drugich elementów, itd.

- element nieistniejący jest zawsze mniejszy od każdego innego elementu


>>> lista1 == [1, 2, 4, 4]
True
>>> lista1 != [1, 2, 3, 4]
True
>>> lista1 > [1, 2, 2, 5]
True
>>> lista1 &< [1, 2, 4, 4, 5]
True



- Sprawdzanie zawartości list


Aby sprawdzić, czy określona wartość znajduje się na liście, używamy "operatora in":


>>> 1 in lista1
True
>>> 2 not in lista1
False
>>> "pierwszy" in lista2
True



- Listy wielopoziomowe


W przypadku list wielopoziomowych, to jest takich, które zawierają inne listy, np.:


>>> lista4
[[1, 2, 3], ['Nocny', 'Dzienny']]


możliwy jest dostęp do poszczególnych elementów list podrzędnych poprzez użycie dwóch indeksów:


>>> lista4[1][0]
'Nocny'
>>> lista4[0][1]
2


Jako pierwszy podajemy zawsze indeks listy wyższego rzędu.



- Typ listy jako typ zmienny


W Pythonie wszystkie sekwencje zmienne nie odnoszą się do określonych danych, ale do miejsca w pamięci, w którym te dane się znajdują.
W związku z tym przypisanie listy do listy nie kopiuje wartości, a jedynie wskaźnik do nich:


>>> lista5=lista1
>>> lista5
[1, 2, 4, 4]


A zatem od tej pory, niezależnie czy zmieniamy elementy listy 1 czy 5, zmieniamy obie, bo zmianie tak naprawdę podlegają te same dane:


>>> lista1[2]=3
>>> lista5
[1, 2, 3, 4]
>>> lista5[2]=5
>>> lista1
[1, 2, 5, 4]


Jeżeli listę utworzono z innych list:


>>> lista6=[0,lista1]
>>> lista6
[0, [1, 2, 5, 4]]


To każda zmiana ich wartości będzie przenoszona na listę nadrzędną:


>>> lista1[1]=4
>>> lista6
[0, [1, 4, 5, 4]]


Co więcej, zmiana wartości listy nadrzędnej będzie przenoszona na listę podrzędną:


>>> lista6[1][0]=2
>>> lista1
[2, 4, 5, 4]



- Tworzenie i używanie krotek


Krotki pod wieloma względami przypominają listy, w podobny sposób tworzymy je i sprawdzamy ich wartości. W odróżnieniu od list, krotki są sekwencjami niezmiennymi, co powoduje różnice w sposobie ich
modyfikacji. Krotki tworzymy używając nawiasów okrągłych, rozdzielając ich elementy przecinkami. Aby stworzyć krotkę z trzech liczb naturalnych, napiszemy:


>>> krotka1=(1,2,3)
>>> krotka1
(1, 2, 3)


Przy czym nawiasy okrągłe można pomijać:


>>> krotka1=1,2,3
>>> krotka1
(1, 2, 3)


(Dla zachowania przejrzystości my tego robić nie będziemy.)
Krotki mogą zawierać elementy różnych typów:


>>> krotka2=(1.0, 2, "trzy")
>>> krotka2
(1.0, 2, 'trzy')


W tym sekwencyjnych


>>> krotka3=(krotka1, lista1)
>>> krotka3
((1, 2, 3), [2, 4, 5, 4])


Krotki mogą być puste:


>>> krotka_pusta = ()
>>> krotka_pusta
()
>>> len (krotka_pusta)
0


Krotki mogą zawierać tylko jeden element. Jako że zapis (1) oznacza liczbę jeden w nawiasie, tworząc krotki jednoelementowe obowiązkowo na ich końcu stawiamy przecinek:


>>> liczba=(1)
>>> liczba
1
>>> krotka_jednoelementowa=(1,)
>>> krotka_jednoelementowa
(1,)
>>> len(krotka_jednoelementowa)
1
>>>


Można odczytywać wybiórczo zawartość poszczególnych elementów krotki:


>>> krotka1[1]
2
>>> krotka3[-1]
[2, 4, 5, 4]


Lub ich ciągów:


>>> krotka1[1:]
(2, 3)
>>> krotka1[::2] - co drugi element krotki
(1, 3)


Krotki można powielać:


>>> krotka1*=2
>>> krotka1
(1, 2, 3, 1, 2, 3)


Skracać:


>>> krotka1=krotka1[:3]
>>> krotka1
(1, 2, 3)


Wydłużać:


>>> krotka1=krotka1+(4,)
>>> krotka1
(1, 2, 3, 4)



- Modyfikacja krotek


Krotki są sekwencjami niezmiennymi, więc nie można modyfikować ich fragmentów:


>>> krotka1[2]=1

Traceback (most recent call last):
  File "&<pyshell-151>", line 1, in -toplevel-
    krotka1[2]=1
TypeError: object does not support item assignment


Oczywiście, pożądaną operację możemy wykonać, inaczej formułując polecenie:


>>> krotka1=krotka1[:2]+(1,)+krotka1[3:]
>>> krotka1
(1, 2, 1, 4)



- Typ krotki jako typ niezmienny


Krotki są sekwencjami niezmiennymi, w związku z tym przypisanie krotki do krotki kopiuje faktyczne wartości, a nie jedynie wskaźnik do nich:


>>> krotka4=krotka1
>>> krotka4
(1, 2, 1, 4)
>>> krotka1=(1,2,3,4)
>>> krotka4
(1, 2, 1, 4)



- Konwersja typów sekwencyjnych


W konwersji typów sekwencyjnych używamy następujących instrukcji:

- "list" zamienia typ sekwencyjny na listę


>>> lista7=list(krotka5)
>>> lista7
[2, 4, 5, 4]
>>> lista8=list("abcd")
>>> lista8
['a', 'b', 'c', 'd']


- "tuple" zamienia typ sekwencyjny na krotkę


>>> krotka5=tuple(lista1)
>>> krotka5
(2, 4, 5, 4)
>>> krotka6=tuple("abcd")
>>> krotka6
('a', 'b', 'c', 'd')


- "str" zamienia typ sekwencyjny na napis


>>> str(krotka6)
"('a', 'b', 'c', 'd')"
>>> str(lista7)
'[2, 4, 5, 4]'


Lub krócej, przy użyciu odwróconych apostrofów:


>>> `krotka6`
"('a', 'b', 'c', 'd')"
>>> `lista7`
'[2, 4, 5, 4]'



- Pętle iterowane po elementach sekwencji


Aby wykonać jakieś operacje na wszystkich lub wybranych elementach sekwencji, najprościej jest posłużyć się "pętlą for ... in".
Przykładowo, aby wyświetlić w kolejnych liniach wszystkie elementy sekwencji lista1 napiszemy:


>>> for a in lista1:
      print a
      
2
4
5
4


gdzie "a" jest przykładową zmienną, która w danym powtórzeniu pętli przyjmuje wartość kolejnych elementów sekwencji.
Aby poznać numer aktualnego powtórzenia pętli, posługujemy się "funkcją enumerate":


>>> for nr, wartosc in enumerate(lista2):
      print nr,
      print wartosc
      
0 pierwszy
1 ostatni


gdzie "nr" jest zmienną zawierająca aktualny numer obiegu pętli, a wartosc zmienną, która w danym powtórzeniu pętli przyjmuje wartość kolejnych elementów sekwencji.
Możemy wykonywać pętlę tylko dla fragmentu sekwencji:


>>> for i in lista7[1:3]:
      print i,i**2

4 16
5 25


A wewnątrz pętli wykonywać instrukcje warunkowe:


>>> for i in lista7:
      if i>0:
            print i, i**0.5

2 1.41421356237
4 2.0
5 2.2360679775
4 2.0



- Ćwiczenia kontrolne


I. Napisz program "parzyste2.py", który wczyta od użytkownika liczbę całkowitą i bez użycia instrukcji "if" wyświetli informację, czy jest to liczba parzysta, czy nieparzysta.

II. Napisz program "numer.py", który zamieni wprowadzony przez użytkownika ciąg cyfr na formę tekstową:
a) znaki nie będące cyframi mają być ignorowane
b) konwertujemy cyfry, nie liczby, a zatem:
- 911 to "dziewięć jeden jeden"
- 1100 to "jeden jeden zero zero"





-- back