Cours Python · Module 12: Projet final

Préparation à ta carrière

7 min de lecture
Dans cette leçon5

Félicitations ! Tu as terminé Python Safari. Tu as douze lieux derrière toi, mais un certificat seul n'a jamais fait embaucher personne. Un recruteur consacre quelques dizaines de secondes à ton CV, et un entretien technique comportera des questions qui vérifient si tu comprends ce que tu écris. Il est temps de transformer tes compétences en premier emploi. On va préparer un CV, un profil LinkedIn, des réponses aux questions typiques et une liste d'endroits où chercher des offres.

CV pour un développeur Python

Un bon CV de développeur est court et concret : coordonnées avec un lien vers GitHub, un résumé d'une phrase, des compétences regroupées par catégories et des projets avec leurs résultats. Voici un modèle :

1# John Smith
2Développeur Python | Spécialiste AI/ML
3
4john@example.com | linkedin.com/in/john | github.com/john
5
6## Résumé
7Développeur Python avec de l'expérience dans la création d'applications AI/ML.
8Spécialisation : systèmes RAG, FastAPI, Machine Learning.
9
10## Compétences
11
12**Langages :** Python, JavaScript, SQL
13**Frameworks :** FastAPI, Django, React
14**AI/ML :** LlamaIndex, LangChain, PyTorch, scikit-learn
15**Bases de données :** PostgreSQL, Qdrant, Redis
16**Outils :** Docker, Git, GitHub Actions, AWS
17
18## Projets
19
20### AI Document Assistant | [GitHub](link) | [Démo](link)
21- Système RAG pour rechercher dans les documents
22- Tech : FastAPI, LlamaIndex, Qdrant, OpenAI
23- Résultats : temps de réponse <2s, précision de 92%
24
25### ML Pipeline | [GitHub](link)
26- Pipeline ML de bout en bout avec MLflow
27- Tech : scikit-learn, XGBoost, MLflow, Docker
28- Résultats : amélioration de 15% de la précision
29
30## Formation
31
32**Python Safari** - CodeWorlds (2024)
33- Cours Python et IA en 12 modules
34- Projet Capstone : AI Document Assistant
35
36## Certifications
37- [Nom du certificat]

La section Projets compte plus que la section Formation, car elle montre ce que tu as construit. Les chiffres des lignes « Résultats » illustrent le format, ce ne sont pas des valeurs toutes faites : n'y mets que ce que tu as vraiment mesuré dans ton projet. Un recruteur peut t'interroger sur chaque chiffre en entretien. En début de carrière, garde ton CV sur une page et envoie-le en PDF pour que la mise en page ne se casse pas de l'autre côté.

Optimisation de LinkedIn

LinkedIn fonctionne comme un moteur de recherche, les recruteurs cherchent par mots-clés dans le titre et la section À propos. Le titre n'est pas seulement un intitulé de poste, c'est une liste de technologies :

1## Titre (Headline)
2Développeur Python | AI/ML | FastAPI | Je construis des applications intelligentes
3
4## À propos
5Développeur Python passionné, spécialisé dans les applications d'IA.
6
7Systèmes RAG et intégration de LLM
8FastAPI et Python asynchrone
9Pipelines de Machine Learning
10
11En cours de développement : AI Document Assistant - recherche sémantique dans les documents.
12
13Ouvert aux opportunités en développement AI/ML.
14
15## Sélection (Featured)
16- Lien vers ton meilleur projet
17- Un article/post sur une technologie
18- Un certificat/diplôme

La section Sélection (Featured) est l'endroit pour le lien vers ton meilleur projet. Un seul projet bien décrit avec une démo en dit plus qu'une liste de vingt technologies. Ajoute aussi un lien vers GitHub dans tes coordonnées, car c'est précisément là que le recruteur ira chercher les preuves de tes compétences.

Préparation à l'entretien

Un entretien technique pour un développeur Python couvre en général quatre domaines. Passons-les en revue un par un. Le premier, ce sont les fondamentaux du langage, et la question classique porte sur le GIL :

1# Questions techniques typiques
2
3# 1. Fondamentaux de Python
4def explain_gil():
5    """
6    GIL (Global Interpreter Lock) - un mécanisme de CPython
7    qui n'autorise qu'un seul thread à exécuter
8    du bytecode Python à un instant donné.
9
10    Solutions :
11    - multiprocessing pour les tâches CPU-bound
12    - asyncio pour les tâches I/O-bound
13    - interpréteurs alternatifs (PyPy)
14    """
15    pass

Dans le CPython standard, le GIL (Global Interpreter Lock) n'autorise qu'un seul thread à la fois à exécuter du bytecode Python. Les threads n'accélèrent donc pas les calculs sur le processeur. Il vaut la peine d'ajouter que depuis Python 3.13 il existe un build free-threaded séparé, sans GIL (PEP 703), officiellement pris en charge en 3.14 (PEP 779) mais toujours optionnel. Le deuxième domaine, c'est la programmation asynchrone :

1# 2. Python asynchrone
2async def explain_async():
3    """
4    async/await - le modèle de concurrence de Python.
5    - async def - définit une coroutine
6    - await - attend le résultat d'une opération async
7    - Idéal pour les opérations I/O-bound
8    """
9    pass

Le module asyncio fournit la prise en charge d'async/await. La règle à retenir : async/await pour les opérations I/O-bound (réseau, base de données, fichiers), multiprocessing pour le travail CPU-bound. Le troisième domaine, ce sont les design patterns, que tu connais depuis la leçon sur l'architecture :

