Podstawy Pythona

Materiały dla studentów informatyki

Python to język wysokiego poziomu o automatycznym zarządzaniu pamięcią. Jego składnia jest czytelna i bliska pseudokodu — celowo: w Pythonie mniej czasu spędzasz na walce ze składnią, a więcej na zrozumieniu algorytmów i struktur danych. Ten sam język znajdziesz później w skryptach DevOps, automatyzacji, AI/ML i analizie danych.


Spis treści

  1. Środowisko pracy
  2. Zmienne i typy danych
  3. Łańcuchy znaków i f-strings
  4. Instrukcje warunkowe
  5. Pętle
  6. Kolekcje: listy, krotki, słowniki, zbiory
  7. List comprehensions
  8. Funkcje
  9. Wyjątki
  10. Praca z plikami
  11. Programowanie obiektowe (OOP)
  12. Moduły i pakiety
  13. Styl, testy i debugowanie
  14. Szybka ściągawka

1. Środowisko pracy

Instalacja

Pobierz Pythona z https://python.org. Na Windows podczas instalacji koniecznie zaznacz opcję „Add Python to PATH”.

Sprawdzenie instalacji:

python --version

Dwa tryby pracy

REPL (interaktywna konsola) — szybkie testowanie pojedynczych wyrażeń:

python
>>> 2 + 2
4
>>> exit()

Skrypt — plik .py uruchamiany w całości:

python hello.py

Wirtualne środowisko (venv)

Każdy projekt ma własne środowisko z własnymi pakietami. Chroń ten nawyk od pierwszego dnia:

python -m venv .venv          # utworzenie środowiska
.venv\Scripts\activate       # aktywacja (Windows)
source .venv/bin/activate    # aktywacja (Linux/macOS)
pip install requests         # instalacja pakietu w środowisko
deactivate                   # wyjście

pip to menedżer pakietów — instaluje gotowe, sprawdzone biblioteki (np. requests, numpy, pandas) zamiast pisać wszystko od zera.


2. Zmienne i typy danych

Zmienne

Zmienna to nazwa powiązana z wartością. Python ma typowanie dynamiczne — nie deklarujesz typu:

imię = "Anna"          # str
wiek = 21             # int
wzrost = 172.5        # float
jest_studentem = True  # bool

# Wymuszenie zmiany typu (rzutowanie)
wiek_z_łańcucha = int("25")

Podstawowe typy

Typ Przykład Opis
int 42, -7 liczba całkowita, bez górnego limitu
float 3.14 liczba zmiennoprzecinkowa (IEEE 754)
bool True, False wartość logiczna (podtyp int: True == 1)
str "tekst" niezmienialny łańcuch znaków
None None brak wartości
list [1, 2, 3] zmiana­lana, uporządkowana kolekcja
tuple (1, 2, 3) nie­zmiana­lana, uporządkowana kolekcja
dict {"a": 1} mapa klucz → wartość
set {1, 2, 3} nieuporządkowany zbiór unikalnych wartości

Sprawdzanie typu:

type(wzrost)   # <class 'float'>
isinstance(wiek, int)  # True — preferowany sposób testowania typu

Operatory

5 + 2      # 7   dodawanie
5 - 2      # 3   odejmowanie
5 * 2      # 10  mnożenie
5 / 2      # 2.5 dzielenie (zawsze float)
5 // 2     # 2   dzielenie całkowite
5 ** 2     # 25  potęgowanie
5 % 2      # 1   modulo (reszta z dzielenia)

# Porównania
5 == 5   # True
5 != 3   # True
5 > 3    # True
5 >= 5   # True

# Logiczne
True and False   # False  — oba muszą być True
True or False    # True   — wystarczy jedno
not True         # False  — odwrócenie

# WAŻNE: == porównuje, = przypisuje. Najczęstszy błąd początkujący.

Uwaga o float: arytmetyka zmiennoprzecinkowa jest przybliżona: 0.1 + 0.2 daje 0.30000000000000004. Do porównań użyj abs(a - b) < 1e-9.


