3. Podstawy języka Python

3.1. Skrypt [bases_01]: operacje podstawowe
Skrypt [bases_01] przedstawia podstawowe cechy języka Python.
# ----------------------------------
def affiche(chaine):
# wyświetla ciąg znaków
print("chaine=%s" % chaine)
# ----------------------------------
def affiche_type(variable):
# wyświetla typ zmiennej
print("type[%s]=%s" % (variable, type(variable)))
# ----------------------------------
def f1(param):
# dodaje 10 do parametru
return param + 10
# ----------------------------------
def f2():
# zwraca krotkę zawierającą 3 wartości
return "un", 0, 100
# -------------------------------- program główny ------------------------------------
# to jest komentarz
# zmienna użyta bez zadeklarowania
nom = "dupont"
# wyświetlanie na ekranie
print("nom=%s" % nom)
# lista zawierająca elementy różnych typów
liste = ["un", "deux", 3, 4]
# liczba elementów
n = len(liste)
# pętla
for i in range(n):
print("liste[%d]=%s" % (i, liste[i]))
# inicjalizacja dwóch zmiennych za pomocą krotki
(chaine1, chaine2) = ("chaine1", "chaine2")
# konkatenacja dwóch ciągów znaków
chaine3 = chaine1 + chaine2
# wyświetlenie wyniku
print("[%s,%s,%s]" % (chaine1, chaine2, chaine3))
# użycie funkcji
affiche(chaine1)
# typ zmiennej może być znany
affiche_type(n)
affiche_type(chaine1)
affiche_type(liste)
# typ zmiennej może ulec zmianie w trakcie wykonywania programu
n = "a changé"
affiche_type(n)
# funkcja może zwracać wynik
res1 = f1(4)
print("res1=%s" % res1)
# funkcja może zwracać listę wartości
(res1, res2, res3) = f2()
print("(res1,res2,res3)=[%s,%s,%s]" % (res1, res2, res3))
# wartości te można by zapisać w zmiennej
liste = f2()
for i in range(len(liste)):
print("liste[%s]=%s" % (i, liste[i]))
# testy
for i in range(len(liste)):
# wyświetla tylko ciągi znaków
if type(liste[i]) == "str":
print("liste[%s]=%s" % (i, liste[i]))
# dalsze testy
for i in range(len(liste)):
# wyświetla tylko liczby całkowite większe niż 10
if type(liste[i]) == "int" and liste[i] > 10:
print("liste[%s]=%s" % (i, liste[i]))
# pętla while
liste = (8, 5, 0, -2, 3, 4)
i = 0
somme = 0
while i < len(liste) and liste[i] > 0:
print("liste[%s]=%s" % (i, liste[i]))
somme += liste[i] # suma = suma + lista[i]
i += 1 # i = i + 1
print("somme=%s" % somme)
# koniec programu
Komentarze
- wiersz 2: słowo kluczowe def definiuje funkcję;
- wiersz 2: funkcja przyjmuje parametr [chaine]. Nie określa się typu parametru. W języku Python stosuje się wyłącznie przekazywanie wartości. Wartość ta różni się w zależności od danych:
- w przypadku typu prostego (liczba, wartość logiczna…) jest to wartość zawarta w danym (4, True…);
- w przypadku typu złożonego (lista, klasa…) wartością tą jest adres danego elementu;
- wiersze 3–4: treść funkcji. Jest ona wcięta w prawo o jeden znak tabulacji. To właśnie to wcięcie w połączeniu ze znakiem : w instrukcji def określa treść funkcji. Dotyczy to wszystkich instrukcji zawierających treść: if, else, while, for, try, except;
- wiersz 4: zastosowana tutaj składnia to [print('text1%F1text2%F2…' % data1, data2)]:
- [%Fi] (tutaj %s) to formaty wyświetlania:
- %s (string): dla ciągu znaków;
- %d (decimal): dla liczb całkowitych ze znakiem;
- %f (float): format dziesiętny dla liczb rzeczywistych;
- %e (exponentiel): format wykładniczy dla liczby rzeczywistej;
- …
- [data1, data2…] to wyrażenia, których wartości chcemy wyświetlić:
- [data1] zostanie wyświetlone w formacie F1;
- [data2] zostanie wyświetlone w formacie F2;
- …
- wiersz 10: Python wewnętrznie zarządza typami zmiennych. Typ zmiennej można sprawdzić za pomocą funkcji type(variable), która zwraca zmienną typu „type”. Wyrażenie „%s” % (type(zmienna)) to ciąg znaków reprezentujący typ zmiennej;
- wiersz 25: program główny. Zazwyczaj (ale niekoniecznie) znajduje się on po zdefiniowaniu wszystkich funkcji skryptu. Jego treść nie jest wcięta;
- wiersz 28: w języku Python nie deklaruje się zmiennych. Python rozróżnia wielkość liter. Zmienna Nom różni się od zmiennej nom. Ciąg znaków można ująć w cudzysłowy „” lub apostrofy '. Można więc zapisać 'dupont' lub „dupont”;
- wiersz 34: istnieje różnica między krotką (1,2,3) (zwróć uwagę na nawiasy) a listą [1,2,3] (zwróć uwagę na nawiasy kwadratowe). Krotka jest niezmienna, podczas gdy lista jest zmienna. W obu przypadkach element o numerze i jest oznaczony jako [i];
- wiersz 40: range(n) to krotka (0,1,2,…,n-1);
- wiersz 41: format %d jest używany dla liczb całkowitych ze znakiem;
- wiersz 74: len(var) to liczba elementów zbioru var (krotka, lista, słownik…);
- wiersz 84: struktura [for in …] umożliwia iterację nad strukturą iterowalną. Listy i krotki są elementami iterowalnymi;
- wiersz 86: pozostałe operatory boolowskie to or i not;
- wiersz 93: oblicza sumę liczb większych od 0 z listy;
Wyniki wyświetlane na ekranie są następujące:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/bases/bases_01.py
nom=dupont
liste[0]=un
liste[1]=deux
liste[2]=3
liste[3]=4
[chaine1,chaine2,chaine1chaine2]
chaine=chaine1
type[4]=<class 'int'>
type[chaine1]=<class 'str'>
type[['un', 'deux', 3, 4]]=<class 'list'>
type[a changé]=<class 'str'>
res1=14
(res1,res2,res3)=[un,0,100]
liste[0]=un
liste[1]=0
liste[2]=100
liste[0]=8
liste[1]=5
somme=13
Process finished with exit code 0
3.2. Skrypt [bases_02]: formatowanie ciągów znaków
W Pythonie 3 wprowadzono nowy sposób formatowania ciągów znaków:
# ciągi formatujące
# formaty są zgodne z językiem C
# liczba całkowita
int1 = 10
print(f"[int1={int1}]")
print(f"[int1={int1:4d}]")
print(f"[int1={int1:04d}]")
# liczba zmiennoprzecinkowa
float1=8.2
print(f"[float1={float1}]")
print(f"[float1={float1:8.2f}]")
print(f"[float1={float1:.3e}]")
# ciąg znaków
str1="abcd"
print(f"[str1={str1}]")
print(f"[str1={str1:8s}]")
str2="jean de florette"
print(f"[{str2:20.10s}]")
# sformacjonowane ciągi znaków można przypisywać do zmiennych
str3=f"[{str2:20.10s}]"
print(str3)
Składnia sformatowanego ciągu znaków jest następująca:
gdzie:
- [expri]: wyrażenie;
- [formati]: format wyrażenia [expri]. Formaty te są zgodne z językiem C:
- %d: dla liczb całkowitych;
- %f: notacja dziesiętna dla liczb rzeczywistych;
- %e: notacja wykładnicza dla liczb rzeczywistych;
- %s: dla ciągów znaków. Jest to format stosowany, gdy nie zastosowano żadnego formatu dla [expri];
- %nd, %nf, %ns: wyświetla [expri] w n znakach: ciąg znaków jest albo obcięty, albo uzupełniony spacjami;
- wiersz 7: [04d], liczba całkowita o długości 4 znaków, uzupełniona z lewej strony zerami;
- wiersz 11: [8.2f], liczba zmiennoprzecinkowa składająca się z 8 znaków, w tym 2 po przecinku;
- wiersz 12: [.3e], liczba zmiennoprzecinkowa w postaci wykładniczej z 3 miejscami po przecinku dla mantysy;
- wiersz 18: [20.10s], pierwsze 10 znaków ciągu uzupełnionego spacjami do 20 znaków;
Wyniki wykonania są następujące:
3.3. Skrypt [bases_03]: zmiany typów
W tym miejscu skupiamy się na zmianach typów danych typu str (ciąg znaków), int (liczba całkowita), float (liczba zmiennoprzecinkowa) oraz bool (wartość logiczna).
# zmiany typu
# int --> str, float, bool
x = 4
print(x, type(x))
x = str(4)
print(x, type(x))
x = float(4)
print(x, type(x))
x = bool(4)
print(x, type(x))
# bool → int, float, str
x = True
print(x, type(x))
x = int(True)
print(x, type(x))
x = float(True)
print(x, type(x))
x = str(True)
print(x, type(x))
# str → int, float, bool
x = "4"
print(x, type(x))
x = int("4")
print(x, type(x))
x = float("4")
print(x, type(x))
x = bool("4")
print(x, type(x))
# float → str, int, bool
x = 4.32
print(x, type(x))
x = str(4.32)
print(x, type(x))
x = int(4.32)
print(x, type(x))
x = bool(4.32)
print(x, type(x))
# obsługa błędów związanych ze zmianą typu
try:
x = int("abc")
print(x, type(x))
except ValueError as erreur:
print(erreur)
# różne przypadki
x = bool("abc")
print(x, type(x))
x = bool("")
print(x, type(x))
x = bool(0)
print(x, type(x))
x = None
print(x, type(x))
x = bool(None)
print(x, type(x))
x = bool(0.0)
print(x, type(x))
# wszystkie dane są instancjami klasy i jako takie posiadają metody
# ciąg znaków
str1 = "abc"
print(str1.capitalize())
# liczba całkowita
int1 = 4
print(int1.bit_length())
# wartość logiczna
bool1=True
print(bool1.conjugate())
# liczba rzeczywista
float1=8.2
print (float1.is_integer())
Możliwych jest wiele zmian typów. Niektóre z nich mogą zakończyć się niepowodzeniem, jak na przykład w wierszach 46–47, gdzie próbuje się przekształcić ciąg znaków „abc” w liczbę całkowitą. Błąd ten został obsłużony za pomocą struktury try / except. Ogólna postać tej struktury
wygląda następująco:
try:
actions
except Exception as ex:
actions
finally:
actions
Jeśli którekolwiek z działań w bloku try wygeneruje wyjątek (zgłosi błąd), następuje natychmiastowe przejście do klauzuli except. Jeśli działania w bloku try nie wygenerują wyjątku, klauzula except jest pomijana. Atrybuty Exception i ex instrukcji except są opcjonalne. Gdy są obecne, atrybut Exception określa typ wyjątku przechwyconego przez instrukcję except, a atrybut ex zawiera sam wyjątek, który wystąpił. Może występować wiele instrukcji except, jeśli chce się obsługiwać różne typy wyjątków w tej samej instrukcji try.
Instrukcja finally jest opcjonalna. Jeśli występuje, działania określone w instrukcji finally są zawsze wykonywane, niezależnie od tego, czy wystąpił wyjątek, czy nie.
Do kwestii wyjątków powrócimy nieco później.
Wiersze 49–61 przedstawiają różne próby przekształcenia danych typu str, int, float, NoneType na wartości logiczne. Jest to zawsze możliwe. Zasady są następujące:
- bool(int i) ma wartość False, jeśli i wynosi 0, a True we wszystkich pozostałych przypadkach;
- bool(float f) ma wartość False, jeśli f wynosi 0,0, a True we wszystkich pozostałych przypadkach;
- bool(str chaine) przyjmuje wartość False, jeśli chaine ma 0 znaków, a True we wszystkich pozostałych przypadkach;
- bool(None) ma wartość False. None to wartość specjalna oznaczająca, że zmienna istnieje, ale nie ma wartości.
Wyniki wyświetlane na ekranie są następujące:
Należy zauważyć, że wszystkie dane są obiektami, czyli instancjami klasy. Oznacza to, że mogą posiadać metody. Pokazują to wiersze 63–75 kodu. Nie zamierzamy tutaj wyjaśniać, do czego służą użyte metody, a jedynie pokazać, że istnieją.
3.4. Skrypt [bases_04]: zakres zmiennych
Skrypt [bases_04] pokazuje, że w języku Python nie ma pojęcia zmiennej o zasięgu blokowym:
# zakres zmiennych
i = 4
if True:
i += 1
j = 7
print(f"i={i}, j={j}")
Wyniki
Komentarze
Wyniki wskazują na dwie rzeczy:
- wiersz 4: zmienna [i] z bloku [if] jest taka sama jak zmienna i użyta w wierszu 2;
- wiersz 6: zmienna [j] jest tą samą zmienną, która została zainicjowana w bloku [if];
W niektórych językach programowania, w których deklaruje się zmienne, zmienna zdefiniowana w bloku (takim jak ten w wierszach 3–5) nie jest znana poza tym blokiem. W języku Python tak nie jest.
3.5. Skrypt [bases_05]: listy – 1
Skrypt [bases_05] wygląda następująco:
# listy jednowymiarowe
# inicjalizacja
list1 = [0, 1, 2, 3, 4, 5]
# przeglądanie – 1
print(f"list1 a {len(list1)} éléments")
for i in range(len(list1)):
print(f"list1[{i}]={list1[i]}")
list1[1] = 10
# przeglądanie – 2
print(f"list1 a {len(list1)} éléments")
for element in list1:
print(element)
# dodawanie dwóch elementów
list1[len(list1):] = [10, 11]
# format %s pozwala wyświetlić listę w jednym wierszu
print("%s" % list1)
# usunięcie dwóch ostatnich elementów
list1[len(list1) - 2:] = []
# format domyślny pozwala wyświetlić listę w jednym wierszu
print(f"{list1}")
# dodanie listy na początku listy
list1[:0] = [-10, -11, -12]
print(f"{list1}")
# wstawienie dwóch elementów w środku listy
list1[3:3] = [100, 101]
print(f"{list1}")
# usunięcie dwóch elementów ze środka listy
list1[3:4] = []
print(f"{list1}")
Uwagi:
- notacja tablica[i:j] oznacza elementy od i do j-1 tablicy;
- notacja [i:] oznacza elementy od i oraz kolejne w tablicy;
- zapis [:i] oznacza elementy tablicy od 0 do i-1;
- wiersz 19: print (%s) % (list1) wyświetla ciąg znaków: „[ list1[0], list1[2]…, list1[n-1]]”;
- wiersz 24: zapis print ('f{list1}') daje ten sam efekt;
Wyniki
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/bases/bases_05.py
list1 a 6 éléments
list1[0]=0
list1[1]=1
list1[2]=2
list1[3]=3
list1[4]=4
list1[5]=5
list1 a 6 éléments
0
10
2
3
4
5
[0, 10, 2, 3, 4, 5, 10, 11]
[0, 10, 2, 3, 4, 5]
[-10, -11, -12, 0, 10, 2, 3, 4, 5]
[-10, -11, -12, 100, 101, 0, 10, 2, 3, 4, 5]
[-10, -11, -12, 101, 0, 10, 2, 3, 4, 5]
Process finished with exit code 0
3.6. Skrypt [bases_06]: listy – 2
Powyższy kod można zapisać inaczej (bases_06), wykorzystując niektóre metody list:
# listy jednowymiarowe
# inicjalizacja
list1 = [0, 1, 2, 3, 4, 5]
# przeglądanie – 1
print(f"list1 a {len(list1)} éléments")
for i in range(len(list1)):
print(f"list1[{i}]={list1[i]}")
# modyfikacja elementu
list1[1] = 10
# przeglądanie – 2
print(f"list1 a {len(list1)} éléments")
for element in list1:
print(element)
# dodanie dwóch elementów
list1.extend([10, 11])
print(f"{list1}")
# usunięcie dwóch ostatnich elementów
del list1[len(list1) - 2:]
print(f"{list1}")
# dodanie krotki na początku listy
for i in (-12, -11, -10):
list1.insert(0, i)
print(f"{list1}")
# wstawienie w środku listy
for i in (101, 100):
list1.insert(3, i)
print(f"{list1}")
# usunięcie w środku listy
del list1[3:4]
print(f"{list1}")
Uzyskane wyniki są takie same jak w poprzedniej wersji.
3.7. Skrypt [bases_07]: słownik
Skrypt [bases_07] pokazuje, jak zdefiniować i wykorzystać słownik, zwany czasem tablicą asocjacyjną.
# funkcja sprawdzająca, czy klucz „mari” występuje w słowniku „conjoints”
def existe(conjoints, mari):
if mari in conjoints:
print(f"La clé [{mari}] existe associée à la valeur [{conjoints[mari]}]")
else:
print(f"La clé [{mari}] n'existe pas")
# ----------------------------- Główna
# słownik
conjoints = {"Pierre": "Gisèle", "Paul": "Virginie", "Jacques": "Lucette", "Jean": ""}
# przeglądanie – 1
print(f"Nombre d'éléments du dictionnaire : {len(conjoints)}")
for (clé, valeur) in conjoints.items():
print(f"conjoints[{clé}]={valeur}")
# lista kluczy słownika
print("liste des clés-------------")
clés = conjoints.keys()
print(f"{clés}")
# lista wartości słownika
print("liste des valeurs------------")
valeurs = conjoints.values()
print(f"{valeurs}")
# wyszukiwanie klucza
existe(conjoints, "Jacques")
existe(conjoints, "Lucette")
existe(conjoints, "Jean")
# usunięcie pary klucz-wartość
del (conjoints["Jean"])
print(f"Nombre d'éléments du dictionnaire : {len(conjoints)}")
print(f"{conjoints}")
# klucze i wartości słownika nie są listami
print(f"type des clés : {type(clés)}")
print(f"type des valeurs : {type(valeurs)}")
# można je przekształcić w listy
lclés = list(clés)
print(f"clés : {type(lclés)}, {lclés}")
lvaleurs = list(valeurs)
print(f"valeurs : {type(lvaleurs)}, {lvaleurs}")
Uwagi:
- wiersz 11: stała definicja słownika;
- wiersz 15: funkcja conjoints.items() zwraca listę par (klucz, wartość) ze słownika jako zbiór;
- wiersz 20: funkcja conjoints.keys() zwraca klucze słownika;
- wiersz 25: funkcja conjoints.values() zwraca wartości słownika conjoints;
- wiersz 3: „mari” w słowniku „conjoints” zwraca True, jeśli klucz mari istnieje w słowniku conjoints, w przeciwnym razie zwraca False;
- wiersz 36: słownik można wyświetlić w jednym wierszu.
Wyniki
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/bases/bases_07.py
Nombre d'éléments du dictionnaire : 4
conjoints[Pierre]=Gisèle
conjoints[Paul]=Virginie
conjoints[Jacques]=Lucette
conjoints[Jean]=
liste des clés-------------
dict_keys(['Pierre', 'Paul', 'Jacques', 'Jean'])
liste des valeurs------------
dict_values(['Gisèle', 'Virginie', 'Lucette', ''])
La clé [Jacques] existe associée à la valeur [Lucette]
La clé [Lucette] n'existe pas
La clé [Jean] existe associée à la valeur []
Nombre d'éléments du dictionnaire : 3
{'Pierre': 'Gisèle', 'Paul': 'Virginie', 'Jacques': 'Lucette'}
type des clés : <class 'dict_keys'>
type des valeurs : <class 'dict_values'>
clés : <class 'list'>, ['Pierre', 'Paul', 'Jacques']
valeurs : <class 'list'>, ['Gisèle', 'Virginie', 'Lucette']
Process finished with exit code 0
Uwagi:
- w wierszach 16–17 wyników należy zauważyć, że klucze i wartości słownika nie tworzą listy, lecz typ „dict_keys”;
- wiersze 18–19: prosta zmiana typu pozwala przekonwertować je na typ [list];
3.8. Skrypt [bases_08]: krotki
Krotka wykazuje podobieństwa do listy, ale nie można jej modyfikować:
# krotki
# inicjalizacja
tuple1 = (0, 1, 2, 3, 4, 5)
# przeglądanie – 1
print(f"tuple1 a {len(tuple1)} elements")
for i in range(len(tuple1)):
print(f"tuple1[{i}]={tuple1[i]}")
# przeglądanie – 2
print(f"tuple1 a {len(tuple1)} elements")
for element in tuple1:
print(element)
# krotka może być wyświetlona w jednym wierszu
print(f"tuple1={tuple1}")
# krotka nie może być modyfikowana
tuple1[0] = 10
Wyniki
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/bases/bases_08.py
tuple1 a 6 elements
tuple1[0]=0
tuple1[1]=1
tuple1[2]=2
tuple1[3]=3
tuple1[4]=4
tuple1[5]=5
tuple1 a 6 elements
0
1
2
3
4
5
tuple1=(0, 1, 2, 3, 4, 5)
Traceback (most recent call last):
File "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/bases/bases_08.py", line 19, in <module>
tuple1[0] = 10
TypeError: 'tuple' object does not support item assignment
Process finished with exit code 1
Uwagi:
- wiersze 17–20 wyników: pokazują, że krotki nie można modyfikować.
3.9. Skrypt [bases_09]: wielowymiarowe listy i słowniki
Skrypt [bases_09] pokazuje, jak zdefiniować i wykorzystać wielowymiarową listę lub słownik:
# listy wielowymiarowe
# inicjalizacja
multi = [[0, 1, 2], [10, 11, 12, 13], [20, 21, 22, 23, 24]]
# przeglądanie
for i1 in range(len(multi)):
for i2 in range(len(multi[i1])):
print(f"multi[{i1}][{i2}]={multi[i1][i2]}")
# wyświetlanie w jednym wierszu
print(f"multi={multi}")
# słowniki wielowymiarowe
# inicjalizacja
multi = {"zéro": [0, 1], "un": [10, 11, 12, 13], "deux": [20, 21, 22, 23, 24]}
# przeglądanie
for (clé, valeur) in multi.items():
for i2 in range(len(valeur)):
print(f"multi[{clé}][{i2}]={multi[clé][i2]}")
# wyświetlanie w jednym wierszu
print(f"multi={multi}")
Komentarze
- wiersz 7: multi[i1] jest listą;
- wiersz 18: wartość jest listą;
Wyniki
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/bases/bases_09.py
multi[0][0]=0
multi[0][1]=1
multi[0][2]=2
multi[1][0]=10
multi[1][1]=11
multi[1][2]=12
multi[1][3]=13
multi[2][0]=20
multi[2][1]=21
multi[2][2]=22
multi[2][3]=23
multi[2][4]=24
multi=[[0, 1, 2], [10, 11, 12, 13], [20, 21, 22, 23, 24]]
multi[zéro][0]=0
multi[zéro][1]=1
multi[un][0]=10
multi[un][1]=11
multi[un][2]=12
multi[un][3]=13
multi[deux][0]=20
multi[deux][1]=21
multi[deux][2]=22
multi[deux][3]=23
multi[deux][4]=24
multi={'zéro': [0, 1], 'un': [10, 11, 12, 13], 'deux': [20, 21, 22, 23, 24]}
Process finished with exit code 0
3.10. Skrypt [bases_10]: powiązania między ciągami znaków a listami
Skrypt [bases_10] pokazuje, jak pobrać do listy elementy ciągu znaków oddzielone tym samym separatorem.
# przekształcanie ciągu znaków w listę
chaine = '1:2:3:4'
liste = chaine.split(':')
print(type(liste))
# wyświetlanie listy
print(f"liste a {len(liste)} éléments")
print(f"liste={liste}")
# z listy do ciągu znaków
chaine2 = ":".join(liste)
print(f"chaine2={chaine2}")
# dodajmy puste pole
chaine += ":"
print(f"chaine={chaine}")
liste = chaine.split(":")
# wyświetlanie listy
print(f"liste a {len(liste)} éléments")
print(f"liste={liste}")
# dodajmy ponownie puste pole
chaine += ":"
print(f"chaine={chaine}")
liste = chaine.split(":")
# wyświetlanie listy
print(f"liste a {len(liste)} éléments")
print(f"liste={liste}")
Uwagi:
- wiersz 3: metoda chaine.split(separator) dzieli ciąg znaków chaine na elementy oddzielone separatorem séparateur i zwraca je w postaci listy. W ten sposób wyrażenie '1:2:3:4'.split(":") ma wartością listę („1”, „2”, „3”, „4”);
- wiersz 11: 'separator'.join(lista) zwraca ciąg znaków 'lista[0]+separator+lista[1]+separator+…'.
Wyniki
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/bases/bases_10.py
<class 'list'>
liste a 4 éléments
liste=['1', '2', '3', '4']
chaine2=1:2:3:4
chaine=1:2:3:4:
liste a 5 éléments
liste=['1', '2', '3', '4', '']
chaine=1:2:3:4::
liste a 6 éléments
liste=['1', '2', '3', '4', '', '']
Process finished with exit code 0
3.11. Skrypt [bases_11]: wyrażenia regularne
Skrypt [bases_11] pokazuje, jak używać wyrażeń regularnych:
# importujemy moduł wyrażeń regularnych
import re
# --------------------------------------------------------------------------
def compare(modèle, chaine):
# porównuje ciąg znaków [chaîne] z wzorcem [modèle]
# wyświetlanie wyników
print(f"\nRésultats({chaine},{modèle})")
match = re.match(modèle, chaine)
if match:
print(match.groups())
else:
print(f"La chaîne [{chaine}] ne correspond pas au modèle [{modèle}]")
# wyrażenia regularne w języku Python
# pobieranie poszczególnych pól z ciągu znaków
# wzór: ciąg cyfr otoczony dowolnymi znakami
# chcemy wyodrębnić tylko ciąg cyfr
modèle = r"^.*?(\d+).*?$"
# porównujemy ciąg znaków z wzorcem
compare(modèle, "xyz1234abcd")
compare(modèle, "12 34")
compare(modèle, "abcd")
# wzór: ciąg cyfr otoczony dowolnymi znakami
# chcemy uzyskać ciąg cyfr wraz z polami poprzedzającymi i następującymi po nim
modèle = r"^(.*?)(\d+)(.*?)$"
# porównujemy ciąg znaków z wzorcem
compare(modèle, "xyz1234abcd")
compare(modèle, "12 34")
compare(modèle, "abcd")
# wzorzec – data w formacie dd/mm/rr
modèle = r"^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$"
compare(modèle, "10/05/97")
compare(modèle, " 04/04/01 ")
compare(modèle, "5/1/01")
# wzór – liczba dziesiętna
modèle = r"^\s*([+-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*$"
compare(modèle, "187.8")
compare(modèle, "-0.6")
compare(modèle, "4")
compare(modèle, ".6")
compare(modèle, "4.")
compare(modèle, " + 4")
# koniec
Uwagi:
- zwróć uwagę na moduł [re] zaimportowany w wierszu 2. To właśnie on zawiera funkcje do obsługi wyrażeń regularnych;
- wiersz 10: porównanie ciągu znaków z wyrażeniem regularnym (wzorem) zwraca wartość logiczną True, jeśli ciąg znaków pasuje do wzoru, a w przeciwnym razie – False;
- wiersz 12: match.groups() to krotka, której elementami są fragmenty ciągu odpowiadające elementom wyrażenia regularnego ujętym w nawiasy. W wzorcu:
- ^.*?(\d+).*?, match.groups() będzie krotką jednoelementową, ponieważ występuje nawias;
- ^(.*?)(\d+)(.*?)$, match.groups() będzie krotką składającą się z 3 elementów, ponieważ występują trzy nawiasy;
- wiersz 21: dosłowne wyrażenie regularne zapisuje się jako r"xxx". To właśnie symbol r sprawia, że ciąg znaków staje się wyrażeniem regularnym;
Wyrażenia regularne pozwalają nam sprawdzać format ciągu znaków. Dzięki temu możemy zweryfikować, czy ciąg znaków reprezentujący datę ma format dd/mm/rr. W tym celu używamy wzorca i porównujemy ciąg znaków z tym wzorcem. Tak więc w tym przykładzie j, m i a muszą być cyframi. Szablon prawidłowego formatu daty to zatem „\d\d/\d\d/\d\d”, gdzie symbol \d oznacza cyfrę. W szablonie można używać następujących symboli:
Znak | Opis |
\ | Oznacza następny znak jako znak specjalny lub dosłowny. Na przykład „n” odpowiada znakowi „n”, podczas gdy „\n” odpowiada znakowi nowego wiersza. Sekwencja „\\” odpowiada znakowi „\”, natomiast „\(" odpowiada znakowi „(”. |
^ | Odpowiada początkowi ciągu. |
$ | Odpowiada końcowi ciągu. |
* | Odpowiada poprzedniemu znakowi, zero lub więcej razy. Tak więc „zo*” odpowiada „z” lub „zoo”. |
+ | Odpowiada poprzedniemu znakowi, jeden lub więcej razy. Na przykład „zo+” odpowiada „zoo”, ale nie odpowiada „z”. |
? | Odpowiada poprzedniemu znakowi, zero lub jeden raz. Na przykład „a?ve?” odpowiada „ve” w słowie „lever”. |
. | Odpowiada dowolnemu pojedynczemu znakowi, z wyjątkiem znaku nowej linii. |
(wzór) | Wyszukuje ciąg modèle i zapamiętuje dopasowanie. Odpowiedni podciąg można pobrać z kolekcji match.groups(). Aby znaleźć dopasowania zawierające znaki w nawiasach ( ), należy użyć znaków „\(" lub „\)”. |
x|y | Odpowiada albo x, albo y. Na przykład „z|foot" correspond à "z" ou à "foot". "(z|f)oo” odpowiada „zoo” lub „foo”. |
{n} | n to nieujemna liczba całkowita. Odpowiada dokładnie n razy znak. Na przykład „o{2}” nie odpowiada „o” w „Bob”, ale dwóm pierwszym „o” w „fooooot”. |
{n,} | n jest liczbą całkowitą nieujemną. Odpowiada co najmniej n-krotności danego znaku. Na przykład „o{2,}” nie odpowiada literze „o” w słowie „Bob”, ale wszystkim literom „o” w słowie „fooooot”. „o{1,}” jest równoważne „o+”, a „o{0,}” jest równoważne „o*”. |
{n,m} | m i n to liczby całkowite nieujemne. Odpowiada co najmniej n i co najwyżej m wystąpieniom znaku. Na przykład „o{1,3}” odpowiada trzem pierwszym „o” w słowie „foooooot”, a „o{0,1}” odpowiada „o?”. |
[xyz] | Zbiór znaków. Odpowiada jednemu z podanych znaków. Na przykład „[abc]” odpowiada znakowi „a” w słowie „plat”. |
[^xyz] | Zbiór znaków ujemnych. Odpowiada każdemu znakowi, który nie został wymieniony. Na przykład „[^abc]” odpowiada literze „p” w słowie „plat”. |
[a-z] | Zakres znaków. Odpowiada dowolnemu znakowi z podanego zakresu. Na przykład „[a-z]” odpowiada dowolnemu małej literze alfabetu od „a” do „z”. |
[^m-z] | Zakres znaków ujemny. Odpowiada dowolnemu znakowi, który nie występuje w podanej serii. Na przykład „[^m-z]” odpowiada dowolnemu znakowi, który nie występuje między „m” a „z”. |
\b | Odpowiada granicy wyznaczającej słowo, czyli pozycji między słowem a spacją. Na przykład „er\b” odpowiada „er” w słowie „lever”, ale nie odpowiada „er” w słowie „verbe”. |
\B | Odpowiada granicy nieoznaczającej słowa. „en*t\B” odpowiada „ent” w słowie „bien entendu”. |
\d | Odpowiada znakowi reprezentującemu cyfrę. Odpowiada [0-9]. |
\D | Odpowiada znakowi, który nie jest cyfrą. Odpowiada ciągowi [^0-9]. |
\f | Odpowiada znakowi końca strony. |
\n | Odpowiada znakowi nowego wiersza. |
\r | Odpowiada znakowi powrotu karetki. |
\s | Odpowiada dowolnemu znakowi spacji, w tym spacji, tabulacji, znakowi końca strony itp. Odpowiada ciągowi znaków „[ \f\n\r\t\v]”. |
\S | Odpowiada dowolnemu znakowi spacji niebędącemu znakiem białej przestrzeni. Odpowiada „[^ \f\n\r\t\v]”. |
\t | Odpowiada znakowi tabulacji. |
\v | Odpowiada znakowi pionowego tabulacji. |
\w | Odpowiada dowolnemu znakowi reprezentującemu słowo, w tym znakowi podkreślenia. Odpowiada ciągowi znaków „[A-Za-z0-9_]”. |
\W | Odpowiada dowolnemu znakowi, który nie stanowi słowa. Odpowiada ciągowi „[^A-Za-z0-9_]”. |
\num | Odpowiada num, gdzie num jest dodatnią liczbą całkowitą. Odnosi się do zapisanych przyporządkowań. Na przykład „(.)\1” odpowiada dwóm identycznym, następującym po sobie znakom. |
\n | Odpowiada n, gdzie n jest ośmiokrotną wartością escape. Ośmiokrotne wartości escape muszą składać się z 1, 2 lub 3 cyfr. Na przykład zarówno „\11”, jak i „\011” odpowiadają znakowi tabulacji. „\0011” jest równoważne „\001” i „1”. Oktalowe wartości escape nie mogą przekraczać 256. W przeciwnym razie w wyrażeniu brane pod uwagę będą tylko dwie pierwsze cyfry. Umożliwia używanie kodów ASCII w wyrażeniach regularnych. |
\xn | Odpowiada n, gdzie n jest szesnastkową wartością escape. Wartości ucieczkowe w systemie szesnastkowym muszą obowiązkowo składać się z dwóch cyfr. Na przykład „\x41” odpowiada literze „A”. „\x041” jest równoważne „\x04” i „1”. Umożliwia stosowanie kodów ASCII w wyrażeniach regularnych. |
Element w szablonie może występować w jednej lub wielu instancjach. Rozważmy kilka przykładów dotyczących symbolu \d, który reprezentuje jedną cyfrę:
szablon | znaczenie |
\d | cyfra |
\d? | 0 lub 1 cyfra |
\d* | 0 lub więcej cyfr |
\d+ | 1 lub więcej cyfr |
\d{2} | 2 cyfry |
\d{3,} | co najmniej 3 cyfry |
\d{5,7} | od 5 do 7 cyfr |
Wyobraźmy sobie teraz wzorzec, który może opisać oczekiwany format ciągu znaków:
poszukiwany ciąg znaków | model |
data w formacie dd/mm/rr | \d{2}/\d{2}/\d{2} |
godzina w formacie hh:mm:ss | \d{2}:\d{2}:\d{2} |
liczba całkowita bez znaku | \d+ |
sekwencja spacji, która może być pusta | \s* |
liczba całkowita bez znaku, przed którą lub po której mogą występować spacje | \s*\d+\s* |
liczba całkowita, która może być ze znakiem i może być poprzedzona lub następować po spacjach | \s*[+|-]?\s*\d+\s* |
liczba rzeczywista bez znaku, przed którą lub po której mogą występować spacje | \s*\d+(.\d*)?\s* |
liczba rzeczywista, która może być ze znakiem i może być poprzedzona lub następowana przez spacje | \s*[+-]?\s*\d+(.\d*)?\s* |
ciąg znaków zawierający słowo „juste” | \bjuste\b |
Można określić, w którym miejscu ciągu ma być wyszukiwany wzorzec:
wzór | znaczenie |
^wzorzec | wzorzec rozpoczyna ciąg |
wzór$ | szablon kończy ciąg |
^wzorzec$ | szablon rozpoczyna i kończy ciąg |
wzorzec | wzorzec jest wyszukiwany w całym ciągu, zaczynając od jego początku. |
wyszukiwany ciąg | wzorzec |
ciąg kończący się wykrzyknikiem | !$ |
ciąg kończący się kropką | \.$ |
ciąg znaków rozpoczynający się sekwencją // | ^// |
ciąg zawierający tylko jedno słowo, po którym mogą następować lub przed którym mogą występować spacje | ^\s*\w+\s*$ |
ciąg zawierający dwa słowa, po których mogą następować lub przed którymi mogą występować spacje | ^\s*\w+\s*\w+\s*$ |
ciąg zawierający słowo „secret” | \bsecret\b |
Podzbiory wzorca można „wyodrębnić”. Dzięki temu nie tylko można sprawdzić, czy ciąg znaków odpowiada konkretnemu wzorcowi, ale także wyodrębnić z tego ciągu elementy odpowiadające podzbiorom wzorca, które zostały ujęte w nawiasy. Jeśli więc analizujemy ciąg zawierający datę dd/mm/rr i chcemy dodatkowo wyodrębnić elementy dd, mm, rr z tej daty, użyjemy wzorca (\d\d)/(\d\d)/(\d\d).
Wyniki skryptu
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/bases/bases_11.py
Résultats(xyz1234abcd,^.*?(\d+).*?$)
('1234',)
Résultats(12 34,^.*?(\d+).*?$)
('12',)
Résultats(abcd,^.*?(\d+).*?$)
La chaîne [abcd] ne correspond pas au modèle [^.*?(\d+).*?$]
Résultats(xyz1234abcd,^(.*?)(\d+)(.*?)$)
('xyz', '1234', 'abcd')
Résultats(12 34,^(.*?)(\d+)(.*?)$)
('', '12', ' 34')
Résultats(abcd,^(.*?)(\d+)(.*?)$)
La chaîne [abcd] ne correspond pas au modèle [^(.*?)(\d+)(.*?)$]
Résultats(10/05/97,^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$)
('10', '05', '97')
Résultats( 04/04/01 ,^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$)
('04', '04', '01')
Résultats(5/1/01,^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$)
La chaîne [5/1/01] ne correspond pas au modèle [^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$]
Résultats(187.8,^\s*([+-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*$)
('', '187.8')
Résultats(-0.6,^\s*([+-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*$)
('-', '0.6')
Résultats(4,^\s*([+-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*$)
('', '4')
Résultats(.6,^\s*([+-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*$)
('', '.6')
Résultats(4.,^\s*([+-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*$)
('', '4.')
Résultats( + 4,^\s*([+-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*$)
('+', '4')
Process finished with exit code 0