1# 3. Design Patterns
2def explain_patterns():
3    """
4    Patterns les plus importants :
5    - Repository Pattern - abstraction de l'accès aux données
6    - Dependency Injection - couplage faible
7    - Factory Pattern - création d'objets
8    - Observer Pattern - réactivité
9    """
10    pass

En entretien, le nom du pattern ne suffit pas, montre un exemple tiré de ton propre projet, comme DocumentRepository. Le quatrième domaine, c'est le system design :

1# 4. System Design
2def design_rag_system():
3    """
4    Composants :
5    1. API Gateway - routage, auth
6    2. RAG Service - traitement des requêtes
7    3. Vector Database - stockage des embeddings
8    4. LLM Service - génération de texte
9    5. Cache - Redis pour les requêtes fréquentes
10    6. Monitoring - Prometheus + Grafana
11    """
12    pass

C'est exactement l'architecture de ton projet capstone. Explique pourquoi tu as choisi chaque composant, car c'est là-dessus qu'on va te questionner.

Il y aura aussi des questions sur les outils. Tu crées un environnement virtuel avec python -m venv .venv et tu l'actives sous Linux et macOS avec source .venv/bin/activate. Le fichier requirements.txt liste les dépendances avec leurs versions. Dans FastAPI, Pydantic valide les données et définit les modèles de requête et de réponse. Par défaut, pytest découvre les fichiers test_*.py et *_test.py.

Où chercher un emploi

Dernière étape : savoir où chasser les offres. Les sites d'emploi évoluent avec le temps (GitHub Jobs et Stack Overflow Jobs n'existent plus), alors considère cette liste comme un point de départ :

1## Développeur Python Junior/Mid
2
31. **LinkedIn Jobs** - la meilleure source
42. **NoFluffJobs** - marché IT polonais
53. **JustJoinIT** - startups et grandes entreprises
64. **Bulldogjob** - site polonais d'offres IT
75. **Wellfound** (anciennement AngelList Talent) - startups, offres internationales
8
9## Freelance
10
111. **Upwork** - projets à long terme
122. **Toptal** - premium, nécessite une vérification
133. **Fiverr** - projets plus petits
14
15## Open Source
16
171. Contribue aux projets que tu utilises
182. Construis ta réputation
193. Réseaute avec d'autres développeurs

L'open source est une voie souvent sous-estimée : une contribution à une bibliothèque que tu utilises est une preuve publique de tes compétences et un moyen de rencontrer des développeurs expérimentés.

Prochaines étapes

Le plan pour les semaines à venir est simple : termine le projet Capstone, publie-le sur GitHub, mets à jour ton CV et ton LinkedIn, postule à des offres et continue d'apprendre. Mon conseil : n'attends pas de te sentir « prêt ». Postule dès que tu as un projet solide, car les entretiens eux-mêmes sont le meilleur entraînement.

Souviens-toi : ce n'est pas la fin, c'est le début de ton aventure Python, et chaque future expédition commence par la carte que tu as tracée dans ce module.

Code de cette leçon : main.py
1# ===========================================
2# Safari Capstone : Couche de service principale
3# ===========================================
4# Implémente le service de logique métier principal qui
5# gère les opérations sur la faune et les analyses.
6
7from dataclasses import dataclass, field
8from datetime import datetime
9from typing import Optional
10import json
11
12# --- Modèles ---
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# --- Service principal ---
43class SafariService:
44    """Logique métier principale du système de gestion du safari."""
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        """Enregistre un nouvel animal dans le système."""
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        """Enregistre une nouvelle observation de faune sauvage."""
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        """Renvoie les statistiques de population groupées par espèce."""
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        # Convertir les ensembles en listes pour la compatibilité JSON
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        """Compte les observations pour un animal précis."""
95        return sum(1 for o in self.observations if o.animal_id == animal_id)
96
97    def generate_report(self) -> str:
98        """Génère un rapport de synthèse de toutes les données de la faune."""
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# --- Démo ---
115repo = AnimalRepository()
116service = SafariService(repo)
117
118# Enregistrer des animaux
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# Enregistrer des 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# Générer un rapport
130print(service.generate_report())
131print(f"\nObservations de Simba : {service.get_observation_count('LI-001')}")
132print(f"\nStats par espèce :")
133print(json.dumps(service.get_species_stats(), indent=2))
134
135# TODO : Ajoute une méthode pour trouver l'animal le plus observé
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 : Ajoute une fonctionnalité d'export des données
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

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Qu'est-ce que le GIL en Python ?

  2. 2. Que fournit asyncio en Python ?

Voici 2 des 5 questions de cette leçon. Réponds aux autres dans le jeu.

Tâches pratiques dans le jeu

  • Tri horizontal

    Range la commande pour créer un environnement virtuel Python :

  • Clique dans l'ordre

    Clique sur les éléments pour construire la commande d'activation de venv (Linux/Mac) :

  • Éditeur de code

    Écris une configuration GitHub Actions pour le CI d'un projet Python

  • Éditeur de code

    Crée la structure initiale du projet Capstone avec le module principal et la configuration

  • Éditeur de code

    Implémente le service d'IA principal avec une méthode de prédiction

  • Éditeur de code

    Crée une couche API REST avec FastAPI pour le projet Capstone

  • Éditeur de code

    Écris des tests pour le projet Capstone avec pytest

Articles utiles