Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

This project has been created as part of the 42 curriculum by Edson Baptista Finda.

python

The exercise-by-exercise journey — problem statements, my reasoning, and the concepts each one was designed to teach — is fully documented on Notion. This README is a lighter, GitHub-native companion to that: a concept-first map of what each module covers and which exercises apply it, so the code is legible on its own without needing the full write-up open.

Contents

Description

This repository holds my solutions to a Python Piscine: eleven modules (module00 through module10) that go from the language's basics to writing idiomatic, modern Python (3.10–3.14) across OOP, packaging, external libraries, and functional-style code. Each module wraps its exercises in a small theme — a garden, an alchemy grimoire, a monster-battling RPG, the Matrix — but the theming is a skin over a specific concept each exercise is built to force.

Every exercise lives in its own exN/ folder as a runnable, self-contained script. The sections below aren't a file listing — they walk through the concept each module targets and point to the exercises that apply it. For the deeper narrative behind why a given approach was chosen over another, that's what the Notion documentation is for.

module00 — Fundamentals

#module00--fundamentals

The warm-up: functions, input()/f-strings, type casting, conditionals, loops, and a first look at recursion — before any of it is wrapped in a class.

  • ex0ex3: A function per exercise (ft_hello_garden, ft_garden_name, ft_plot_area, ft_harvest_total), moving from a static print to reading and casting user input (int(input(...))) and formatting output with f-strings.
  • ex4/ex5: if/else branching on user input (ft_plant_age, ft_water_reminder).
  • ex6: The same problem solved two ways — ft_count_harvest_iterative with a for loop, ft_count_harvest_recursive with a nested helper function and default parameter values, comparing iteration against recursion for the same task.
  • ex7: ft_seed_inventory takes multiple typed parameters (with type hints) and dispatches on one of them, plus string methods like .capitalize().

module01 — OOP basics: classes, encapsulation & inheritance

#module01--oop-basics-classes-encapsulation--inheritance

