Kurs Python · Moduł 12: Projekt końcowy

Przygotowanie do Kariery

5 min czytania
W tej lekcji5

Gratulacje! Ukończyłeś Python Safari. Masz za sobą dwanaście lokacji, ale sam certyfikat jeszcze nikogo nie zatrudnił. Rekruter ma kilkadziesiąt sekund na Twoje CV, a na rozmowie technicznej padną pytania, które sprawdzą, czy rozumiesz to, co piszesz. Teraz czas zamienić zdobyte umiejętności w pierwszą pracę. Przygotujemy CV, profil LinkedIn, odpowiedzi na typowe pytania i listę miejsc, gdzie warto szukać ofert.

CV dla Python Developera

Dobre CV programisty jest krótkie i konkretne: dane kontaktowe z linkiem do GitHuba, jednozdaniowe podsumowanie, umiejętności pogrupowane w kategorie i projekty z wynikami. Oto szablon:

1# Jan Kowalski
2Python Developer | AI/ML Specialist
3
4jan@example.com | linkedin.com/in/jan | github.com/jan
5
6## Summary
7Python developer z doświadczeniem w budowaniu aplikacji AI/ML.
8Specjalizacja: RAG systems, FastAPI, Machine Learning.
9
10## Skills
11
12**Languages:** Python, JavaScript, SQL
13**Frameworks:** FastAPI, Django, React
14**AI/ML:** LlamaIndex, LangChain, PyTorch, scikit-learn
15**Databases:** PostgreSQL, Qdrant, Redis
16**Tools:** Docker, Git, GitHub Actions, AWS
17
18## Projects
19
20### AI Document Assistant | [GitHub](link) | [Demo](link)
21- RAG system do przeszukiwania dokumentów
22- Tech: FastAPI, LlamaIndex, Qdrant, OpenAI
23- Wyniki: <2s response time, 92% accuracy
24
25### ML Pipeline | [GitHub](link)
26- End-to-end ML pipeline z MLflow
27- Tech: scikit-learn, XGBoost, MLflow, Docker
28- Wyniki: 15% improvement w accuracy
29
30## Education
31
32**Python Safari** - CodeWorlds (2024)
33- 12-modułowy kurs Python i AI
34- Capstone: AI Document Assistant
35
36## Certifications
37- [Nazwa certyfikatu]

Sekcja Projects jest ważniejsza niż Education, bo pokazuje, co zbudowałeś. Liczby w polach "Wyniki" to przykład formatu, nie gotowe wartości: wpisz tylko to, co naprawdę zmierzyłeś w swoim projekcie. Rekruter może o każdą liczbę zapytać na rozmowie. Na początku kariery trzymaj CV na jednej stronie i wysyłaj je jako PDF, żeby formatowanie nie rozjechało się po drugiej stronie.

LinkedIn Optimization

LinkedIn działa jak wyszukiwarka, rekruterzy szukają po słowach kluczowych w nagłówku i sekcji About. Nagłówek to nie tylko stanowisko, to lista technologii:

1## Headline
2Python Developer | AI/ML | FastAPI | Building intelligent applications
3
4## About
5Passionate Python developer specializing in AI applications.
6
7RAG Systems & LLM Integration
8FastAPI & Async Python
9Machine Learning Pipelines
10
11Currently building: AI Document Assistant - semantic search for documents.
12
13Open to opportunities in AI/ML development.
14
15## Featured
16- Link do najlepszego projektu
17- Artykuł/post o technologii
18- Certyfikat/dyplom

Sekcja Featured to miejsce na link do najlepszego projektu. Jeden dobrze opisany projekt z demo mówi więcej niż lista dwudziestu technologii. Dodaj też link do GitHuba w danych kontaktowych, bo właśnie tam rekruter pójdzie szukać dowodów Twoich umiejętności.

Przygotowanie do Interview

Rozmowa techniczna dla Python developera zwykle obejmuje cztery obszary. Przejdźmy przez nie po kolei. Pierwszy to fundamenty języka, a klasyczne pytanie dotyczy GIL:

1# Typowe pytania techniczne
2
3# 1. Python fundamentals
4def explain_gil():
5    """
6    GIL (Global Interpreter Lock) - mechanizm w CPython,
7    który pozwala tylko jednemu wątkowi wykonywać
8    bytecode Pythona w danym momencie.
9
10    Rozwiązania:
11    - multiprocessing dla CPU-bound
12    - asyncio dla I/O-bound
13    - alternatywne interpretery (PyPy)
14    """
15    pass

GIL (Global Interpreter Lock) w standardowym CPythonie pozwala tylko jednemu wątkowi naraz wykonywać bytecode Pythona. Wątki nie przyspieszą więc obliczeń na procesorze. Warto dodać, że od Pythona 3.13 istnieje osobny build free-threaded bez GIL (PEP 703), w 3.14 oficjalnie wspierany (PEP 779), ale wciąż opcjonalny. Drugi obszar to programowanie asynchroniczne:

