Podstawy Pythona przed pierwszym skryptem LLM

Michał Feliksik
3 min read
Podstawy Pythona przed pierwszym skryptem LLM

Wprowadzenie

Coraz więcej osób trafia do Pythona nie dlatego, że chce zostać programistą, tylko dlatego, że chce napisać prosty skrypt korzystający z LLM-a — na przykład z użyciem LlamaIndex. Zanim jednak dojdzie do samych modeli językowych, warto poukładać sobie kilka podstaw języka. Bez tego łatwo pogubić się w nawiasach, listach i błędach, które na pierwszy rzut oka wyglądają tajemniczo. W tym wpisie zostawiamy LLM-y na boku i skupiamy się wyłącznie na fundamentach: czym różnią się () od [], czym jest lista, czym krotka i jak wygląda praca z prostymi macierzami.

() kontra [] — pierwsza pułapka

W Pythonie nawiasy okrągłe i kwadratowe wyglądają podobnie, ale znaczą zupełnie co innego:

1
2
krotka = (1, 2, 3)   # nawiasy okrągłe -> krotka (tuple)
lista  = [1, 2, 3]   # nawiasy kwadratowe -> lista (list)

Różnica nie jest kosmetyczna:

  • lista [] jest mutowalna — możesz dodawać, usuwać i zmieniać elementy po utworzeniu,
  • krotka () jest niemutowalna — raz utworzonej krotki nie da się zmienić.
1
2
lista[0] = 99        # OK — lista się zmienia
krotka[0] = 99        # błąd: TypeError, krotki nie da się edytować

Nawiasy okrągłe pojawiają się też przy wywołaniu funkcji — print(x) — więc kontekst ma znaczenie: () po nazwie to wywołanie, () samodzielnie to krotka.

Kiedy lista, a kiedy krotka?

Prosta zasada: lista, gdy zbiór danych będzie się zmieniał (np. lista wyników, które dopiero zbierasz w pętli), krotka, gdy dane mają być stałe i niezmienne (np. współrzędne punktu, para klucz-wartość, wynik funkcji zwracającej kilka wartości naraz).

1
2
3
4
5
def podziel(a, b):
    return a // b, a % b   # zwraca krotkę (iloraz, reszta)

wynik = podziel(17, 5)      # (3, 2)
iloraz, reszta = wynik      # rozpakowanie krotki

To rozpakowywanie (iloraz, reszta = wynik) jest jedną z najczęściej używanych sztuczek Pythona — przyda się wszędzie tam, gdzie funkcja zwraca kilka rzeczy jednocześnie.

Listy list, czyli macierze

Python nie ma wbudowanego typu „macierz" — macierz to po prostu lista list, gdzie każda lista wewnętrzna to jeden wiersz:

1
2
3
4
5
6
7
8
macierz = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
]

macierz[0]       # [1, 2, 3]  -> pierwszy wiersz
macierz[0][2]    # 3          -> element z 1. wiersza, 3. kolumny

Podstawowe operacje, które warto znać:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Liczba wierszy i kolumn
liczba_wierszy = len(macierz)
liczba_kolumn = len(macierz[0])

# Przejście po wszystkich elementach
for wiersz in macierz:
    for element in wiersz:
        print(element)

# Suma wszystkich elementów
suma = sum(sum(wiersz) for wiersz in macierz)

# Transpozycja (zamiana wierszy z kolumnami)
transponowana = [list(kolumna) for kolumna in zip(*macierz)]

zip(*macierz) to popularny idiom: gwiazdka rozpakowuje listę wierszy jako osobne argumenty, a zip łączy je kolumna po kolumnie.

Listy składane (list comprehension)

Zamiast pisać pętlę, żeby przetworzyć każdy element listy, Python pozwala zapisać to w jednej linii:

1
2
3
4
liczby = [1, 2, 3, 4, 5]

kwadraty = [x ** 2 for x in liczby]              # [1, 4, 9, 16, 25]
parzyste = [x for x in liczby if x % 2 == 0]     # [2, 4]

Ta sama konstrukcja działa też na macierzach — dokładnie tak, jak w przykładzie z transpozycją wyżej. To jeden z najbardziej „pythonicznych" nawyków — im wcześniej wejdzie w krew, tym łatwiej później czyta się cudzy (i własny) kod.

Podsumowanie

Zanim sięgniesz po LlamaIndex czy jakąkolwiek bibliotekę do pracy z LLM-ami, te kilka podstaw wystarczy, żeby czuć się pewnie w kodzie: rozróżnienie () od [], świadomy wybór między listą a krotką, rozpakowywanie wartości oraz podstawowe operacje na listach list, czyli macierzach. To fundament, na którym w kolejnych wpisach zbudujemy pierwsze skrypty korzystające z modeli językowych.