3. Łańcuchy znaków i f-strings

s = "Python"
s[0]       # 'P'  — indeksowanie, indeksy od 0
s[-1]      # 'n'  — ostatni znak
s[1:4]     # 'yth' — zakres (slice): od włącznie, do exclusive
s.upper()  # 'PYTHON'
s.lower()  # 'python'
s.replace("Py", "Ry")  # 'Rython'
len(s)     # 6
"a" in s   # False;  "on" in s  # True
s.strip()  # usuwa białe znaki z obu końców
s.split(" ")  # dzieli na listę wg separatora

f-strings — standardowy sposób budowania łańcuchów (Python 3.6+):

imię = "Anna"
rok = 1
print(f"Student {imię}, rok {rok}")
print(f"2 + 2 = {2 + 2}")          # wyrażenia wewnątrz {}
print(f"{'x' * 10}")               # nawiasy dla wyrażeń z wewnętrznymi cudzysłowami

Ścinki vs podwójne cudzysłowy: używaj jednego spójnie, ale jeśli łańcuch zawiera apostrofy, zamień: "nie miałem" lub f-string z podwójnymi na zewnątrz.


4. Instrukcje warunkowe

Python używa wcięć zamiast klamres — wcięcia definiują bloki kodu.

wiek = 20

if wiek >= 18:
    print("Pełnoletni")
elif wiek >= 16:
    print("Niemal")
else:
    print("Niepełnoletni")