1# 2. Async Python
2async def explain_async():
3    """
4    async/await - model współbieżności w Pythonie.
5    - async def - definiuje coroutine
6    - await - czeka na wynik async operacji
7    - Idealne dla I/O-bound operations
8    """
9    pass

Moduł asyncio daje obsługę async/await. Zasada do zapamiętania: async/await dla operacji I/O-bound (sieć, baza, pliki), multiprocessing dla CPU-bound. Trzeci obszar to wzorce projektowe, które znasz z lekcji o architekturze:

1# 3. Design Patterns
2def explain_patterns():
3    """
4    Najważniejsze wzorce:
5    - Repository Pattern - abstrakcja dostępu do danych
6    - Dependency Injection - luźne powiązania
7    - Factory Pattern - tworzenie obiektów
8    - Observer Pattern - reaktywność
9    """
10    pass

Na rozmowie nie wystarczy nazwa wzorca, pokaż przykład z własnego projektu, na przykład DocumentRepository. Czwarty obszar to projektowanie systemu:

1# 4. System Design
2def design_rag_system():
3    """
4    Komponenty:
5    1. API Gateway - routing, auth
6    2. RAG Service - query processing
7    3. Vector Database - embeddings storage
8    4. LLM Service - text generation
9    5. Cache - Redis for frequent queries
10    6. Monitoring - Prometheus + Grafana
11    """
12    pass

To dokładnie architektura Twojego capstone projektu. Opowiedz, dlaczego wybrałeś każdy komponent, bo o to będą dopytywać.

Padną też pytania o narzędzia. Wirtualne środowisko tworzysz poleceniem python -m venv .venv, a aktywujesz na Linuksie i macOS przez source .venv/bin/activate. Plik requirements.txt zawiera listę zależności z wersjami. Pydantic w FastAPI waliduje dane i definiuje modele żądań oraz odpowiedzi. pytest domyślnie odkrywa pliki test_*.py oraz *_test.py.

Gdzie szukać pracy

Ostatni krok to wiedzieć, gdzie polować na oferty. Serwisy zmieniają się z czasem (GitHub Jobs i Stack Overflow Jobs już nie istnieją), więc traktuj tę listę jako punkt startu:

1## Junior/Mid Python Developer
2
31. **LinkedIn Jobs** - najlepsze źródło
42. **NoFluffJobs** - polski rynek IT
53. **JustJoinIT** - startupy i korpo
64. **Bulldogjob** - polski portal z ofertami IT
75. **Wellfound** (dawniej AngelList Talent) - startupy, oferty międzynarodowe
8
9## Freelance
10
111. **Upwork** - projekty długoterminowe
122. **Toptal** - premium, wymaga weryfikacji
133. **Fiverr** - mniejsze projekty
14
15## Open Source
16
171. Contribute to projects you use
182. Build your reputation
193. Network with developers

Open source to często niedoceniana droga: kontrybucja do biblioteki, której używasz, to publiczny dowód umiejętności i kontakt z doświadczonymi programistami.

Następne kroki

Plan na najbliższe tygodnie jest prosty: ukończ Capstone Project, opublikuj go na GitHubie, zaktualizuj CV i LinkedIn, aplikuj na pozycje i kontynuuj naukę. Moja rada: nie czekaj, aż poczujesz się "gotowy". Aplikuj, gdy masz jeden porządny projekt, bo rozmowy same w sobie są najlepszym treningiem.

Pamiętaj: to nie koniec, to początek Twojej przygody z Pythonem, a każda kolejna ekspedycja zaczyna się od mapy, którą narysowałeś w tym module.

