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.
Pobierz Pythona z https://python.org. Na Windows podczas instalacji koniecznie zaznacz opcję „Add Python to PATH”.
Sprawdzenie instalacji:
python --version
REPL (interaktywna konsola) — szybkie testowanie pojedynczych wyrażeń:
python
>>> 2 + 2
4
>>> exit()
Skrypt — plik .py uruchamiany w całości:
python hello.py
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.
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")
| 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] |
zmianalana, uporządkowana kolekcja |
tuple |
(1, 2, 3) |
niezmianalana, 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
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.2daje0.30000000000000004. Do porównań użyjabs(a - b) < 1e-9.
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.
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")
truthy).None, 0, "", [], {}) są falsy.status = "aktywny" if is_active else "wyłączony"
for — iteracja po sekwencjifor 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 warunkiemn = 1
while n < 16:
n *= 2
print(n) # 16
break i continuefor 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
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
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
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ść)
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ć)
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.
# 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.
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 tymKeyboardInterrupt, gdy user wciska Ctrl+C.
# 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ąć.
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)
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}"
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
| 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] |
.py. Import: import math, from datetime import date.__init__.py).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).
x = a + b (nie x=a+b)Narzędzia: black, ruff — automatyczny formatter i linter.
pip install black ruff
black .
ruff check .
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).
# 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.
| 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 |
with przy plikach i zasobach.except: w całości.