scikit-learn Onboarding LabChapter II — BaseEstimator and the fit contract0/5Contents
Chapter II

BaseEstimator and the fit contract

Every scikit-learn estimator inherits from BaseEstimator, which supplies get_params/set_params (the introspection machinery that GridSearchCV, Pipeline, and clone() rely on), a pretty-printing __repr__/HTML display, and pickling/versioning hooks. The _fit_context decorator wraps nearly every estimator's fit method to validate constructor parameters against _parameter_constraints and to push global config (like skip_parameter_validation) into a context manager before the real fit body runs. Understanding this one file explains how disparate parts of the library — model selection, pipelines, and parameter validation — all plug into the same estimator contract.


        valid_params = self.get_params(deep=True)        nested_params = defaultdict(dict)  # grouped by prefix        for key, value in params.items():            key, delim, sub_key = key.partition("__")            if key not in valid_params:                local_valid_params = self._get_param_names()                raise ValueError(                    f"Invalid parameter {key!r} for estimator {self}. "                    f"Valid parameters are: {local_valid_params!r}."                )            if delim:                nested_params[key][sub_key] = value            else:                setattr(self, key, value)                valid_params[key] = value        for key, sub_params in nested_params.items():            valid_params[key].set_params(**sub_params)
sklearn/base.py · lines 421440
Figure I · set_params splits each key on the first '__' to decide whether to setattr directly or recurse into a nested component's own set_params. This is precisely what makes GridSearchCV(pipe, {'clf__C': [1, 10]})-style dotted parameter grids work: the top level looks up 'clf' in valid_params (built from get_params(deep=True), so nested names are already known) and forwards 'C' to that component.
checkpoint

Check your understanding

Answered in place — nothing is graded, everything is explained. 0 / 3 passed

Where does BaseEstimator.get_params() get the list of parameter names to report?

What does the @_fit_context decorator do before the wrapped fit() method's body actually runs?

In set_params(clf__C=10), how does BaseEstimator know to forward C=10 to the nested 'clf' component instead of setting an attribute literally named 'clf__C'?