%23%20%2F%2F%2F%20script%0A%23%20requires-python%20%3D%20%22%3E%3D3.11%22%0A%23%20dependencies%20%3D%20%5B%0A%23%20%20%20%20%20%22numpy%22%2C%0A%23%20%20%20%20%20%22plotly%22%2C%0A%23%20%20%20%20%20%22scikit-learn%22%2C%0A%23%20%20%20%20%20%22sklearn-wrap%22%2C%0A%23%20%5D%0A%23%20%2F%2F%2F%0A%22%22%22%0A%23%20How%20to%20Control%20Nested%20Wrapper%20Parameters%0A%0AThis%20notebook%20shows%20how%20to%20use%20the%20double-underscore%20(%60__%60)%20syntax%0Afor%20controlling%20parameters%20in%20nested%20estimator%20hierarchies.%0A%22%22%22%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.23.2%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20import%20numpy%20as%20np%0A%0A%20%20%20%20from%20sklearn_wrap%20import%20BaseClassWrapper%0A%0A%20%20%20%20return%20BaseClassWrapper%2C%20np%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20In%20this%20tutorial%20we%20build%20an%20ensemble%20wrapper%20that%20contains%20two%20inner%20wrappers.%0A%20%20%20%20We%20will%20inspect%20the%20nested%20parameter%20structure%2C%20modify%20parameters%20at%20any%20depth%0A%20%20%20%20with%20the%20%60__%60%20syntax%2C%20and%20see%20how%20sklearn%20renders%20the%20hierarchy.%0A%0A%20%20%20%20**Prerequisites**%20-%20Familiarity%20with%20%5Bfirst_wrapper.py%5D(first_wrapper.py)%20and%20%5Bparameter_interface.py%5D(parameter_interface.py).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20class%20BaseRegressor%3A%0A%20%20%20%20%20%20%20%20%22%22%22Non-sklearn%20regressor%20with%20custom%20methods.%22%22%22%0A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20scale%3D1.0)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self._scaling_factor%20%3D%20scale%0A%0A%20%20%20%20%20%20%20%20def%20train_model(self%2C%20X%2C%20y)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22Train%20the%20model%20(not%20'fit').%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20self._average_value%20%3D%20y.mean()%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self%0A%0A%20%20%20%20%20%20%20%20def%20generate_output(self%2C%20X)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22Generate%20predictions%20(not%20'predict').%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20np.full(X.shape%5B0%5D%2C%20self._average_value%20*%20self._scaling_factor)%0A%0A%0A%20%20%20%20class%20EnsembleRegressor%3A%0A%20%20%20%20%20%20%20%20%22%22%22Ensemble%20that%20doesn't%20follow%20sklearn%20conventions.%22%22%22%0A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20estimator1%2C%20estimator2%2C%20blend%3D0.5)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self._model_a%20%3D%20estimator1%0A%20%20%20%20%20%20%20%20%20%20%20%20self._model_b%20%3D%20estimator2%0A%20%20%20%20%20%20%20%20%20%20%20%20self._blend_ratio%20%3D%20blend%0A%0A%20%20%20%20%20%20%20%20def%20train_ensemble(self%2C%20X%2C%20y)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22Train%20both%20models%20(not%20'fit').%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20self._model_a.fit(X%2C%20y)%0A%20%20%20%20%20%20%20%20%20%20%20%20self._model_b.fit(X%2C%20y)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self%0A%0A%20%20%20%20%20%20%20%20def%20compute_blend(self%2C%20X)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22Compute%20blended%20predictions%20(not%20'predict').%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20pred1%20%3D%20self._model_a.predict(X)%0A%20%20%20%20%20%20%20%20%20%20%20%20pred2%20%3D%20self._model_b.predict(X)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self._blend_ratio%20*%20pred1%20%2B%20(1%20-%20self._blend_ratio)%20*%20pred2%0A%0A%20%20%20%20return%20BaseRegressor%2C%20EnsembleRegressor%0A%0A%0A%40app.cell%0Adef%20_(BaseClassWrapper)%3A%0A%20%20%20%20class%20BaseWrapper(BaseClassWrapper)%3A%0A%20%20%20%20%20%20%20%20_estimator_name%20%3D%20%22regressor%22%0A%20%20%20%20%20%20%20%20_estimator_base_class%20%3D%20object%0A%0A%20%20%20%20%20%20%20%20def%20fit(self%2C%20X%2C%20y)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.instantiate()%0A%20%20%20%20%20%20%20%20%20%20%20%20self.instance_.train_model(X%2C%20y)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.fitted_%20%3D%20True%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self%0A%0A%20%20%20%20%20%20%20%20def%20predict(self%2C%20X)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self.instance_.generate_output(X)%0A%0A%20%20%20%20return%20(BaseWrapper%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%201.%20Creating%20a%20Nested%20Estimator%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(BaseClassWrapper%2C%20BaseRegressor%2C%20BaseWrapper%2C%20EnsembleRegressor)%3A%0A%20%20%20%20class%20EnsembleWrapper(BaseClassWrapper)%3A%0A%20%20%20%20%20%20%20%20_estimator_name%20%3D%20%22ensemble%22%0A%20%20%20%20%20%20%20%20_estimator_base_class%20%3D%20object%0A%0A%20%20%20%20%20%20%20%20def%20fit(self%2C%20X%2C%20y)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.instantiate()%0A%20%20%20%20%20%20%20%20%20%20%20%20self.instance_.train_ensemble(X%2C%20y)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.fitted_%20%3D%20True%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self%0A%0A%20%20%20%20%20%20%20%20def%20predict(self%2C%20X)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self.instance_.compute_blend(X)%0A%0A%20%20%20%20%23%20Create%20two%20inner%20estimators%20with%20different%20scales%0A%20%20%20%20inner1%20%3D%20BaseWrapper(regressor%3DBaseRegressor%2C%20scale%3D0.8)%0A%20%20%20%20inner2%20%3D%20BaseWrapper(regressor%3DBaseRegressor%2C%20scale%3D1.2)%0A%0A%20%20%20%20%23%20Create%20ensemble%20with%20nested%20estimators%0A%20%20%20%20ensemble%20%3D%20EnsembleWrapper(%0A%20%20%20%20%20%20%20%20ensemble%3DEnsembleRegressor%2C%0A%20%20%20%20%20%20%20%20estimator1%3Dinner1%2C%0A%20%20%20%20%20%20%20%20estimator2%3Dinner2%2C%0A%20%20%20%20%20%20%20%20blend%3D0.5%0A%20%20%20%20)%0A%20%20%20%20return%20EnsembleWrapper%2C%20ensemble%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(ensemble%2C%20mo)%3A%0A%20%20%20%20params%20%3D%20ensemble.get_params(deep%3DTrue)%0A%0A%20%20%20%20%23%20Filter%20to%20show%20nested%20params%20clearly%0A%20%20%20%20nested_params%20%3D%20%7Bk%3A%20v%20for%20k%2C%20v%20in%20params.items()%20if%20'__'%20in%20k%7D%0A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20f%22%22%22%0A%20%20%20%20%20%20%20%20%23%23%202.%20Parameter%20Inspection%0A%0A%20%20%20%20%20%20%20%20**All%20parameters%3A**%0A%20%20%20%20%20%20%20%20%60%60%60python%0A%20%20%20%20%20%20%20%20%7Blist(params.keys())%7D%0A%20%20%20%20%20%20%20%20%60%60%60%0A%0A%20%20%20%20%20%20%20%20**Nested%20parameters%20(with%20__)%3A**%0A%20%20%20%20%20%20%20%20%60%60%60python%0A%20%20%20%20%20%20%20%20%7Bnested_params%7D%0A%20%20%20%20%20%20%20%20%60%60%60%0A%0A%20%20%20%20%20%20%20%20Notice%20the%20%60__%60%20syntax%20for%20nested%20access%20like%20%60estimator1__scale%60.%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%203.%20Interactive%20Control%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20def%20create_slider(start%2C%20stop%2C%20value%2C%20label%2C%20step%3DNone%2C%20**kwargs)%3A%0A%20%20%20%20%20%20%20%20params%20%3D%20%7B%22start%22%3A%20start%2C%20%22stop%22%3A%20stop%2C%20%22value%22%3A%20value%2C%20%22label%22%3A%20label%2C%20%22show_value%22%3A%20True%2C%20**kwargs%7D%0A%20%20%20%20%20%20%20%20if%20step%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20params%5B%22step%22%5D%20%3D%20step%0A%20%20%20%20%20%20%20%20return%20mo.ui.slider(**params)%0A%0A%20%20%20%20return%20(create_slider%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(create_slider%2C%20mo)%3A%0A%20%20%20%20scale1_slider%20%3D%20create_slider(0.5%2C%201.5%2C%200.8%2C%20%22Scale%201%22%2C%20step%3D0.1)%0A%20%20%20%20scale2_slider%20%3D%20create_slider(0.5%2C%201.5%2C%201.2%2C%20%22Scale%202%22%2C%20step%3D0.1)%0A%20%20%20%20blend_slider%20%3D%20create_slider(0.0%2C%201.0%2C%200.5%2C%20%22Blend%22%2C%20step%3D0.1)%0A%20%20%20%20mo.hstack(%5Bscale1_slider%2C%20scale2_slider%2C%20blend_slider%5D%2C%20justify%3D%22space-around%22)%0A%20%20%20%20return%20blend_slider%2C%20scale1_slider%2C%20scale2_slider%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20BaseRegressor%2C%0A%20%20%20%20BaseWrapper%2C%0A%20%20%20%20EnsembleRegressor%2C%0A%20%20%20%20EnsembleWrapper%2C%0A%20%20%20%20blend_slider%2C%0A%20%20%20%20np%2C%0A%20%20%20%20scale1_slider%2C%0A%20%20%20%20scale2_slider%2C%0A)%3A%0A%20%20%20%20%23%20Create%20ensemble%20with%20slider-controlled%20parameters%20using%20nested%20syntax%0A%20%20%20%20ensemble_interactive%20%3D%20EnsembleWrapper(%0A%20%20%20%20%20%20%20%20ensemble%3DEnsembleRegressor%2C%0A%20%20%20%20%20%20%20%20estimator1%3DBaseWrapper(regressor%3DBaseRegressor%2C%20scale%3Dscale1_slider.value)%2C%0A%20%20%20%20%20%20%20%20estimator2%3DBaseWrapper(regressor%3DBaseRegressor%2C%20scale%3Dscale2_slider.value)%2C%0A%20%20%20%20%20%20%20%20blend%3Dblend_slider.value%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Generate%20and%20fit%20data%0A%20%20%20%20X_train%2C%20X_test%2C%20y_train%2C%20y_test%20%3D%20generate_regression_data(n_features%3D1%2C%20noise%3D10)%0A%20%20%20%20ensemble_interactive.fit(X_train%2C%20y_train)%0A%0A%20%20%20%20%23%20Make%20predictions%0A%20%20%20%20y_pred_train%20%3D%20ensemble_interactive.predict(X_train)%0A%20%20%20%20y_pred_test%20%3D%20ensemble_interactive.predict(X_test)%0A%0A%20%20%20%20%23%20For%20plotting%0A%20%20%20%20X_plot%20%3D%20np.linspace(X_train.min()%2C%20X_train.max()%2C%20100).reshape(-1%2C%201)%0A%20%20%20%20y_pred_plot%20%3D%20ensemble_interactive.predict(X_plot)%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20X_plot%2C%0A%20%20%20%20%20%20%20%20X_test%2C%0A%20%20%20%20%20%20%20%20X_train%2C%0A%20%20%20%20%20%20%20%20y_pred_plot%2C%0A%20%20%20%20%20%20%20%20y_pred_test%2C%0A%20%20%20%20%20%20%20%20y_pred_train%2C%0A%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20y_train%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20X_plot%2C%0A%20%20%20%20X_test%2C%0A%20%20%20%20X_train%2C%0A%20%20%20%20blend_slider%2C%0A%20%20%20%20calculate_train_test_scores%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20scale1_slider%2C%0A%20%20%20%20scale2_slider%2C%0A%20%20%20%20y_pred_plot%2C%0A%20%20%20%20y_pred_test%2C%0A%20%20%20%20y_pred_train%2C%0A%20%20%20%20y_test%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20train_r2%2C%20test_r2%20%3D%20calculate_train_test_scores(%0A%20%20%20%20%20%20%20%20y_train%2C%20y_pred_train%2C%20y_test%2C%20y_pred_test%0A%20%20%20%20)%0A%0A%20%20%20%20fig%20%3D%20create_regression_scatter(%0A%20%20%20%20%20%20%20%20X_train%2C%20y_train%2C%20X_test%2C%20y_test%2C%20X_plot%2C%20y_pred_plot%2C%0A%20%20%20%20%20%20%20%20train_r2%2C%20test_r2%2C%0A%20%20%20%20%20%20%20%20title_prefix%3Df%22Ensemble%3A%20scale1%3D%7Bscale1_slider.value%3A.1f%7D%2C%20scale2%3D%7Bscale2_slider.value%3A.1f%7D%2C%20blend%3D%7Bblend_slider.value%3A.1f%7D%22%0A%20%20%20%20)%0A%0A%20%20%20%20mo.ui.plotly(fig)%0A%20%20%20%20return%0A%0A%0A%40app.function(hide_code%3DTrue)%0Adef%20generate_regression_data(n_samples%3D300%2C%20n_features%3D2%2C%20noise%3D20%2C%20test_size%3D0.3%2C%20random_state%3D42%2C%20**kwargs)%3A%0A%20%20%20%20from%20sklearn.datasets%20import%20make_regression%0A%20%20%20%20from%20sklearn.model_selection%20import%20train_test_split%0A%20%20%20%20X%2C%20y%20%3D%20make_regression(n_samples%3Dn_samples%2C%20n_features%3Dn_features%2C%20noise%3Dnoise%2C%20random_state%3Drandom_state%2C%20**kwargs)%0A%20%20%20%20return%20train_test_split(X%2C%20y%2C%20test_size%3Dtest_size%2C%20random_state%3Drandom_state)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(np)%3A%0A%20%20%20%20def%20calculate_r2_score(y_true%2C%20y_pred)%3A%0A%20%20%20%20%20%20%20%20return%201%20-%20np.mean((y_true%20-%20y_pred)%20**%202)%20%2F%20np.var(y_true)%0A%0A%20%20%20%20return%20(calculate_r2_score%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(calculate_r2_score)%3A%0A%20%20%20%20def%20calculate_train_test_scores(y_train%2C%20y_pred_train%2C%20y_test%2C%20y_pred_test)%3A%0A%20%20%20%20%20%20%20%20return%20(calculate_r2_score(y_train%2C%20y_pred_train)%2C%20calculate_r2_score(y_test%2C%20y_pred_test))%0A%0A%20%20%20%20return%20(calculate_train_test_scores%2C)%0A%0A%0A%40app.function(hide_code%3DTrue)%0Adef%20create_regression_scatter(X_train%2C%20y_train%2C%20X_test%2C%20y_test%2C%20X_plot%2C%20y_pred_plot%2C%20train_score%2C%20test_score%2C%20title_prefix%3D%22%22%2C%20**layout_kwargs)%3A%0A%20%20%20%20import%20plotly.graph_objects%20as%20go%0A%20%20%20%20fig%20%3D%20go.Figure()%0A%20%20%20%20fig.add_trace(go.Scatter(x%3DX_train.flatten()%2C%20y%3Dy_train%2C%20mode%3D%22markers%22%2C%20name%3D%22Training%20Data%22%2C%20marker%3Ddict(size%3D8%2C%20color%3D%22lightblue%22%2C%20line%3Ddict(width%3D1%2C%20color%3D%22darkblue%22))))%0A%20%20%20%20fig.add_trace(go.Scatter(x%3DX_test.flatten()%2C%20y%3Dy_test%2C%20mode%3D%22markers%22%2C%20name%3D%22Test%20Data%22%2C%20marker%3Ddict(size%3D8%2C%20color%3D%22lightcoral%22%2C%20line%3Ddict(width%3D1%2C%20color%3D%22darkred%22))))%0A%20%20%20%20fig.add_trace(go.Scatter(x%3DX_plot.flatten()%2C%20y%3Dy_pred_plot%2C%20mode%3D%22lines%22%2C%20name%3D%22Model%20Prediction%22%2C%20line%3Ddict(color%3D%22green%22%2C%20width%3D3)))%0A%20%20%20%20title%20%3D%20f%22Train%20R%C2%B2%20%3D%20%7Btrain_score%3A.3f%7D%2C%20Test%20R%C2%B2%20%3D%20%7Btest_score%3A.3f%7D%22%0A%20%20%20%20if%20title_prefix%3A%0A%20%20%20%20%20%20%20%20title%20%3D%20f%22%7Btitle_prefix%7D%3Cbr%3E%7Btitle%7D%22%0A%20%20%20%20fig.update_layout(title%3Dtitle%2C%20xaxis_title%3D%22Feature%22%2C%20yaxis_title%3D%22Target%22%2C%20height%3D500%2C%20showlegend%3DTrue%2C%20**layout_kwargs)%0A%20%20%20%20return%20fig%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%204.%20Modifying%20Nested%20Parameters%0A%0A%20%20%20%20We%20can%20use%20%60set_params()%60%20with%20%60__%60%20syntax%20to%20modify%20nested%20parameters%20without%0A%20%20%20%20recreating%20the%20estimator.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(ensemble)%3A%0A%20%20%20%20%23%20Demonstrate%20nested%20parameter%20modification%0A%20%20%20%20ensemble_modified%20%3D%20ensemble.set_params(%0A%20%20%20%20%20%20%20%20estimator1__scale%3D1.5%2C%0A%20%20%20%20%20%20%20%20estimator2__scale%3D0.7%2C%0A%20%20%20%20%20%20%20%20blend%3D0.3%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Verify%20changes%0A%20%20%20%20modified_params%20%3D%20%7B%0A%20%20%20%20%20%20%20%20'estimator1__scale'%3A%20ensemble_modified.get_params(deep%3DTrue)%5B'estimator1__scale'%5D%2C%0A%20%20%20%20%20%20%20%20'estimator2__scale'%3A%20ensemble_modified.get_params(deep%3DTrue)%5B'estimator2__scale'%5D%2C%0A%20%20%20%20%20%20%20%20'blend'%3A%20ensemble_modified.get_params(deep%3DTrue)%5B'blend'%5D%0A%20%20%20%20%7D%0A%0A%20%20%20%20modified_params%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%205.%20HTML%20Representation%0A%0A%20%20%20%20Notice%20that%20the%20nested%20structure%20renders%20correctly%2C%20showing%20the%20full%20parameter%0A%20%20%20%20hierarchy%20at%20a%20glance.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%23%20Ensemble%20Estimator%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(ensemble)%3A%0A%20%20%20%20ensemble%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20What%20We%20Built%0A%0A%20%20%20%20We%20built%20a%20two-level%20estimator%20hierarchy%20and%20used%20the%20%60__%60%20syntax%20to%20inspect%20and%0A%20%20%20%20modify%20parameters%20at%20every%20level.%20This%20same%20syntax%20is%20what%20%60GridSearchCV%60%20uses%20to%0A%20%20%20%20search%20nested%20parameter%20spaces.%0A%0A%20%20%20%20Next%3A%20%5Bfit_context.py%5D(fit_context.py)%20covers%20the%20%60_fit_context%60%20decorator%20and%0A%20%20%20%20automatic%20validation%20control.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
dfe79f3a3f1c6e483a96c285ecad69a4