# Warunek złożony
godzina = 14
if 8 <= godzina <= 17 and not w_sobotę:
    print("Praca biurowa")
  • Warunek musi być wyrażeniem zwracającym wartość logiczną (wartość „prawdziwa" / truthy).
  • Puste wartości (None, 0, "", [], {}) są falsy.
  • „Ternaryjny" operator:
status = "aktywny" if is_active else "wyłączony"

5. Pętle

for — iteracja po sekwencji

for i in range(5):          # 0, 1, 2, 3, 4
    print(i)

for i in range(10, 2, -2):  # 10, 8, 6, 4, 2 (start, stop, krok)
    print(i)

for znak in "abc":
    print(znak)

while — pętla z warunkiem

n = 1
while n < 16:
    n *= 2
print(n)  # 16

break i continue

for i in range(100):
    if i == 5:
        break        # opuszcza pętlę całkowicie
    if i % 2 == 0:
        continue     # pomija tę iterację, idzie do następnej
    print(i)         # 1, 3

else przy pętli (specyficznym dla Pythona)

for x in lista:
    if warunek(x):
        break
else:
    print("Nie znaleziono")  # tylko gdy break NIE nastąpił

Wskazówka: większość zadań iteracyjnych da się zapisać cleaner jako list comprehension (dział 7) albo wezwanie wbudowane: sum(), max(), min(), any(), all().

liczby = [3, 1, 4, 1, 5]
sum(liczby)   # 14
max(liczby)   # 5
all(x > 0 for x in liczby)  # True

6. Kolekcje

Listy

tab = [3, 1, 4, 1, 5]
tab.append(9)            # dodaje na końcu
tab.insert(0, 99)        # wstawi na początku
tab.remove(1)            # usuwa pierwsze wystąpienie wartości
x = tab.pop()            # zdejmuje z końca i zwraca
x = tab.pop(2)           # zdejmuje w danym indeksie
tab.sort()               # sortuje in-place (rosnąco)
tab.reverse()            # odwraca
tab.index(4)             # indeks pierwszego 4
tab.count(1)             # ile razy 1
s = tab.copy()           # płytka kopia — ważne: sort() zmienia oryginał

# Sortowanie z kluczem
slowa = ["bbb", "a", "cccc"]
sorted(slowa, key=len)   # ['a', 'bbb', 'cccc'] — oryginał nietknięty

Krotki (tuple)

p = (3, 4)
p[0]              # 3 — odczyt tak jak lista
# p[0] = 5        #TypeError — krotki niezmienialne
x, y = p          # rozpakowanie
a, b = b, a       # zamiana zmiennych bez tymczasowej

# Krotka jednoelementowa: (5,) — bez nawiasów to po prostu wyrażenie

Słowniki (dict)

uzytkownik = {"imię": "Anna", "wiek": 21, "aktywny": True}
uzytkownik["imię"]            # 'Anna'
uzytkownik["mail"] = "a@x.pl" # dodanie
uzytkownik["mail"]            # 'a@x.pl'
uzytkownik.get("login")       # None — bezpieczne: nie rzuca KeyError
uzytkownik.get("login", "anon")  # 'anon' — wartość domyślna
uzytkownik["imię"] = "Ania"   # zamiana wartości
"mail" in uzytkownik          # True — sprawdzenie KLUCZY
del uzytkownik["wiek"]        # usunięcie pary

# Iteracja
for klucz in uzytkownik:
    print(klucz, uzytkownik[klucz])

for imie, wiek in [("a", 1), ("b", 2)]:
    print(imie, wiek)         # iteracja po krotkach w liście

# Podsumowanie
uzytkownik.keys()   # wszystkie klucze
uzytkownik.values() # wszystkie wartości
uzytkownik.items()  # pary (klucz, wartość)

Zbiory (set)

a = {1, 2, 3}
b = {3, 4, 5}
a | b   # {1, 2, 3, 4, 5} — suma zbiorów
a & b   # {3} — przecięcie
a - b   # {1, 2} — różnica
a ^ b   # {1, 2, 4, 5} — różnica symetryczna

# Praktyczne zastosowanie: usunięcie duplikatów
lista = [1, 2, 2, 3, 3, 3]
unikalne = list(set(lista))  # [1, 2, 3] (kolejność może się zmienić)

7. List comprehensions

Kompaktowy sposób budowania list z iteracji. Wiele pętli for zastępuje się jednym wierszem.

# Kwadraty liczb 0..9
kwadraty = [x * x for x in range(10)]

# Z filtrem
parzyste = [x for x in range(10) if x % 2 == 0]

# Zamiana elementów
znaki = [c.upper() for c in "abc"]

# Wersja złożona: zagnieżdżona pętla
pary = [(x, y) for x in range(3) for y in range(3)]
# [(0,0), (0,1), (0,2), (1,0), ...]

# Rozszerzenia: dict- i set-comprehension
kwadratowcy = {x: x * x for x in range(5)}
{c for c in "abcabc"}  # {'a', 'b', 'c'}

Zasada: comprehension czyta się jako „wypisz X dla każdego elemencie Y, gdzie [filtr]". Jeśli wyrażenie jest skomplikowane — wróć do zwykłej pętli. Przeczytność > oszczędność wierszy.


8. Funkcje

# Prosta funkcja
def powitanie(imie):
    """Zwraca przywitanie o podanym imieniu."""
    return f"Cześć, {imię}!"

print(powitanie("Anna"))  # Cześć, Anna!
# Parametry domyślne
def potega(a, b=2):
    return a ** b

potega(3)     # 9
potega(3, 3)  # 27
# return vs print
def suma(a, b):       # zwraca wartość — daje się użyć w wyrażeniach
    return a + b

def wypisz_sumę(a, b):
    print(a + b)      # wyświetla i zwraca None

suma(2, 3) ** 2       # 25
wypisz_sumę(2, 3) ** 2  #TypeError: NoneType nie ma potęgi **
# *args i **kwargs — zmienne liczby argumentów
def losowy(*args, **kwargs):
    print("pozycyjne:", args)     # krotka
    print("slownikowe:", kwargs)  # słownik

losowy(1, 2, x=10, y=20)
# pozycyjne: (1, 2)
# slownikowe: {'x': 10, 'y': 20}
# Zakres zmiennych (scope)
x = 10            # globalna
def f():
    x = 5         # lokalna — cieniuje globalną
    print(x)      # 5
f()
print(x)          # 10 — zmiana lokalnej nie dotyka globalnej

# global / nonlocal
licznik = 0
def inkrement():
    global licznik
    licznik += 1
# Funkcje pierwszoklasowe — można je przechowywać, przekazywać, zwracać
operacje = {
    "dodaj": lambda a, b: a + b,
    "odejmij": lambda a, b: a - b,
}
operacje["dodaj"](3, 4)  # 7

# Wyższe rzędu (funkcje zwracające funkcje)
def powielacz(mnoznik):
    def powiel(x):
        return x * mnoznik
    return powiel

podwojenie = powielacz(2)
podwojenie(21)  # 42

Dobra praktyka: jeden verb, jedna odpowiedzialność, nazwy czasownikowe (sprawdz, pobierz, znormalizuj). Dokumentuj docstringiem — w Pythonie standardem jest docstring w stylu: Czasownik-imienny + opis.


9. Wyjątki

Wyjątek to zdarzenie specjalne, które przerywa normalny przebieg programu i przechodzi do najbliższego blokującego except.

# Wyjątki wzbudzone „naturalnie" przez interpreter
1 / 0                     # ZeroDivisionError
int("abc")                # ValueError
lista = [1, 2]
lista[5]                  # IndexError
d = {"a": 1}
d["b"]                    # KeyError
# Obsługa — try/except
try:
    x = int(input("Podaj liczbę: "))
except ValueError:
    print("To nie była liczba")
else:
    print("Wynik:", x * 2)          # tylko gdy NIE było wyjątku
finally:
    print("To zawsze się wykona")   # np. zwalnianie zasobów
# Rzucaj własne wyjątki
def podziel(a, b):
    if b == 0:
        raise ValueError("Mianownik nie może być zerem")
    return a / b
# Wiele klauzul
try:
    x = int("42")
except (ValueError, TypeError) as e:
    print(f"Błąd: {e}")

Zasada: łap tylko te wyjątki, które potrafisz obsłużyć. Puste except: (bez typu) chwyta WSZYSTKO — w tym KeyboardInterrupt, gdy user wciska Ctrl+C.


10. Praca z plikami

# tryb "w" zdejstuje, "a" dajstuje, "r" tylko czyta (domyślny)
# "with" gwarantuje zamknięcie pliku nawet przy wyjątku
with open("dane.txt", "w", encoding="utf-8") as f:
    f.write("Dzień, świecie\n")
    for i in range(5):
        f.write(f"Wiersz {i}\n")

with open("dane.txt", "r", encoding="utf-8") as f:
    calosc = f.read()             # cały plik jako jedna stringa
    # lUB
    wiersze = f.readlines()       # lista stringów

# Elegantszy wariant: iteruj wiersz po wierszu
with open("dane.txt", "r", encoding="utf-8") as f:
    for linia in f:
        print(linia.strip())      # strip usuwa \n
# Duże pliki: czytaj chunkami, nie całym plikiem naraz
with open("wielki_plik.log", "r") as f:
    for linia in f:   # lazowo, wiersz po wierszu
        if błąd in linia:
            print(linia)

encoding="utf-8" podawaj zawsze — inaczej polskie znaki mogą zniknąć.


11. Programowanie obiektowe

OOP to modelowanie: obiekt to „rzecz" z stanem (atributy) i zachowaniem (metody).

class Kot:
    """Przykład klasy z atrybutem klasy i atrybutem instancji."""

    gatunek = "Felis catus"            # atrybut KLASY — wspólny dla wszystkich instancji

    def __init__(self, imie, wiek=1):
        self.imie = imie              # atrybut INSTANCJI — każda z osobna
        self.wiek = wiek
        self.kocie = 0

    def meow(self):                   # metoda
        self.kocie += 1
        # "Miau!"
        return f"{self.imie} miauczy ({self.kocie}. razy)"

    def __str__(self):                # repr dla print()
        return f"Kot({self.imie}, {self.wiek} lat)"

micius = Kot("Micius", 3)
zuzia  = Kot("Zuzia")
micius.meow()  # Micius miauczy (1. razy)
str(zuzia)     # Kot(Zuzia, 1 lat)

Dziedziczenie

class MaineCoon(Kot):
    def __init__(self, imie, kolor="rudy"):
        super().__init__(imie)          # wywołaj konstruktor rodzica
        self.kolor = kolor

    def __str__(self):
        base = super().__str__()
        return f"{base}, kolor={self.kolor}"

Encapsulacja

Konwencja Pythona: atrybuty z _ przedrostkiem są „prywatne" (konwencja, nie mechanizm).

class BankAccount:
    def __init__(self, saldo=0):
        self._saldo = saldo       # konwencja: „nie ruszaj bezpośrednio"

    @property
    def saldo(self):              # dostep jak do atrybutu, ale przez metodę
        return self._saldo

    def wpłaca(self, kwota):
        if kwota <= 0:
            raise ValueError("Kwota musi być dodatnia")
        self._saldo += kwota

Magia metod (dunder)

Metoda Wywoływana gdy…
__str__ print / str()
__repr__ repr() — „bezpośredni" opis
__len__ len(obiekt)
__eq__ a == b
__lt__ a < b (porzdek, sortowanie)
__iter__ iter(obiekt) — pętla for
__getitem__ obiekt[indeks]

12. Moduły i pakiety

  • Moduł = plik .py. Import: import math, from datetime import date.
  • Pakiet = katalog z modułami (z plikiem __init__.py).
  • Instalacja zewnętrznych pakietów: pip install <nazwa-w-zwiazaniu> (np. pip install requests).
import math          # importuje cały modul — dziala: math.sqrt(16)
from random import randint  # konkretny symbol do przestrzeni nazw

# Własne moduły: plik utils.py w tym samym katalogu
# from utils import funkcja_...

Standard: importy na górze pliku, zgrupowane (standardowe → trzecie strony → własne).


13. Styl, testy i debugowanie

PEP 8 — oficjalny styl Pythona

  • snake_case dla zmiennych i funkcji, CamelCase dla klas
  • 4 spacje, NIE taby
  • spacje wokół operatorów: x = a + b (nie x=a+b)
  • 73 znaki na wiersz (maks. 79)
  • Puste wiersze: 2 przed funkcjami, 1 w module

Narzędzia: black, ruff — automatyczny formatter i linter.

pip install black ruff
black .
ruff check .

Testy

Python ma wbudowany framework unittest. Prosty test:

import unittest
from kody import podziel

class TestPodziel(unittest.TestCase):
    def test_normal(self):
        self.assertEqual(podziel(10, 2), 5)

    def test_zero_division(self):
        with self.assertRaises(ValueError):
            podziel(1, 0)

if __name__ == "__main__":
    unittest.main()

Popularne alternatywne: pytest (czystszy składnia).

Debugowanie

# Wbudowany debugger
import pdb; pdb.set_trace()   # zatrzymuje się na tym wierszu

# Nowoczesny: breakpoint()
breakpoint()

W pdb: n = następny wiersz, s = wejdź w funkcję, c = kontynuuj, p x = wydrukuj x, q = wyjście.


14. Szybka ściągawka

Zadanie Kod
Lista 0..n-1 list(range(n))
Kwadraty z filtrem [x*x for x in range(10) if x%2==0]
Liczba wystąpięć "aa".count("a")
Rozwiązanie d.get("a", domyślna)
Usunięcie duplikatów list(set(lista))
Zamiana zmiennych a, b = b, a
F-string f"{x} = {y}"
Tryb zamykający plik with open(...) as f: ...
Rzut na własny wyjątek raise ValueError("...")
Funkcja zwracająca funkcję def f(m): def g(x): return x*m; return g

Dobre praktyki

  1. Wirtualne środowisko na każdym projekcie.
  2. with przy plikach i zasobach.
  3. Docstringi przy każdej funkcji publicznej.
  4. Łap konkretne wyjątki — nie except: w całości.
  5. Testuj zanim pójdziesz dalej.
  6. Black + Ruff — daj narzędziom załatwić styl.
  7. Pisz czytelny kod — kod czyta się więcej razy niż się pisze.

Gdzie dalej?