Kod do tej lekcji: main.py
1# ===========================================
2# Safari Capstone: Core Service Layer
3# ===========================================
4# Implement the core business logic service that
5# manages wildlife operations and analytics.
6
7from dataclasses import dataclass, field
8from datetime import datetime
9from typing import Optional
10import json
11
12# --- Models ---
13@dataclass
14class Animal:
15    animal_id: str
16    species: str
17    name: str
18    weight_kg: float
19    region: str
20
21@dataclass
22class Observation:
23    obs_id: str
24    animal_id: str
25    latitude: float
26    longitude: float
27    observer: str
28    timestamp: str = ""
29
30# --- Repository ---
31class AnimalRepository:
32    def __init__(self):
33        self._data = {}
34
35    def save(self, animal): self._data[animal.animal_id] = animal
36    def get(self, aid): return self._data.get(aid)
37    def get_all(self): return list(self._data.values())
38    def delete(self, aid): return self._data.pop(aid, None) is not None
39    def find_by_species(self, sp):
40        return [a for a in self._data.values() if a.species.lower() == sp.lower()]
41
42# --- Core Service ---
43class SafariService:
44    """Core business logic for the safari management system."""
45
46    def __init__(self, repo: AnimalRepository):
47        self.repo = repo
48        self.observations: list[Observation] = []
49        self._next_obs_id = 1
50
51    def register_animal(self, species, name, weight_kg, region) -> Animal:
52        """Register a new animal in the system."""
53        prefix = species[:2].upper()
54        count = len(self.repo.find_by_species(species)) + 1
55        animal_id = f"{prefix}-{count:03d}"
56        animal = Animal(animal_id, species, name, weight_kg, region)
57        self.repo.save(animal)
58        return animal
59
60    def record_observation(self, animal_id, lat, lon, observer) -> Optional[Observation]:
61        """Record a new wildlife observation."""
62        animal = self.repo.get(animal_id)
63        if not animal:
64            return None
65        obs = Observation(
66            obs_id=f"OBS-{self._next_obs_id:04d}",
67            animal_id=animal_id,
68            latitude=lat,
69            longitude=lon,
70            observer=observer,
71            timestamp=datetime.now().isoformat()
72        )
73        self.observations.append(obs)
74        self._next_obs_id += 1
75        return obs
76
77    def get_species_stats(self) -> dict:
78        """Get population statistics grouped by species."""
79        stats = {}
80        for animal in self.repo.get_all():
81            species = animal.species
82            if species not in stats:
83                stats[species] = {"count": 0, "total_weight": 0.0, "regions": set()}
84            stats[species]["count"] += 1
85            stats[species]["total_weight"] += animal.weight_kg
86            stats[species]["regions"].add(animal.region)
87        # Convert sets to lists for JSON compatibility
88        for sp in stats:
89            stats[sp]["avg_weight"] = round(stats[sp]["total_weight"] / stats[sp]["count"], 1)
90            stats[sp]["regions"] = list(stats[sp]["regions"])
91        return stats
92
93    def get_observation_count(self, animal_id: str) -> int:
94        """Count observations for a specific animal."""
95        return sum(1 for o in self.observations if o.animal_id == animal_id)
96
97    def generate_report(self) -> str:
98        """Generate a summary report of all wildlife data."""
99        stats = self.get_species_stats()
100        total_animals = self.repo.get_all()
101        lines = [
102            "=== Safari Wildlife Report ===",
103            f"Total animals tracked: {len(total_animals)}",
104            f"Total observations: {len(self.observations)}",
105            f"Species tracked: {len(stats)}",
106            ""
107        ]
108        for species, data in stats.items():
109            lines.append(f"{species}: {data['count']} animals, "
110                        f"avg {data['avg_weight']} kg, "
111                        f"regions: {', '.join(data['regions'])}")
112        return "\n".join(lines)
113
114# --- Demo ---
115repo = AnimalRepository()
116service = SafariService(repo)
117
118# Register animals
119service.register_animal("Lion", "Simba", 195.0, "Savanna")
120service.register_animal("Lion", "Nala", 130.0, "Savanna")
121service.register_animal("Elephant", "Tembo", 5200.0, "Forest")
122service.register_animal("Cheetah", "Duma", 52.0, "Grassland")
123
124# Record observations
125service.record_observation("LI-001", -2.33, 34.83, "Dr. Darwin")
126service.record_observation("LI-001", -2.34, 34.84, "Dr. Darwin")
127service.record_observation("EL-001", -2.41, 34.92, "Ranger Kate")
128
129# Generate report
130print(service.generate_report())
131print(f"\nSimba observations: {service.get_observation_count('LI-001')}")
132print(f"\nSpecies stats:")
133print(json.dumps(service.get_species_stats(), indent=2))
134
135# TODO: Add a method to find the most observed animal
136# def most_observed_animal(self) -> Optional[str]:
137#     counts = {}
138#     for obs in self.observations:
139#         counts[obs.animal_id] = counts.get(obs.animal_id, 0) + 1
140#     if not counts:
141#         return None
142#     return max(counts, key=counts.get)
143
144# TODO: Add data export functionality
145# def export_data(self, format="json") -> str:
146#     data = {
147#         "animals": [vars(a) for a in self.repo.get_all()],
148#         "observations": [vars(o) for o in self.observations],
149#         "stats": self.get_species_stats()
150#     }
151#     return json.dumps(data, indent=2, default=str)
152

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Co to jest GIL (Global Interpreter Lock) w Pythonie?

  2. 2. Kiedy używać async/await zamiast multiprocessing?

To 2 z 5 pytań do tej lekcji. Pozostałe rozwiążesz w grze.

Zadania praktyczne w grze

  • Układanie w poziomie

    Ułóż elementy:

  • Klikanie w kolejności

    Kliknij w kolejności:

  • Edytor kodu

    Stwórz .github/workflows/ci.yml z krokami: checkout, setup-python, install, test.

  • Edytor kodu

    Zainicjuj projekt Capstone

  • Edytor kodu

    Stwórz rdzeń aplikacji

  • Edytor kodu

    Zaimplementuj warstwę API

  • Edytor kodu

    Dodaj testy do projektu

Przydatne artykuły