The first real class, then everything that follows from it: private-by-convention attributes, classmethod/staticmethod, and single and multi-level inheritance.

  • ex1Plant: The core class. Attributes prefixed with _ (Python's encapsulation convention), constructor-level validation, getters/setters that reject bad state, a @classmethod factory (make_anonymous) that builds a Plant without normal arguments, a @staticmethod (is_older_than_1y) that doesn't need an instance at all, and a nested class (Stats) tracking how many times each method has been called.
  • ex2/ex3: Importing Plant across files and using it in a loop (ft_plant_growth) and in a batch of instances (ft_plant_factory).
  • ex4: ft_garden_security — proving the encapsulation from ex1 actually holds by trying (and failing) to force a Plant into an invalid state.
  • ex5Flower/Tree/Vegetable: Single inheritance from Plant, each subclass calling super().__init__() and overriding show() while adding its own behavior and state.
  • ex6Seed: A second level of inheritance (Seed → Flower → Plant), extending inherited state (self._stats.insert(...)) rather than replacing it.

module02 — Exception handling

#module02--exception-handling

try/except/finally used for real control flow, escalating from catching a single built-in exception to a small custom exception hierarchy.

  • ex0: A first try/except ValueError.
  • ex1TempError: A custom exception with __str__ overridden for a readable message, caught alongside a built-in one via a tuple: except (ValueError, TempError).
  • ex2: Deliberately triggering four different built-in exceptions (ValueError, ZeroDivisionError, FileNotFoundError, TypeError) from one dispatch function to practice catching each by type.
  • ex3GardenError / PlantError / WaterError: A small exception hierarchy — two specific exceptions inheriting from a common base — caught either individually or, just as validly, by catching the shared base class.
  • ex4: *args for a variadic function, and a finally block that guarantees cleanup ("closing watering system") runs whether or not an exception was raised.

module03 — CLI arguments & core data structures

#module03--cli-arguments--core-data-structures

Reading real input from sys.argv, then a tour of Python's core containers — tuples, sets, dicts — plus generators and comprehensions.

  • ex0/ex1: sys.argv, sys.exit, parsing CLI arguments into a list of numbers and computing aggregates (sum, min, max).
  • ex2: Tuple unpacking (x, y, z = ...), Python's structural pattern matching (match/case) to distinguish KeyboardInterrupt from EOFError, and the distinction between catching Exception vs the broader BaseException.
  • ex3: set operations — union (|), intersection (&), difference (-) — used to compare which achievements different players share or are missing.
  • ex4: dict construction from parsed input, dict.update(), and computing per-key percentages of a whole.
  • ex5: Generators — an infinite generator (while True: yield) for random events, and a second generator that mutates the list it's consuming from (events.pop(index)) as it's iterated with next().
  • ex6: List and dict comprehensions, including a comprehension with a filtering condition.

module04 — File I/O & streams

#module04--file-io--streams

Opening, reading, writing, and safely closing files — ending in the idiomatic way to do all of it.

  • ex0: open()/.read()/.close(), with OSError caught around the open() call.
  • ex1: A reusable ft_safe_open() helper, the walrus operator (if file := ft_safe_open(path):) to open and check in one expression, iterating a file line by line, and writing transformed content to a new file.
  • ex2: Doing the same job with sys.stdin.readline() / sys.stdout.write() / sys.stdout.flush() instead of input()/print(), to work directly with the stream objects.
  • ex3: The context manager form, with open(file_name, mode=action) as file:, which guarantees the file is closed even if an exception is raised inside the block — plus returning a tuple[bool, str] as a functional alternative to raising an exception for an expected failure case.

module05 — Abstraction: ABCs, protocols & dunder methods

#module05--abstraction-abcs-protocols--dunder-methods

Where Python's abstraction tools stop being theoretical: an abstract base class enforced at runtime, then a second way to achieve the same polymorphism without inheritance at all.

  • ex0DataProcessor(ABC): abc.ABC and @abstractmethod force NumericProcessor, TextProcessor, and LogProcessor to each implement validate()/ingest(), while sharing the base's output() behavior.
  • ex1DataStream: Dunder methods (__len__, __str__) that make custom objects work with len() and print() naturally, and compositionDataStream holds a set of DataProcessor instances and dispatches to whichever one validates a given item, all through the shared abstract interface.
  • ex2ExportPlugin(Protocol): typing.Protocol for structural typingCSVExportPlugin and JSONExportPlugin satisfy the plugin interface just by having a matching process_output() method, with no inheritance from ExportPlugin required at all. The clearest contrast in the repo between nominal typing (ex0's ABC) and structural typing (Protocol).

module06 — Modules & packages

#module06--modules--packages

Not language syntax so much as Python's import system: the difference between a module and a package, and exactly what __init__.py does and doesn't expose.

  • ft_alembic_0ft_alembic_5: import x vs from x import y, first against a single-file module (elements.py), then against a package (alchemy/) — and what changes once alchemy/__init__.py re-exports specific names (ft_alembic_4 deliberately tries to reach a function __init__.py doesn't re-export, to show it fails).
  • ft_distillation_0/1: Reaching a function directly through its submodule vs through the package's re-exported (and aliased — heal = healing_potion) name.
  • ft_kaboom_0/1: alchemy/grimoire/__init__.py only re-exports light_spellbook, not dark_spellbookft_kaboom_1 imports dark_spellbook directly to show that submodules not surfaced by __init__.py are still reachable by their full dotted path, they're just not part of the package's public surface.
  • ft_transmutation_02: A subpackage (alchemy/transmutation/) reached three different ways — direct submodule import, subpackage import, and through the top-level package — to make the dotted-path resolution rules concrete.

module07 — Design patterns in Python OOP

#module07--design-patterns-in-python-oop

Classic OOP design patterns, implemented Python-style — including the multiple inheritance Python allows that C++-style single-inheritance languages don't make as easy.

  • ex0Creature / CreatureFactory: An Abstract FactoryFlameFactory/AquaFactory each produce a matching base/evolved pair (FlamelingPyrodon, AquabubTorragon) without the caller needing to know the concrete classes.
  • ex1HealCapability / TransformCapability: Multiple inheritance as mixinsSproutling(Creature, HealCapability) combines two unrelated abstract bases, each contributing its own behavior, with both __init__s called explicitly where needed.
  • ex2BattleStrategy: The Strategy patternNormalStrategy/AggressiveStrategy/DefensiveStrategy each implement act() differently, using isinstance() checks against the ex1 mixins (and typing.cast) to validate that a given creature actually supports the strategy being applied to it.

module08 — Environments & dependency management

#module08--environments--dependency-management

Python outside the language itself: isolating a project's dependencies, managing them, and configuring an app without hardcoding secrets.

  • ex0construct.py: Detecting whether the script is running inside a virtual environment by comparing sys.prefix to sys.base_prefix, and locating the environment's package install path via site.getsitepackages().
  • ex1loading.py: importlib.import_module() for checking optional/third-party dependencies (numpy, pandas, matplotlib, requests) at runtime with a friendly error instead of a crash, alongside both dependency-management styles side by side — requirements.txt (pip) and pyproject.toml (Poetry).
  • ex2oracle.py: Loading configuration from a .env file via python-dotenv, validating that required variables are present and well-formed, and masking secrets in output depending on whether MATRIX_MODE is development or production.

module09 — Data validation with Pydantic

#module09--data-validation-with-pydantic

Runtime, type-safe data validation with Pydantic — moving field validation out of scattered if checks and into declarative model definitions.

  • ex0SpaceStation: A pydantic.BaseModel with per-field constraints (Field(ge=..., le=..., min_length=..., max_length=...)), and an invalid instantiation caught as a ValidationError with a structured, field-level error message.
  • ex1AlienContact: A StrEnum for a constrained set of valid values, automatic type coercion (passing '8.5' into a float field), and @model_validator(mode="after") for cross-field business rules a single Field constraint can't express (e.g. physical contact reports must be verified; strong signals require a received message), raised as a PydanticCustomError.
  • ex2SpaceMission / CrewMember: Nested Pydantic models — a SpaceMission holding a list[CrewMember], each validated independently — plus a model_validator enforcing rules across the whole nested structure (a mission needs at least one Commander/Captain, and long missions need enough experienced crew).

module10 — Functional programming

#module10--functional-programming

Python's functional side: lambdas, closures, functools, and decorators, each building on the last.

  • ex0: lambda as the key= argument to sorted/max/min, and with filter/map.
  • ex1: Higher-order functions — functions that take other functions as arguments and/or return new functions (spell_combiner, power_amplifier, conditional_caster), typed with Callable type aliases.
  • ex2: Closuresmage_counter, spell_accumulator, and memory_vault each return an inner function (or dict of them) that keeps its own private state alive between calls via the nonlocal keyword, with no class involved.
  • ex3: functools.reduce, functools.partial (pre-filling arguments), @functools.lru_cache (memoizing a recursive Fibonacci), and @functools.singledispatch (dispatching a function's behavior based on its argument's runtime type).
  • ex4: Decorators — a plain decorator (@spell_timer), a parameterized decorator factory (@power_validator(10), @retry_spell(3)), functools.wraps to preserve the wrapped function's __name__/metadata, and a decorator applied to a function defined inside a class method.

About

My solutions to the 42 school Python Piscine — eleven modules covering OOP, exceptions, file I/O, the import system, design patterns, environments & dependency management, Pydantic validation, and functional programming, in modern Python (3.10–3.14).

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages