├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .prettierignore ├── CHANGELOG.md ├── Dockerfile ├── README.md ├── docs ├── assets │ ├── css │ │ └── custom.css │ ├── images │ │ ├── aprendepython-logo.svg │ │ ├── favicon.svg │ │ └── monty-python.jpg │ └── js │ │ ├── clipboard.js │ │ └── mathjax.js ├── core │ ├── controlflow │ │ ├── conditionals.md │ │ ├── images │ │ │ ├── conditionals │ │ │ │ ├── arrows.jpg │ │ │ │ ├── elif-dark.svg │ │ │ │ ├── elif-light.svg │ │ │ │ ├── four-spaces-dark.svg │ │ │ │ ├── four-spaces-light.svg │ │ │ │ └── truth-tables.svg │ │ │ └── loops │ │ │ │ ├── big-wheel.jpg │ │ │ │ └── matrioskas.png │ │ ├── index.md │ │ └── loops.md │ ├── datastructures │ │ ├── dicts.md │ │ ├── files.md │ │ ├── images │ │ │ ├── dicts │ │ │ │ ├── dictionary.jpg │ │ │ │ ├── dicts-dark.svg │ │ │ │ └── dicts-light.svg │ │ │ ├── files │ │ │ │ └── files.jpg │ │ │ ├── lists │ │ │ │ ├── join-list-dark.svg │ │ │ │ ├── join-list-light.svg │ │ │ │ ├── list-comprehension-dark.svg │ │ │ │ ├── list-comprehension-light.svg │ │ │ │ ├── list-comprehensions-transformation.svg │ │ │ │ ├── santa.jpg │ │ │ │ ├── spain2023-worldchampions.svg │ │ │ │ ├── sys-argv-dark.svg │ │ │ │ ├── sys-argv-light.svg │ │ │ │ └── zip.svg │ │ │ ├── sets │ │ │ │ ├── hug-chain.jpg │ │ │ │ ├── inclusion.svg │ │ │ │ ├── venn-dark.svg │ │ │ │ ├── venn-difference-dark.svg │ │ │ │ ├── venn-difference-light.svg │ │ │ │ ├── venn-intersection-dark.svg │ │ │ │ ├── venn-intersection-light.svg │ │ │ │ ├── venn-light.svg │ │ │ │ ├── venn-symdiff-dark.svg │ │ │ │ ├── venn-symdiff-light.svg │ │ │ │ ├── venn-union-dark.svg │ │ │ │ └── venn-union-light.svg │ │ │ └── tuples │ │ │ │ ├── chain.jpg │ │ │ │ ├── tuple-unpacking-dark.svg │ │ │ │ └── tuple-unpacking-light.svg │ │ ├── index.md │ │ ├── lists.md │ │ ├── sets.md │ │ └── tuples.md │ ├── datatypes │ │ ├── data.md │ │ ├── images │ │ │ ├── data │ │ │ │ ├── binheart.jpg │ │ │ │ ├── inmutable1.svg │ │ │ │ ├── inmutable2.svg │ │ │ │ ├── inmutable3.svg │ │ │ │ ├── mutable1.svg │ │ │ │ ├── mutable2.svg │ │ │ │ ├── mutable3.svg │ │ │ │ └── pyobject.svg │ │ │ ├── numbers │ │ │ │ ├── circular-shift-step1-dark.svg │ │ │ │ ├── circular-shift-step1-light.svg │ │ │ │ ├── circular-shift-step3-dark.svg │ │ │ │ ├── circular-shift-step3-light.svg │ │ │ │ ├── coil-modulo1-dark.svg │ │ │ │ ├── coil-modulo1-light.svg │ │ │ │ ├── coil-modulo2-dark.svg │ │ │ │ ├── coil-modulo2-light.svg │ │ │ │ ├── coil-modulo3-dark.svg │ │ │ │ ├── coil-modulo3-light.svg │ │ │ │ ├── dices.jpg │ │ │ │ ├── modulo-dark.svg │ │ │ │ └── modulo-light.svg │ │ │ └── strings │ │ │ │ ├── newspaper.jpg │ │ │ │ ├── string-indexing-dark.svg │ │ │ │ └── string-indexing-light.svg │ │ ├── index.md │ │ ├── numbers.md │ │ └── strings.md │ ├── devenv │ │ ├── images │ │ │ ├── real-context │ │ │ │ ├── replit.png │ │ │ │ └── spacex.jpg │ │ │ ├── thonny │ │ │ │ ├── desktop.jpg │ │ │ │ ├── thonny-debug.png │ │ │ │ ├── thonny-empty.png │ │ │ │ └── thonny-save.png │ │ │ └── vscode │ │ │ │ ├── pencil.jpg │ │ │ │ ├── vscode-debug-breakpoint.png │ │ │ │ ├── vscode-debug-cbreakpoint.png │ │ │ │ ├── vscode-debug-config.png │ │ │ │ ├── vscode-debug-open.png │ │ │ │ ├── vscode-debug-toolbar.png │ │ │ │ ├── vscode-debug-variables.png │ │ │ │ ├── vscode-debug-watch.png │ │ │ │ └── vscode-debug-zones.png │ │ ├── index.md │ │ ├── real-context.md │ │ ├── thonny.md │ │ └── vscode.md │ ├── index.md │ ├── introduction │ │ ├── history.md │ │ ├── images │ │ │ ├── history │ │ │ │ ├── ada-lovelace.jpg │ │ │ │ ├── coliseum.jpg │ │ │ │ └── proglangs.svg │ │ │ ├── machine │ │ │ │ └── engine.jpg │ │ │ └── python │ │ │ │ ├── python.jpg │ │ │ │ └── who-uses-python.svg │ │ ├── index.md │ │ ├── machine.md │ │ └── python.md │ └── modularity │ │ ├── exceptions.md │ │ ├── files │ │ └── functions │ │ │ └── docs.zip │ │ ├── functions.md │ │ ├── images │ │ ├── exceptions │ │ │ └── icecream.jpg │ │ ├── functions │ │ │ ├── args-params-dark.svg │ │ │ ├── args-params-light.svg │ │ │ ├── decorator-anatomy.svg │ │ │ ├── decorator-behaviour-dark.svg │ │ │ ├── decorator-behaviour-light.svg │ │ │ ├── def-dark.svg │ │ │ ├── def-light.svg │ │ │ ├── lambda-dark.svg │ │ │ ├── lambda-light.svg │ │ │ ├── machine.jpg │ │ │ ├── map-filter-reduce-dark.svg │ │ │ ├── map-filter-reduce-light.svg │ │ │ ├── namespaces-dark.svg │ │ │ ├── namespaces-light.svg │ │ │ ├── params-only-keywords-dark.svg │ │ │ ├── params-only-keywords-light.svg │ │ │ ├── params-only-positional-dark.svg │ │ │ ├── params-only-positional-light.svg │ │ │ ├── sphinx-docs-dark.png │ │ │ └── sphinx-docs-light.png │ │ ├── modules │ │ │ ├── if-name-main-dark.svg │ │ │ ├── if-name-main-light.svg │ │ │ ├── import-dark.svg │ │ │ ├── import-light.svg │ │ │ ├── lego.jpg │ │ │ ├── library-package-module.svg │ │ │ └── stdlib-package-module.svg │ │ └── oop │ │ │ ├── aggregation.svg │ │ │ ├── bike-object-dark.svg │ │ │ ├── bike-object-light.svg │ │ │ ├── composition.svg │ │ │ ├── inheritance.svg │ │ │ ├── iterables-dark.svg │ │ │ ├── iterables-light.svg │ │ │ ├── mold-dark.svg │ │ │ ├── mold-light.svg │ │ │ ├── mold.svg │ │ │ ├── multiple-inheritance-dark.svg │ │ │ ├── multiple-inheritance-light.svg │ │ │ ├── obeys-owner1-dark.svg │ │ │ ├── obeys-owner1-light.svg │ │ │ ├── obeys-owner2-dark.svg │ │ │ ├── obeys-owner2-light.svg │ │ │ ├── properties-vs-methods-dark.svg │ │ │ ├── properties-vs-methods-light.svg │ │ │ ├── starwars-droids.jpg │ │ │ └── things.jpg │ │ ├── index.md │ │ ├── modules.md │ │ └── oop.md ├── index.md ├── stdlib │ ├── data-access │ │ ├── images │ │ │ └── sqlite │ │ │ │ └── hdd.jpg │ │ ├── index.md │ │ └── sqlite.md │ ├── index.md │ └── text-processing │ │ ├── images │ │ ├── re │ │ │ └── floor.jpg │ │ └── string │ │ │ └── ball.jpg │ │ ├── index.md │ │ ├── re.md │ │ └── string.md └── third-party │ ├── config │ ├── index.md │ └── prettyconf.md │ ├── data-science │ ├── files │ │ ├── jupyter │ │ │ ├── equations.tex │ │ │ └── timeit.py │ │ ├── matplotlib │ │ │ ├── avengers.csv │ │ │ ├── bmw-clean.csv │ │ │ ├── bmw_plot.py │ │ │ ├── eth-usd.csv │ │ │ ├── euro-dollar-clean.csv │ │ │ ├── euro_dollar.py │ │ │ ├── global-temperatures.csv │ │ │ ├── imdb-top-1000.csv │ │ │ ├── medals.xlsx │ │ │ ├── mwh-spain-2021-clean.csv │ │ │ ├── mwh_spain.py │ │ │ ├── nba-data.csv │ │ │ ├── pokemon.csv │ │ │ ├── pokemon_speed.py │ │ │ ├── soften_wave.py │ │ │ ├── tiobe-2020-clean.csv │ │ │ └── tiobe_2020.py │ │ ├── numpy │ │ │ ├── diag.py │ │ │ ├── diag_transform.py │ │ │ ├── euler_product.py │ │ │ ├── flip_powers.py │ │ │ ├── identity_equation.py │ │ │ ├── lineq.py │ │ │ ├── np_matrix.py │ │ │ ├── np_odds.py │ │ │ ├── np_random.py │ │ │ ├── np_transform.py │ │ │ ├── transpose.py │ │ │ └── vectorize.py │ │ └── pandas │ │ │ ├── above_mean.py │ │ │ ├── comunidades.py │ │ │ ├── create_dataframe.py │ │ │ ├── create_series.py │ │ │ ├── democan.csv │ │ │ ├── df_access.py │ │ │ ├── df_oasis.py │ │ │ ├── grants.py │ │ │ ├── index_dataframe.py │ │ │ ├── load_dataframe.py │ │ │ ├── oasis.csv │ │ │ ├── pop_density.py │ │ │ ├── pop_percentage.py │ │ │ ├── recoding.py │ │ │ ├── smallest_density.py │ │ │ └── tech.csv │ ├── images │ │ ├── jupyter │ │ │ ├── basic-plot.png │ │ │ ├── canaryislands-googlemaps.png │ │ │ ├── google-colab.png │ │ │ ├── jupyter-browser.png │ │ │ ├── jupyter-busy-kernel.png │ │ │ ├── jupyter-cell-menu.png │ │ │ ├── jupyter-cells.jpg │ │ │ ├── jupyter-edit-menu.png │ │ │ ├── jupyter-file-menu.png │ │ │ ├── jupyter-help-menu.png │ │ │ ├── jupyter-insert-menu.png │ │ │ ├── jupyter-kernel-menu.png │ │ │ ├── jupyter-view-menu.png │ │ │ ├── jupyter.jpg │ │ │ ├── jupyterlab.png │ │ │ └── kaggle.png │ │ ├── matplotlib │ │ │ ├── add-subplot-dark.svg │ │ │ ├── add-subplot-light.svg │ │ │ ├── avengers-plot.png │ │ │ ├── axes-2by2.png │ │ │ ├── axis-labels.png │ │ │ ├── axis-lim.png │ │ │ ├── barplot-tiobe.png │ │ │ ├── blank-figure.png │ │ │ ├── bluered-grid.png │ │ │ ├── boxplot-anatomy-dark.svg │ │ │ ├── boxplot-anatomy-light.svg │ │ │ ├── centering-legend.png │ │ │ ├── default-grid.png │ │ │ ├── dist-boxplot.png │ │ │ ├── eth-evolution.png │ │ │ ├── gbar-plot.png │ │ │ ├── global-temperatures.png │ │ │ ├── heatmap-eurodollar.png │ │ │ ├── hist-pokemon-speed.png │ │ │ ├── imdb-heatmap.png │ │ │ ├── label-ticks.png │ │ │ ├── mandala.jpg │ │ │ ├── minor-ticks.png │ │ │ ├── mwh-spain-2021.png │ │ │ ├── nba-scatter-plot.png │ │ │ ├── plot-annotations.png │ │ │ ├── plot-legend.png │ │ │ ├── plot-sin.png │ │ │ ├── plot-sincos.png │ │ │ ├── plot-styles.png │ │ │ ├── scatter-bmw.png │ │ │ ├── soften-wave.png │ │ │ └── tex-legend.png │ │ ├── numpy │ │ │ ├── blocks.jpg │ │ │ ├── numpy-arrays-dark.svg │ │ │ ├── numpy-arrays-light.svg │ │ │ ├── numpy-diagonal-dark.svg │ │ │ └── numpy-diagonal-light.svg │ │ └── pandas │ │ │ ├── dataframe-structure-dark.svg │ │ │ ├── dataframe-structure-light.svg │ │ │ ├── panda.jpg │ │ │ ├── pandas-concat-dark.svg │ │ │ ├── pandas-concat-light.svg │ │ │ ├── pandas-merge-dark.svg │ │ │ ├── pandas-merge-light.svg │ │ │ ├── series-and-dataframes-dark.svg │ │ │ └── series-and-dataframes-light.svg │ ├── index.md │ ├── jupyter.md │ ├── matplotlib.md │ ├── numpy.md │ └── pandas │ │ ├── dataframes.md │ │ ├── index.md │ │ └── series.md │ ├── index.md │ ├── networking │ ├── files │ │ └── requests │ │ │ └── req.py │ ├── images │ │ └── requests │ │ │ └── wing.jpg │ ├── index.md │ └── requests.md │ ├── pdf │ ├── index.md │ └── weasyprint.md │ ├── scraping │ ├── beautifulsoup.md │ ├── files │ │ ├── beautifulsoup │ │ │ └── pypi-trend.py │ │ └── selenium │ │ │ ├── mercadona.py │ │ │ ├── wordle_play.py │ │ │ └── wordle_try.py │ ├── images │ │ ├── beautifulsoup │ │ │ └── soup.jpg │ │ └── selenium │ │ │ ├── dom-inspector.png │ │ │ ├── robot-assistant.jpg │ │ │ ├── selenium-python.png │ │ │ ├── webdriverwait-dark.svg │ │ │ └── webdriverwait-light.svg │ ├── index.md │ └── selenium.md │ └── webdev │ ├── django │ ├── admin.md │ ├── api.md │ ├── apps.md │ ├── auth.md │ ├── extras.md │ ├── forms.md │ ├── i18n.md │ ├── images │ │ ├── models │ │ │ ├── related_name-dark.svg │ │ │ └── related_name-light.svg │ │ └── webdev │ │ │ ├── client-side-rendering.png │ │ │ ├── django-logo.svg │ │ │ ├── django-reinhardt.jpg │ │ │ ├── frontend-backend.svg │ │ │ ├── html-and-css.png │ │ │ ├── server-side-rendering.png │ │ │ ├── web-langs.svg │ │ │ ├── webdev-layers.png │ │ │ └── who-uses-django.svg │ ├── index.md │ ├── models.md │ ├── setup.md │ ├── static.md │ ├── templates.md │ ├── urls.md │ ├── views.md │ └── webdev.md │ └── index.md ├── includes └── abbreviations.md ├── justfile ├── mkdocs.yml ├── promo.jpg ├── pyproject.toml └── uv.lock /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | workflow_dispatch: 7 | jobs: 8 | deploy-documentation: 9 | name: Deploy documentation 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v2 14 | - name: Build docker image 15 | run: docker build . -t aprendepython 16 | - name: Build documentation 17 | run: docker run --rm -v .:/docs aprendepython 18 | - name: Sync files with production server 19 | uses: burnett01/rsync-deployments@4.1 20 | with: 21 | switches: -avzr --delete 22 | path: site/ 23 | remote_host: aprendepython.es 24 | remote_path: ${{ secrets.REMOTE_BUILD_PATH }} 25 | remote_user: ${{ secrets.REMOTE_USER }} 26 | remote_key: ${{ secrets.REMOTE_KEY }} 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .venv 2 | .artwork 3 | *.pyc 4 | TODO 5 | site 6 | .DS_Store 7 | __pycache__ 8 | .mypy_cache 9 | .pytest_cache 10 | *.egg-info 11 | *.egg 12 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | *.md 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | Las versiones siguen [versionado semántico](https://semver.org/) (`..`). 4 | 5 | ## Sin publicar 6 | 7 | Publicada el XX-XX-XXXX 8 | 9 | ## Version 2.0.1 10 | 11 | Publicada el 19-05-2025 12 | 13 | - Añade bloques de contenido en la página principal. 14 | - Añade `README.md` en el repositorio de código. 15 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y curl && \ 5 | curl -LsSf https://astral.sh/uv/install.sh | sh 6 | 7 | ENV UV_LINK_MODE=copy \ 8 | PATH="/root/.local/bin:$PATH" 9 | 10 | WORKDIR /docs 11 | COPY . /docs 12 | 13 | CMD ["uv", "run", "mkdocs", "build"] 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Aprende Python 2 | 3 | Aprende el lenguaje de programación Python con este manual que cubre los fundamentos del lenguaje, módulos de la librería estándar y paquetes de terceros. Contiene multitud de ejercicios a través de pypas.es y está ajustado a distintos niveles de aprendizaje. Todos los recursos están disponibles vía web utilizando un diseño moderno y completamente gratuito. 4 | 5 | ![Promo](./promo.jpg) 6 | 7 | **La guía definitiva en español para aprender tu lenguaje de programación favorito.** 8 | 9 | © Sergio Delgado Quintero. 10 | -------------------------------------------------------------------------------- /docs/assets/css/custom.css: -------------------------------------------------------------------------------- 1 | /* 2 | INSPIRATION: https://github.com/astral-sh/uv/blob/main/mkdocs.template.yml 3 | MATERIAL COLORS: https://github.com/squidfunk/mkdocs-material/blob/master/src/templates/assets/stylesheets/main/_colors.scss 4 | DARK & LIGHT STYLES: https://uxplanet.org/create-an-easily-switchable-light-dark-styles-in-figma-ffee3cd542a7 5 | PATTERNS BASED ON PRIMARY COLOR: https://mycolor.space/?hex=%23009485&sub=1 6 | */ 7 | 8 | /* LIGHT MODE */ 9 | [data-md-color-scheme="default"] { 10 | /* Custom colors */ 11 | --blue-color: rgb(23, 143, 255); 12 | --green-color: rgb(29, 187, 53); 13 | --orange-color: rgb(254, 160, 47); 14 | --red-color: rgb(248, 65, 65); 15 | --yellow-color: rgb(216, 210, 25); 16 | --pink-color: rgb(177, 36, 137); 17 | /* Transparent custom colors */ 18 | --blue-transparent-color: rgba(23, 143, 255, 0.5); 19 | --green-transparent-color: rgba(29, 187, 53, 0.5); 20 | --orange-transparent-color: rgba(254, 160, 47, 0.5); 21 | --red-transparent-color: rgba(248, 65, 65, 0.5); 22 | --yellow-transparent-color: rgba(216, 210, 25, 0.5); 23 | --pink-transparent-color: rgba(177, 36, 137, 0.5); 24 | /* Modification of theme colors */ 25 | --md-code-hl-comment-color: var(--md-primary-fg-color); 26 | 27 | .blue { 28 | color: var(--blue-color); 29 | } 30 | .green { 31 | color: var(--green-color); 32 | } 33 | .orange { 34 | color: var(--orange-color); 35 | } 36 | .red { 37 | color: var(--red-color); 38 | } 39 | .yellow { 40 | color: var(--yellow-color); 41 | } 42 | .pink { 43 | color: var(--pink-color); 44 | } 45 | } 46 | 47 | /* DARK MODE */ 48 | [data-md-color-scheme="slate"] { 49 | /* Custom colors */ 50 | --blue-color: rgb(0, 133, 255); 51 | --green-color: rgb(32, 203, 73); 52 | --orange-color: rgb(249, 135, 0); 53 | --red-color: rgb(233, 44, 44); 54 | --yellow-color: rgb(231, 231, 21); 55 | --pink-color: rgb(196, 44, 153); 56 | /* Transparent custom colors */ 57 | --blue-transparent-color: rgba(0, 133, 255, 0.5); 58 | --green-transparent-color: rgba(32, 203, 73, 0.5); 59 | --orange-transparent-color: rgba(249, 135, 0, 0.5); 60 | --red-transparent-color: rgba(233, 44, 44, 0.5); 61 | --yellow-transparent-color: rgba(231, 231, 21, 0.5); 62 | --pink-transparent-color: rgba(196, 44, 153, 0.5); 63 | /* Modification of theme colors */ 64 | --md-code-hl-comment-color: var(--md-primary-fg-color); 65 | 66 | .blue { 67 | color: var(--blue-color); 68 | } 69 | .green { 70 | color: var(--green-color); 71 | } 72 | .orange { 73 | color: var(--orange-color); 74 | } 75 | .red { 76 | color: var(--red-color); 77 | } 78 | .yellow { 79 | color: var(--yellow-color); 80 | } 81 | .pink { 82 | color: var(--pink-color); 83 | } 84 | } 85 | 86 | .hl { 87 | color: var(--md-primary-fg-color); 88 | } 89 | 90 | .acc { 91 | color: var(--md-accent-fg-color); 92 | } 93 | 94 | .mono { 95 | font-family: monospace; 96 | } 97 | 98 | .bold { 99 | font-weight: bold; 100 | } 101 | 102 | .md-nav__link--active { 103 | font-weight: bold; 104 | } 105 | 106 | @keyframes beat { 107 | 0%, 108 | 40%, 109 | 80%, 110 | 100% { 111 | transform: scale(1); 112 | } 113 | 20%, 114 | 60% { 115 | transform: scale(1.15); 116 | } 117 | } 118 | .beat { 119 | animation: beat 1000ms infinite; 120 | } 121 | 122 | @keyframes flip { 123 | /* https://animista.net/play/basic/flip */ 124 | 50% { 125 | transform: rotateY(-180deg); 126 | } 127 | } 128 | .flip { 129 | animation: flip 1500ms infinite both; 130 | } 131 | 132 | @keyframes slide { 133 | /* https://animista.net/play/basic/slide */ 134 | 0% { 135 | transform: translateX(-1px); 136 | } 137 | 50% { 138 | transform: translateX(1px); 139 | } 140 | 100% { 141 | transform: translateX(-1px); 142 | } 143 | } 144 | .slide { 145 | animation: slide 1000ms infinite both; 146 | } 147 | 148 | /* Custom exercise admonition */ 149 | :root { 150 | --md-admonition-icon--brain: url('data:image/svg+xml;charset=utf-8,'); 151 | } 152 | .md-typeset .admonition.exercise, 153 | .md-typeset details.exercise { 154 | border-color: rgb(156, 18, 158); 155 | } 156 | .md-typeset .exercise > .admonition-title, 157 | .md-typeset .exercise > summary { 158 | background-color: rgba(156, 18, 158, 0.1); 159 | } 160 | .md-typeset .exercise > .admonition-title::before, 161 | .md-typeset .exercise > summary::before { 162 | background-color: rgb(156, 18, 158); 163 | -webkit-mask-image: var(--md-admonition-icon--brain); 164 | mask-image: var(--md-admonition-icon--brain); 165 | } 166 | 167 | span.example { 168 | font-style: italic; 169 | font-weight: bold; 170 | color: var(--orange-color); 171 | span.twemoji { 172 | margin-left: -0.15rem; 173 | margin-right: -0.2rem; 174 | margin-top: 0.1rem; 175 | } 176 | } 177 | 178 | span.pyversion { 179 | span.version { 180 | font-size: smaller; 181 | } 182 | span.twemoji { 183 | margin-right: -0.1rem; 184 | } 185 | } 186 | 187 | span.djversion { 188 | width: fit-content; 189 | display: block; 190 | font-size: smaller; 191 | color: white; 192 | padding: 0.1rem 0.4rem 0.1rem 0.4rem; 193 | border-radius: 0.2rem; 194 | /* https://codyhouse.co/nuggets/css-gradient-borders */ 195 | &.basic { 196 | background: linear-gradient(to right, #2c3b98, #21cffa) border-box; 197 | } 198 | &.intermediate { 199 | background: linear-gradient(to right, #159842, #aca513) border-box; 200 | } 201 | &.advanced { 202 | background: linear-gradient(to right, #de227a, #0e3ecc) border-box; 203 | } 204 | &.specialized { 205 | background: linear-gradient(to right, #14b2c0, #ef55ed) border-box; 206 | } 207 | } 208 | 209 | /* https://github.com/squidfunk/mkdocs-material/issues/3453#issuecomment-2407192662 */ 210 | .md-tooltip { 211 | top: inherit; 212 | left: inherit; 213 | margin-left: 12px; 214 | margin-top: 7px; 215 | } 216 | 217 | /* https://mkdocstrings.github.io/recipes/#prevent-selection-of-prompts-and-output-in-python-code-blocks */ 218 | .highlight .gp, 219 | .highlight .gt, 220 | .highlight .gr, 221 | .highlight .go { 222 | /* Generic.Prompt, Generic.Output */ 223 | user-select: none; 224 | } 225 | 226 | .white { 227 | background-color: white; 228 | display: inline-block; 229 | } 230 | -------------------------------------------------------------------------------- /docs/assets/images/aprendepython-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/assets/images/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/assets/images/monty-python.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/assets/images/monty-python.jpg -------------------------------------------------------------------------------- /docs/assets/js/clipboard.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function () { 2 | document.body.addEventListener("click", function (event) { 3 | // Verifica si se hizo clic en un botón de copiar 4 | const copyButton = event.target.closest("button.md-clipboard"); 5 | if (!copyButton) return; 6 | 7 | // Encuentra el bloque de código asociado 8 | const preBlock = copyButton.closest("pre"); 9 | const codeBlock = preBlock ? preBlock.querySelector("code") : null; 10 | if (!codeBlock) return; 11 | 12 | // Obtiene el texto del bloque de código 13 | let codeText = codeBlock.innerText; 14 | 15 | // Filtra y elimina los prompts ">>>", "...", y "$" al inicio de las líneas 16 | codeText = codeText 17 | .split("\n") 18 | .filter( 19 | (line) => 20 | line.startsWith(">>>") || 21 | line.startsWith("...") || 22 | line.startsWith("$") 23 | ) // Solo instrucciones 24 | .map((line) => line.replace(/^(>>>|\.\.\.|\$)\s?/, "")) // Elimina ">>>", "..." o "$" 25 | .join("\n"); 26 | 27 | // Si el bloque no es de sesión interactiva o Bash, copia todo el contenido 28 | if (codeText.trim() === "") { 29 | // Limpia las líneas resaltadas (hl_lines) 30 | codeText = codeBlock.textContent || codeBlock.innerText; // Usamos textContent para evitar problemas de espaciado 31 | } 32 | 33 | // Copia el código limpio al portapapeles 34 | navigator.clipboard.writeText(codeText).then(() => { 35 | // Opcional: Mostrar feedback visual en el botón 36 | copyButton.classList.add("copied"); 37 | setTimeout(() => copyButton.classList.remove("copied"), 1000); 38 | }); 39 | 40 | // Evita que el evento siga propagándose y se copie el código original 41 | event.stopPropagation(); 42 | event.preventDefault(); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /docs/assets/js/mathjax.js: -------------------------------------------------------------------------------- 1 | window.MathJax = { 2 | tex: { 3 | inlineMath: [["\\(", "\\)"]], 4 | displayMath: [["\\[", "\\]"]], 5 | processEscapes: true, 6 | processEnvironments: true, 7 | }, 8 | options: { 9 | ignoreHtmlClass: ".*|", 10 | processHtmlClass: "arithmatex", 11 | }, 12 | }; 13 | 14 | document$.subscribe(() => { 15 | MathJax.startup.output.clearCache(); 16 | MathJax.typesetClear(); 17 | MathJax.texReset(); 18 | MathJax.typesetPromise(); 19 | }); 20 | -------------------------------------------------------------------------------- /docs/core/controlflow/images/conditionals/arrows.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/controlflow/images/conditionals/arrows.jpg -------------------------------------------------------------------------------- /docs/core/controlflow/images/loops/big-wheel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/controlflow/images/loops/big-wheel.jpg -------------------------------------------------------------------------------- /docs/core/controlflow/images/loops/matrioskas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/controlflow/images/loops/matrioskas.png -------------------------------------------------------------------------------- /docs/core/controlflow/index.md: -------------------------------------------------------------------------------- 1 | # Control de flujo 2 | 3 | El control de flujo en programación se refiere a la manera en que se determina el orden en que se ejecutan las instrucciones de un programa. En lugar de seguir una secuencia lineal, los programas pueden tomar decisiones, repetir bloques de código o desviar la ejecución según ciertas condiciones. Esto se logra mediante estructuras como condicionales (if, else), bucles (for, while) y declaraciones de control como break o continue. Dominar el control de flujo es clave para desarrollar programas dinámicos y adaptables, capaces de responder a distintos escenarios. En este capítulo, aprenderás cómo utilizar estas estructuras en Python para crear algoritmos más complejos y eficientes. 4 | -------------------------------------------------------------------------------- /docs/core/datastructures/images/dicts/dictionary.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/datastructures/images/dicts/dictionary.jpg -------------------------------------------------------------------------------- /docs/core/datastructures/images/files/files.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/datastructures/images/files/files.jpg -------------------------------------------------------------------------------- /docs/core/datastructures/images/lists/santa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/datastructures/images/lists/santa.jpg -------------------------------------------------------------------------------- /docs/core/datastructures/images/sets/hug-chain.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/datastructures/images/sets/hug-chain.jpg -------------------------------------------------------------------------------- /docs/core/datastructures/images/sets/venn-difference-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /docs/core/datastructures/images/sets/venn-difference-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/core/datastructures/images/sets/venn-intersection-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /docs/core/datastructures/images/sets/venn-intersection-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/core/datastructures/images/sets/venn-symdiff-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /docs/core/datastructures/images/sets/venn-symdiff-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /docs/core/datastructures/images/sets/venn-union-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/core/datastructures/images/sets/venn-union-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/core/datastructures/images/tuples/chain.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/datastructures/images/tuples/chain.jpg -------------------------------------------------------------------------------- /docs/core/datastructures/index.md: -------------------------------------------------------------------------------- 1 | # Estructuras de datos 2 | 3 | Las estructuras de datos son formas organizadas de almacenar y gestionar conjuntos de información para que puedan ser utilizadas de manera eficiente por un programa. En Python, existen diversas estructuras integradas como listas, tuplas, conjuntos y diccionarios, cada una con características específicas que las hacen más adecuadas para ciertos tipos de tareas. Comprender cómo funcionan estas estructuras y cuándo utilizarlas es fundamental para escribir código limpio, optimizado y fácil de mantener. En este capítulo, exploraremos las principales estructuras de datos en Python, su sintaxis, operaciones comunes y casos prácticos donde se aplican. 4 | -------------------------------------------------------------------------------- /docs/core/datatypes/images/data/binheart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/datatypes/images/data/binheart.jpg -------------------------------------------------------------------------------- /docs/core/datatypes/images/numbers/dices.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/datatypes/images/numbers/dices.jpg -------------------------------------------------------------------------------- /docs/core/datatypes/images/strings/newspaper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/datatypes/images/strings/newspaper.jpg -------------------------------------------------------------------------------- /docs/core/datatypes/index.md: -------------------------------------------------------------------------------- 1 | # Tipos de datos 2 | 3 | En programación, los tipos de datos son fundamentales porque determinan la naturaleza de los valores que se pueden almacenar y manipular en un programa. Cada lenguaje, incluido Python, clasifica la información en distintos tipos para poder realizar operaciones apropiadas según su naturaleza, como sumar números o concatenar cadenas de texto. Comprender los tipos de datos es esencial para escribir código correcto y eficiente, ya que permite al programador elegir la forma adecuada de representar la información. En este capítulo exploraremos los principales tipos de datos en Python, como los números, las cadenas de texto o los booleanos. 4 | -------------------------------------------------------------------------------- /docs/core/devenv/images/real-context/replit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/real-context/replit.png -------------------------------------------------------------------------------- /docs/core/devenv/images/real-context/spacex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/real-context/spacex.jpg -------------------------------------------------------------------------------- /docs/core/devenv/images/thonny/desktop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/thonny/desktop.jpg -------------------------------------------------------------------------------- /docs/core/devenv/images/thonny/thonny-debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/thonny/thonny-debug.png -------------------------------------------------------------------------------- /docs/core/devenv/images/thonny/thonny-empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/thonny/thonny-empty.png -------------------------------------------------------------------------------- /docs/core/devenv/images/thonny/thonny-save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/thonny/thonny-save.png -------------------------------------------------------------------------------- /docs/core/devenv/images/vscode/pencil.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/vscode/pencil.jpg -------------------------------------------------------------------------------- /docs/core/devenv/images/vscode/vscode-debug-breakpoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/vscode/vscode-debug-breakpoint.png -------------------------------------------------------------------------------- /docs/core/devenv/images/vscode/vscode-debug-cbreakpoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/vscode/vscode-debug-cbreakpoint.png -------------------------------------------------------------------------------- /docs/core/devenv/images/vscode/vscode-debug-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/vscode/vscode-debug-config.png -------------------------------------------------------------------------------- /docs/core/devenv/images/vscode/vscode-debug-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/vscode/vscode-debug-open.png -------------------------------------------------------------------------------- /docs/core/devenv/images/vscode/vscode-debug-toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/vscode/vscode-debug-toolbar.png -------------------------------------------------------------------------------- /docs/core/devenv/images/vscode/vscode-debug-variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/vscode/vscode-debug-variables.png -------------------------------------------------------------------------------- /docs/core/devenv/images/vscode/vscode-debug-watch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/vscode/vscode-debug-watch.png -------------------------------------------------------------------------------- /docs/core/devenv/images/vscode/vscode-debug-zones.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/devenv/images/vscode/vscode-debug-zones.png -------------------------------------------------------------------------------- /docs/core/devenv/index.md: -------------------------------------------------------------------------------- 1 | # Entornos de desarrollo 2 | 3 | Un entorno de desarrollo es un conjunto de herramientas y recursos que facilitan la escritura, prueba y depuración de programas informáticos. Estos entornos, conocidos comúnmente como IDEs (Integrated Development Environments), integran funciones como resaltado de sintaxis, autocompletado de código, control de versiones y depuración paso a paso, lo que mejora significativamente la productividad del programador. En el caso de Python, algunos de los entornos más populares incluyen PyCharm, Visual Studio Code, Thonny y Jupyter Notebook, cada uno con características específicas que se adaptan tanto a principiantes como a desarrolladores avanzados. Elegir un buen entorno de desarrollo puede hacer la experiencia de programación más fluida, intuitiva y eficiente. 4 | -------------------------------------------------------------------------------- /docs/core/devenv/thonny.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: material/baby-carriage 3 | --- 4 | 5 | # Thonny { #thonny } 6 | 7 | ![Desktop](images/thonny/desktop.jpg) 8 | (1) 9 | { .annotate } 10 | 11 | 1. :fontawesome-regular-copyright: [Freddie Marriage](https://unsplash.com/es/@fredmarriage) (Unsplash) 12 | 13 | [Thonny](https://thonny.org/) es un programa muy interesante para empezar a aprender Python porque ofrece un entorno amigable en el que sólo te debes preocupar por escribir código y mejorar tus detrezas en Python. 14 | 15 | El programa además integra tres de las herramientas fundamentales para trabajar en programación: **intérprete**, **editor** y **depurador**. 16 | 17 | Cuando vamos a trabajar con Python debemos tener instalado, como mínimo, un [intérprete](../introduction/machine.md#compilers) del lenguaje (para otros lenguajes sería un _compilador_). El **intérprete** nos permitirá ejecutar nuestro código para obtener los resultados deseados. La idea del intéprete es lanzar instrucciones «sueltas» para probar determinados aspectos. 18 | 19 | Pero normalmente queremos ir un poco más allá y poder escribir programas algo más largos, por lo que también necesitaremos un **editor**. Un editor es un programa que nos permite crear ficheros de código (en nuestro caso con extensión `*.py`), que luego son ejecutados por el intérprete. 20 | 21 | Hay otra herramienta interesante dentro del entorno de desarrollo que sería el **depurador**. Lo podemos encontrar habitualmente en la bibliografía por su nombre inglés «debugger». Es el módulo que nos permite ejecutar paso a paso nuestro código y visualizar qué está ocurriendo en cada momento. Se suele usar normalmente para encontrar fallos («bugs») en nuestros programas y poder solucionarlos («debug & fix»). 22 | 23 | Cuando nos encontramos con un programa que proporciona estas funciones (e incluso otras adicionales) para el trabajo de programación, nos referimos a él como un _Entorno Integrado de Desarrollo_, conocido popularmente por sus siglas en inglés IDE. Thonny es un IDE gratuito, sencillo y apto para principiantes. 24 | 25 | ## Instalación { #installation } 26 | 27 | Para instalar Thonny debemos [acceder a su web](https://thonny.org/) y descargar la aplicación para nuestro sistema operativo. La ventaja es que está disponible tanto para **Windows**, **MacOS** y **Linux**. Una vez descargado el fichero lo ejecutamos y seguimos su instalación paso por paso. 28 | 29 | Una vez terminada la instalación ya podemos lanzar la aplicación que se verá parecida a la siguiente imagen: 30 | 31 | ![Thonny empty](images/thonny/thonny-empty.png) 32 | 33 | !!! tip "Aspecto" 34 | 35 | Es posible que el aspecto del programa varíe ligeramente según el sistema operativo, configuración de escritorio, versión utilizada o idioma (en mi caso está en inglés), pero a efectos de funcionamiento no hay diferencia. 36 | 37 | Podemos observar que la pantalla está dividida en **3 paneles**: 38 | 39 | - ^^Panel principal^^ que contiene el **editor** e incluye la etiqueta `` donde escribiremos nuestro código fuente Python. 40 | - ^^Panel inferior^^ con la etiqueta «Shell» que contiene el **intérprete** de Python. En el momento de la escritura del presente documento, Thonny incluye la versión de Python 3.10. 41 | - ^^Panel derecho^^ que contiene el **depurador**. Más concretamente se trata de la ventana de variables donde podemos inspeccionar el valor de las mismas. 42 | 43 | !!! warning "Versión de Python" 44 | 45 | Las actualizaciones de Thonny no están «alineadas» con las últimas versiones de Python, por lo que es probable que no dispongas de la última versión estable de Python en Thonny. En cualquier caso, siempre se podrá configurar el editor para usar una instalación personalizada de Python más actualizada. 46 | 47 | ## Intérprete { #interpreter } 48 | 49 | El intérprete de Python (por lo general) se identifica claramente porque posee un **prompt**(1)con tres angulos hacia la derecha `#!pycon >>>`. En Thonny lo podemos encontrar en el panel inferior, pero se debe tener en cuenta que el intérprete de Python es una herramienta autocontenida y que la podemos ejecutar desde el símbolo del sistema o la terminal: 50 | { .annotate } 51 | 52 | 1. Término inglés que se refiere al símbolo que precede la línea de comandos. 53 | 54 | ```console 55 | $ python 56 | Python 3.12.5 (main, Aug 14 2024, 04:32:18) [Clang 18.1.8 ] on darwin 57 | Type "help", "copyright", "credits" or "license" for more information. 58 | >>> 59 | ``` 60 | 61 | Para hacer una prueba inicial del intérprete vamos a retomar el primer programa que se suele hacer. Es el llamado [«Hello, World»](../introduction/machine.md/#assembly). Para ello escribimos lo siguiente en el intérprete y pulsamos la tecla ++enter++: 62 | 63 | ```pycon 64 | >>> print('Hello, World') 65 | Hello, World 66 | ``` 67 | 68 | Lo que hemos hecho es indicarle a Python que ejecute como **entrada** la instrucción `#!python print('Hello, World')`. La **salida** es el texto `Hello, World` que lo vemos en la siguiente línea (ya sin el prompt `#!pycon >>>`). 69 | 70 | ## Editor { #editor } 71 | 72 | Ahora vamos a realizar la misma operación, pero en vez de ejecutar la instrucción directamente en el intérprete, vamos a crear un fichero y guardarlo con la sentencia que nos interesa. Para ello escribimos `#!python print('Hello, World')` en el panel de edición (_superior_) y luego guardamos el archivo con el nombre `helloworld.py`[^1]: 73 | 74 | ![Thonny save](images/thonny/thonny-save.png) 75 | 76 | !!! info "Extensión .py" 77 | 78 | Los ficheros que contienen programas hechos en Python siempre deben tener la extensión `.py` 79 | 80 | Ahora ya podemos ejecutar nuestro fichero `helloworld.py`. Para ello pulsamos el botón verde con triángulo blanco :octicons-triangle-right-24: (en la barra de herramientas) o bien damos a la tecla ++f5++. Veremos que en el panel de «Shell» nos aparece la salida esperada. Lo que está pasando «entre bambalinas» es que el intérprete de Python está recibiendo como entrada el fichero que hemos creado; lo ejecuta y devuelve la salida para que Thonny nos lo muestre en el panel correspondiente. 81 | 82 | ## Depurador { #debugger } 83 | 84 | Nos falta por probar el depurador o «debugger». Aunque su funcionamiento va mucho más allá, de momento nos vamos a quedar en la posibilidad de inspeccionar las variables de nuestro programa. Desafortunadamente `helloworld.py` es muy simple y ni siquiera contiene variables, pero podemos hacer una pequeña modificación al programa para poder incorporarlas: 85 | 86 | ```python linenums="1" 87 | msg = 'Hello, World' 88 | print(msg) 89 | ``` 90 | 91 | Aunque ya lo veremos en profundidad, lo que hemos hecho es añadir una variable `#!python msg` en la ^^línea 1^^ para luego utilizarla al mostrar por pantalla su contenido (^^línea 2^^). Si ahora volvemos a ejecutar nuestro programa veremos que en el panel de variables nos aparece la siguiente información: 92 | 93 | | Name | Value | 94 | | -------------- | ------------------------- | 95 | | `#!python msg` | `#!python 'Hello, World'` | 96 | 97 | También existe la posibilidad, a través del depurador, de ir ejecutando nuestro programa **paso a paso**. Para ello basta con pulsar en el botón que tiene un insecto :octicons-bug-24:. Ahí comienza la sesión de depuración y podemos avanzar instrucción por instrucción usando la tecla ++f7++: 98 | 99 | ![Thonny debug](images/thonny/thonny-debug.png) 100 | 101 | [^1]: La carpeta donde se guarden los archivos de código no es crítico para su ejecución, pero sí es importante mantener un orden y una organización para tener localizados nuestros ficheros y proyectos. 102 | -------------------------------------------------------------------------------- /docs/core/devenv/vscode.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: material/microsoft-visual-studio-code 3 | --- 4 | 5 | # Visual Studio Code { #vscode } 6 | 7 | ![Pencil](images/vscode/pencil.jpg) 8 | (1) 9 | { .annotate } 10 | 11 | 1. :fontawesome-regular-copyright: [Kelly Sikkema](https://unsplash.com/@kellysikkema) (Unsplash) 12 | 13 | [Visual Studio Code](https://code.visualstudio.com/) (también conocido por _VSCode_) es un entorno de desarrollo integrado IDE gratuito y de código abierto que ha ganado mucha relevancia en los últimos años. Permite trabajar fácilmente con multitud de lenguajes de programación y dispone de una gran cantidad de extensiones. 14 | 15 | ## Instalación { #installation } 16 | 17 | VSCode está disponible para distintos sistemas operativos con paquetes autoinstalables que puedes descargar desde [este enlace](https://code.visualstudio.com/download). 18 | 19 | ## Extensiones { #extensions } 20 | 21 | VSCode proporciona muchas extensiones que facilitan la escritura de código **Python :material-language-python:**. Personalmente recomiendo las siguientes: 22 | 23 | - [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) → Soporte para el lenguaje Python con múltiples características. 24 | - [Ruff](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff) → Linter[^1] y formateador de código para Python (extremadamente rápido): [astral.sh/ruff](https://astral.sh/ruff). 25 | - [Mypy Type Checker](https://marketplace.visualstudio.com/items?itemName=ms-python.mypy-type-checker) → Chequeador de tipos estáticos para Python: [mypy-lang.org](https://mypy-lang.org/). 26 | 27 | ## Atajos de teclado { #shortcuts } 28 | 29 | Conocer los atajos de teclado de tu editor favorito es fundamental para mejorar el flujo de trabajo y ser más productivo. Veamos los principales atajos de teclado[^2] de Visual Studio Code: 30 | 31 | === "Ajustes generales" 32 | 33 | | Acción | Atajo | 34 | | --- | --- | 35 | | Abrir paleta de comandos | ++ctrl+shift+p++ | 36 | | Abrir archivo | ++ctrl+p++ | 37 | | Nueva ventana | ++ctrl+shift+n++ | 38 | | Cerrar ventana | ++ctrl+shift+w++ | 39 | 40 | === "Usabilidad" 41 | 42 | | Acción | Atajo | 43 | | --- | --- | 44 | | Crear un nuevo archivo | ++ctrl+n++ | 45 | | Abrir archivo | ++ctrl+o++ | 46 | | Guardar archivo | ++ctrl+s++ | 47 | | Cerrar | ++ctrl+f4++ | 48 | | Panel de problemas | ++ctrl+shift+m++ | 49 | 50 | === "Edición básica" 51 | 52 | | Acción | Atajo | 53 | | --- | --- | 54 | | Cortar línea | ++ctrl+x++ | 55 | | Copiar línea | ++ctrl+c++ | 56 | | Borrar línea | ++ctrl+shift+k++ | 57 | | Insertar línea debajo | ++enter++ | 58 | | Insertar línea encima | ++ctrl+shift+enter++ | 59 | | Buscar en archivo abierto | ++ctrl+f++ | 60 | | Reemplazar | ++ctrl+h++ | 61 | | Línea de comentario | ++ctrl+shift+7++ | 62 | | Bloque de comentario | ++shift+alt+a++ | 63 | | Salto de línea | ++alt+z++ | 64 | | Tabular línea | ++tab++ | 65 | | Destabular línea | ++shift+tab++ | 66 | | Renombrar símbolo | ++f2++ | 67 | 68 | === "Pantalla" 69 | 70 | | Acción | Atajo | 71 | | --- | --- | 72 | | Mostrar barra lateral | ++ctrl+b++ | 73 | | Abrir debug | ++ctrl+shift+d++ | 74 | | Panel de salida | ++ctrl+shift+u++ | 75 | | Control de source | ++ctrl+shift+g++ | 76 | | Extensiones | ++ctrl+shift+x++ | 77 | 78 | !!! tip "macOS" 79 | 80 | En **macOS :material-apple:** sustituye ++ctrl++ por ++command++ 81 | 82 | ## Depurando código { #debugging } 83 | 84 | La **depuración de programas** es el proceso de **identificar y corregir errores de programación**.​ Es conocido también por el término inglés «debugging», cuyo significado es eliminación de bugs (bichos), manera en que se conoce informalmente a los errores de programación. 85 | 86 | Existen varias herramientas de depuración (o _debuggers_). Algunas de ellas en modo texto (terminal) y otras con entorno gráfico (ventanas): 87 | 88 | - La herramienta más extendida en el mundo Python para **depurar en modo texto** es el módulo [pdb](https://docs.python.org/3/library/pdb.html) (The Python Debugger). Viene incluido en la instalación base de Python y es realmente potente. 89 | - Aunque existen varias herramientas para **depurar en entorno gráfico** nos vamos a centrar en **Visual Studio Code**. 90 | 91 | Lo primero será abrir el fichero `fibonacci.py` (como ejemplo) sobre que el que vamos a trabajar: 92 | 93 | ![VSCode Debug Open](images/vscode/vscode-debug-open.png) 94 | 95 | ### Punto de ruptura { #breakpoint } 96 | 97 | A continuación pondremos un **punto de ruptura** (también llamado «breakpoint»). Esto implica que la ejecución se pare en ese punto y viene indicado por un punto rojo :octicons-dot-fill-16:{ .red }. Para ponerlo nos tenemos que acercar a la columna que hay a la izquierda del número de línea y hacer clic. 98 | 99 | En este ejemplo ponemos un punto de ruptura en la ^^línea 10^^: 100 | 101 | ![VSCode Debug Breakpoint](images/vscode/vscode-debug-breakpoint.png) 102 | 103 | También es posible añadir **puntos de ruptura condicionales** pulsando con el botón derecho y luego «Add Conditional Breakpoint»: 104 | 105 | ![VSCode Debug conditional Breakpoint](images/vscode/vscode-debug-cbreakpoint.png) 106 | 107 | ### Lanzar la depuración { #launch-debug } 108 | 109 | Ahora ya podemos lanzar la depuración pulsando la tecla ++f5++. Nos aparecerá el siguiente mensaje en el que dejaremos la opción por defecto «Archivo de Python» y pulsamos ++enter++: 110 | 111 | ![VSCode Debug Config](images/vscode/vscode-debug-config.png) 112 | 113 | Ahora ya se inicia el «modo depuración» y veremos una pantalla similar a la siguiente: 114 | 115 | ![VSCode Debug Zones](images/vscode/vscode-debug-zones.png) 116 | 117 | Zonas de la interfaz en modo depuración: 118 | 119 | 1. Código con barra en amarillo que indica la próxima línea que se va a ejecutar. 120 | 2. Visualización automática de valores de variables. 121 | 3. Visualización personalizada de valores de variables (o expresiones). 122 | 4. Salida de la terminal. 123 | 5. Barra de herramientas para depuración. 124 | 125 | ### Controles para depuración { #debug-controls } 126 | 127 | Veamos con mayor detalle la **barra de herramientas** para depuración: 128 | 129 | ![VSCode Debug Toolbar](images/vscode/vscode-debug-toolbar.png) 130 | 131 | | Acción | Atajo | Significado | 132 | | ------------- | ----------------- | ---------------------------------------------------------------------------------------------- | 133 | | **Continue** | ++f5++ | Continuar la ejecución del programa hasta el próximo punto de ruptura o hasta su finalización. | 134 | | **Step over** | ++f10++ | Ejecutar la siguiente instrucción del programa. | 135 | | **Step into** | ++f11++ | Ejecutar la siguiente instrucción del programa entrando en un contexto inferior. | 136 | | **Step out** | ++shift+f11++ | Ejecutar la siguiente instrucción del programa saliendo a un contexto superior. | 137 | | **Restart** | ++ctrl+shift+f5++ | Reiniciar la depuración del programa. | 138 | | **Stop** | ++shift+f5++ | Detener la depuración del programa. | 139 | 140 | ### Seguimiento de variables { #debug-variables } 141 | 142 | Como hemos indicado previamente, la zona «VARIABLES» ya nos informa automáticamente de los valores de las variables que tengamos en el contexto actual de ejecución: 143 | 144 | ![VSCode Debug Variables](images/vscode/vscode-debug-variables.png) 145 | 146 | Pero también es posible añadir manualmente el seguimiento de otras variables o expresiones personalizadas desde la zona «WATCH»: 147 | 148 | ![VSCode Debug Watch](images/vscode/vscode-debug-watch.png) 149 | 150 | 151 | [^1]: Un «linter» es una herramienta software que permite detectar errores en el código previo a su ejecución. 152 | [^2]: Fuente: [Gastón Danielsen](https://dev.to/gastondanielsen/atajos-de-teclado-shortcuts-en-vscode-430a). 153 | -------------------------------------------------------------------------------- /docs/core/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: material/cog 3 | --- 4 | 5 | # Fundamentos del lenguaje 6 | 7 | Los fundamentos del lenguaje constituyen la base sobre la cual se construye cualquier programa en Python. Antes de abordar conceptos más avanzados, es esencial comprender cómo se estructura un programa, qué reglas sigue la sintaxis del lenguaje, y cómo se declaran y utilizan elementos básicos como variables, operadores, comentarios y bloques de código. Estos fundamentos permiten al programador comunicarse correctamente con la computadora y sentar las bases para desarrollar lógica más compleja. En este bloque, exploraremos los aspectos esenciales del lenguaje Python, proporcionando el conocimiento necesario para empezar a escribir código claro y funcional desde el inicio. 8 | -------------------------------------------------------------------------------- /docs/core/introduction/images/history/ada-lovelace.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/introduction/images/history/ada-lovelace.jpg -------------------------------------------------------------------------------- /docs/core/introduction/images/history/coliseum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/introduction/images/history/coliseum.jpg -------------------------------------------------------------------------------- /docs/core/introduction/images/machine/engine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/introduction/images/machine/engine.jpg -------------------------------------------------------------------------------- /docs/core/introduction/images/python/python.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/introduction/images/python/python.jpg -------------------------------------------------------------------------------- /docs/core/introduction/index.md: -------------------------------------------------------------------------------- 1 | # Introducción 2 | 3 | La programación es el proceso mediante el cual se le da instrucciones a una computadora para que realice tareas específicas. Es una herramienta fundamental en el mundo moderno, ya que permite automatizar procesos, analizar datos, crear aplicaciones y desarrollar soluciones tecnológicas para diversos problemas. Aprender a programar no solo ayuda a entender mejor cómo funcionan las tecnologías que usamos a diario, sino que también desarrolla habilidades de pensamiento lógico y resolución de problemas. Uno de los lenguajes más populares para iniciarse en este campo es Python, gracias a su sintaxis simple y legible. 4 | -------------------------------------------------------------------------------- /docs/core/introduction/machine.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: octicons/cpu-24 3 | --- 4 | 5 | # Hablando con la máquina { #talking-to-machine } 6 | 7 | ![Motor](images/machine/engine.jpg) 8 | (1) 9 | { .annotate } 10 | 11 | 1. :fontawesome-regular-copyright: [Garett Mizunaka](https://unsplash.com/@garett3) (Unsplash) 12 | 13 | Los ordenadores son dispositivos complejos pero están diseñados para hacer una cosa bien: ejecutar aquello que se les indica. La cuestión es cómo indicar a un ordenador lo que queremos que ejecute. Esas indicaciones se llaman técnicamente instrucciones y se expresan en un lenguaje. Podríamos decir que programar consiste en escribir instrucciones para que sean ejecutadas por un ordenador. El lenguaje que utilizamos para ello se denomina lenguaje de programación. 14 | 15 | ## Código máquina { #machine-code } 16 | 17 | Pero aún seguimos con el problema de cómo hacer que un ordenador (o máquina) entienda el lenguaje de programación. A priori podríamos decir que un ordenador sólo entiende un lenguaje muy "simple" denominado [código máquina](https://es.wikipedia.org/wiki/Lenguaje_de_m%C3%A1quina). En este lenguaje se utilizan únicamente los símbolos 0 y 1 en representación de los niveles de tensión alto y bajo, que al fin y al cabo, son los estados que puede manejar un circuito digital. Hablamos de [sistema binario](https://es.wikipedia.org/wiki/Sistema_binario). Si tuviéramos que escribir programas de ordenador en este formato sería una tarea ardua, pero afortunadamente se han ido creando con el tiempo lenguajes de programación intermedios que, posteriormente, son convertidos a código máquina. 18 | 19 | Si intentamos visualizar un programa en código máquina, únicamente obtendríamos una secuencia de ceros y unos: 20 | 21 | ``` 22 | 00001000 00000010 01111011 10101100 10010111 11011001 01000000 01100010 23 | 00110100 00010111 01101111 10111001 01010110 00110001 00101010 00011111 24 | 10000011 11001101 11110101 01001110 01010010 10100001 01101010 00001111 25 | 11101010 00100111 11000100 01110101 11011011 00010110 10011111 01010110 26 | ``` 27 | 28 | ## Ensamblador { #assembly } 29 | 30 | El primer lenguaje de programación que encontramos en esta "escalada" es **ensamblador**. Veamos un [ejemplo de código en ensamblador](https://medium.com/nabucodonosor-editorial/hola-mundo-ensamblado-x86-ff62789ab9b0) del típico programa que se escribe por primera vez, el _«Hello, World»_: 31 | 32 | ```asm 33 | SYS_SALIDA equ 1 34 | 35 | section .data 36 | msg db "Hello, World",0x0a 37 | len equ $ - msg ;longitud de msg 38 | 39 | section .text 40 | global _start ;para el linker 41 | _start: ;marca la entrada 42 | mov eax, 4 ;llamada al sistema (sys_write) 43 | mov ebx, 1 ;descripción de archivo (stdout) 44 | mov ecx, msg ;msg a escribir 45 | mov edx, len ;longitud del mensaje 46 | int 0x80 ;llama al sistema de interrupciones 47 | 48 | fin: mov eax, SYS_SALIDA ;llamada al sistema (sys_exit) 49 | int 0x80 50 | ``` 51 | 52 | Aunque resulte difícil de creer, lo «único» que hace este programa es mostrar en la pantalla de nuestro ordenador la frase «Hello, World», pero además teniendo en cuenta que sólo funcionará para una [arquitectura x86](https://es.wikipedia.org/wiki/X86). 53 | 54 | ## C { #c } 55 | 56 | Aunque el lenguaje ensamblador nos facilita un poco la tarea de desarrollar programas, sigue siendo bastante complicado ya que las instrucciones son muy específicas y no proporcionan una semántica entendible. Uno de los lenguajes que vino a suplir – en parte – estos obstáculos fue [C](). Considerado para muchas personas como un referente en cuanto a los lenguajes de programación, permite hacer uso de instrucciones más claras y potentes. El mismo ejemplo anterior del programa _«Hello, World»_ se escribiría así en lenguaje C: 57 | 58 | ```c 59 | #include 60 | 61 | int main() { 62 | printf("Hello, World"); 63 | return 0; 64 | } 65 | ``` 66 | 67 | ## Python { #python } 68 | 69 | Si seguimos «subiendo» en esta lista de lenguajes de programación, podemos llegar hasta [Python](https://es.wikipedia.org/wiki/Python). Se dice que es un lenguaje de más alto nivel en el sentido de que sus instrucciones son más entendibles por un humano. Veamos cómo se escribiría el programa _«Hello, World»_ en el lenguaje de programación Python: 70 | 71 | ```python 72 | print('Hello, World') 73 | ``` 74 | 75 | ¡Pues así de fácil! Hemos pasado de _código máquina_ (ceros y unos) a código Python en el que se puede entender perfectamente lo que estamos indicando al ordenador. La pregunta que surge es: ¿cómo entiende una máquina lo que tiene que hacer si le pasamos un programa hecho en Python (o cualquier otro lenguaje de alto nivel)? La respuesta es un **compilador**. 76 | 77 | ## Compiladores { #compilers } 78 | 79 | Los [compiladores](https://es.wikipedia.org/wiki/Compilador) son programas que convierten un lenguaje «cualquiera» en _código máquina_. Se pueden ver como traductores, permitiendo a la máquina interpretar lo que queremos hacer. 80 | 81 | ```mermaid 82 | sequenceDiagram 83 | autonumber 84 | actor User 85 | User -->> CPU: Please run: file.py 86 | CPU -->> User: I don't know how! 87 | create participant Compiler 88 | User ->> Compiler: Compile it! 89 | Compiler -->> CPU: Here you have: 10110101011 90 | CPU -->> User: Done! 91 | ``` 92 | 93 | En el caso particular de Python el proceso de compilación genera un código intermedio denominado **bytecode**. 94 | 95 | Si partimos del ejemplo anterior: 96 | 97 | ```python 98 | print('Hello, World') 99 | ``` 100 | 101 | el programa se compilaría[^1] al siguiente «bytecode»: 102 | 103 | ```asm 104 | 0 0 RESUME 0 105 | 106 | 1 2 PUSH_NULL 107 | 4 LOAD_NAME 0 (print) 108 | 6 LOAD_CONST 0 ('Hello, World') 109 | 8 PRECALL 1 110 | 12 CALL 1 111 | 22 RETURN_VALUE 112 | ``` 113 | 114 | A continuación estas instrucciones básicas son ejecutadas por el intérprete de «bytecode» de Python (o máquina virtual)[^2]: 115 | 116 | ```mermaid 117 | graph LR 118 | py[.py] --> compiler[Compiler] 119 | subgraph interpreter[Python Interpreter] 120 | compiler --> bytecode[Bytecode] 121 | bytecode --> vm[Python VM] 122 | end 123 | vm --> exec[Code execution] 124 | bytecode -.-> pyc[.pyc] 125 | ``` 126 | 127 | !!! note "Nota" 128 | 129 | Si queremos ver una diferencia entre un lenguaje compilado como C y un lenguaje «interpretado» como Python es que, aunque ambos realizan un proceso de traducción del código fuente, la compilación de C genera un código objeto que debe ser ejecutado en una segunda fase explícita, mientras que la compilación de Python genera un «bytecode» que se ejecuta (interpreta) de forma «transparente». 130 | 131 | [^1]: Consulta aquí más información sobre el [intérprete de bytecode](https://devguide.python.org/internals/interpreter/). 132 | [^2]: Imagen basada en el artículo [Python bytecode analysis](https://nowave.it/python-bytecode-analysis-1.html). 133 | -------------------------------------------------------------------------------- /docs/core/modularity/files/functions/docs.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/modularity/files/functions/docs.zip -------------------------------------------------------------------------------- /docs/core/modularity/images/exceptions/icecream.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/modularity/images/exceptions/icecream.jpg -------------------------------------------------------------------------------- /docs/core/modularity/images/functions/machine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/modularity/images/functions/machine.jpg -------------------------------------------------------------------------------- /docs/core/modularity/images/functions/sphinx-docs-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/modularity/images/functions/sphinx-docs-dark.png -------------------------------------------------------------------------------- /docs/core/modularity/images/functions/sphinx-docs-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/modularity/images/functions/sphinx-docs-light.png -------------------------------------------------------------------------------- /docs/core/modularity/images/modules/lego.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/modularity/images/modules/lego.jpg -------------------------------------------------------------------------------- /docs/core/modularity/images/oop/aggregation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /docs/core/modularity/images/oop/starwars-droids.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/modularity/images/oop/starwars-droids.jpg -------------------------------------------------------------------------------- /docs/core/modularity/images/oop/things.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/core/modularity/images/oop/things.jpg -------------------------------------------------------------------------------- /docs/core/modularity/index.md: -------------------------------------------------------------------------------- 1 | # Modularidad 2 | 3 | La modularidad en programación es un principio clave que permite dividir un programa en partes más pequeñas, reutilizables y fáciles de mantener. En Python, esta modularidad se logra mediante el uso de funciones, la programación orientada a objetos (POO), el manejo de excepciones y la organización del código en módulos. Las funciones permiten encapsular tareas específicas, la POO facilita la creación de estructuras más complejas a través de clases y objetos, las excepciones ayudan a gestionar errores de manera controlada, y los módulos permiten organizar el código en archivos independientes que pueden ser reutilizados. En este capítulo, exploraremos cómo aplicar estos conceptos para construir programas más claros, escalables y robustos. 4 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Aprende Python 2 | 3 | Aprende el lenguaje de programación ^^Python^^ :material-snake:{ .slide .green } y descubre un **mundo de posibilidades**. 4 | 5 | ![Monty Python](assets/images/monty-python.jpg) 6 | (1) 7 | { .annotate } 8 | 9 | 1. :fontawesome-solid-image: Monty Python. Fuente: [noticiascyl](https://www.noticiascyl.com/t/1700231/monty-python-vuelven-leon) 10 | 11 | El contenido de esta página está organizado en tres grandes bloques: 12 | 13 | - [x] [Fundamentos del lenguaje](/core) 14 | - [x] [Librería estándar](/stdlib) 15 | - [x] [Paquetes de terceros](/third-party) 16 | 17 | --- 18 | 19 | Si quieres **apoyar este proyecto** te dejo dos vías: 20 | 21 |
22 | 23 | - GitHub :simple-github:{ .acc .beat } 24 | 25 | 26 | --- 27 | 28 | [Dando una estrella :material-star-plus:](https://github.com/sdelquin/aprendepython) 29 | 30 | - Buy me a coffee :simple-buymeacoffee:{ .acc .beat } 31 | 32 | --- 33 | 34 | [Pagándome un café :material-hand-coin:](https://buymeacoffee.com/sdelquin) 35 | 36 |
37 | 38 | !!! info "Licencia" 39 | 40 | :fontawesome-brands-creative-commons: :fontawesome-brands-creative-commons-by: Creative Commons Reconocimiento 4.0 Internacional: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/deed.es_ES) 41 | -------------------------------------------------------------------------------- /docs/stdlib/data-access/images/sqlite/hdd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/stdlib/data-access/images/sqlite/hdd.jpg -------------------------------------------------------------------------------- /docs/stdlib/data-access/index.md: -------------------------------------------------------------------------------- 1 | # Acceso a datos 2 | 3 | El acceso a datos es un componente esencial en el desarrollo de aplicaciones, ya que la mayoría de los programas necesitan leer, almacenar o intercambiar información con distintas fuentes. En Python, existen múltiples formas de acceder a datos, ya sea desde archivos locales (como texto, CSV o JSON), bases de datos relacionales (como SQLite o MySQL) o servicios externos a través de APIs. Dominar estas técnicas permite construir aplicaciones más útiles y dinámicas, capaces de interactuar con el entorno y manejar grandes volúmenes de información. En este capítulo, exploraremos las principales herramientas de la librería estándar y métodos para acceder, leer y escribir datos en Python de manera segura y eficiente. 4 | -------------------------------------------------------------------------------- /docs/stdlib/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: material/book-open-page-variant-outline 3 | --- 4 | 5 | # Librería estándar 6 | 7 | La librería estándar de Python es un conjunto extenso de módulos integrados que ofrecen funcionalidades listas para usar, sin necesidad de instalar paquetes adicionales. Estas herramientas cubren una amplia gama de tareas comunes como manejo de archivos, manipulación de fechas y horas, expresiones regulares, operaciones matemáticas, gestión de datos estructurados, acceso a internet, y mucho más. Conocer la librería estándar permite aprovechar al máximo el poder del lenguaje y evitar reinventar la rueda al desarrollar soluciones. En este bloque, exploraremos algunos de los módulos más útiles de la librería estándar de Python y cómo aplicarlos eficazmente en distintos contextos. 8 | -------------------------------------------------------------------------------- /docs/stdlib/text-processing/images/re/floor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/stdlib/text-processing/images/re/floor.jpg -------------------------------------------------------------------------------- /docs/stdlib/text-processing/images/string/ball.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/stdlib/text-processing/images/string/ball.jpg -------------------------------------------------------------------------------- /docs/stdlib/text-processing/index.md: -------------------------------------------------------------------------------- 1 | # Procesamiento de texto 2 | 3 | El procesamiento de texto es una de las aplicaciones más comunes y poderosas de la programación, especialmente en un lenguaje como Python que ofrece herramientas muy versátiles para manipular cadenas de caracteres. Desde tareas simples como buscar y reemplazar palabras, hasta operaciones más complejas como analizar, limpiar o transformar grandes volúmenes de texto, el manejo eficiente de datos textuales es fundamental en áreas como la automatización, el análisis de datos y el procesamiento del lenguaje natural. En este capítulo, aprenderás a trabajar con textos en Python utilizando funciones básicas de cadenas, expresiones regulares y otras técnicas clave para procesar información escrita de forma efectiva. 4 | -------------------------------------------------------------------------------- /docs/stdlib/text-processing/string.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: material/code-string 3 | --- 4 | 5 | # string { #string } 6 | 7 | ![Fork](images/string/ball.jpg) 8 | (1) 9 | { .annotate } 10 | 11 | 1. :fontawesome-regular-copyright: [Steve Johnson](https://unsplash.com/@steve_j) :material-at: [Unsplash](https://unsplash.com) 12 | 13 | El módulo [string](https://docs.python.org/es/3/library/string.html) proporciona **operaciones y constantes** muy útiles para manejo de [cadenas de texto](../../core/datatypes/strings.md), además de distintas estrategias de **formateado de cadenas**. 14 | 15 | ## Constantes { #constants } 16 | 17 | Las constantes definidas en este módulo son las siguientes: 18 | 19 | | Constante | Valor | 20 | | --- | --- | 21 | | `string.ascii_lowercase` | `#!python 'abcdefghijklmnopqrstuvwxyz'` | 22 | | `string.ascii_uppercase` | `#!python 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` | 23 | | `string.ascii_letters` | `#!python 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'` | 24 | | `string.digits` | `#!python '0123456789'` | 25 | | `string.octdigits` | `#!python '01234567'` | 26 | | `string.hexdigits` | `#!python '0123456789abcdefABCDEF'` | 27 | | `string.punctuation` | `#!python '!"#$%&\'()*+,-./:;<=>?@[\\]^_``{|}~'` | 28 | | `string.printable` | `#!python '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_``{|}~ \t\n\r\x0b\x0c'` | 29 | | `string.whitespace` | `#!python ' \t\n\r\x0b\x0c'` | 30 | 31 | !!! exercise "Ejercicio" 32 | 33 | [pypas](https://pypas.es)  :fontawesome-solid-hand-holding-heart:{ .slide } `all-ascii` 34 | 35 | ## Plantillas { #templates } 36 | 37 | El módulo `string` también nos permite usar **plantillas con interpolación de variables**. Algo similar a los [f-strings](../../core/datatypes/strings.md#fstrings) pero con otro tipo de sintaxis. 38 | 39 | Veamos un ejemplo:material-flash: en el que definimos una sencilla plantilla: 40 | 41 | ```pycon 42 | >>> from string import Template#(1)! 43 | 44 | >>> tmpl = Template('$lang is the best programming language in the $place!')#(2)! 45 | ``` 46 | { .annotate } 47 | 48 | 1. Importamos la clase `Template` desde el módulo. 49 | 2. Las variables que queramos interporlar deben ir precedidas del signo dólar `#!python $` 50 | 51 | Ahora podemos aplicar la _interpolación_ (sustitución) de variables con los valores que nos interesen: 52 | 53 | ```pycon 54 | >>> tmpl.substitute(lang='Python', place='World')#(1)! 55 | 'Python is the best programming language in the World!' 56 | 57 | >>> tmpl.substitute({'lang': 'Python', 'place': 'World'})#(2)! 58 | 'Python is the best programming language in the World!' 59 | ``` 60 | { .annotate } 61 | 62 | 1. Podemos usar [argumentos nominales](../../core/modularity/functions.md#kwargs). 63 | 2. Podemos usar un [diccionario](../../core/datastructures/dicts.md). 64 | 65 | Hay que prestar atención cuando el identificador de variable está seguido por algún carácter que, a su vez, puede formar parte del identificador. En este caso hay que utilizar llaves para evitar la ambigüedad. 66 | 67 | En el siguiente ejemplo:material-flash: se muestra un ejemplo de _pluralización_: 68 | 69 | ```pycon hl_lines="1" 70 | >>> tmpl = Template('Congratulations! You won several ${gift}s') 71 | 72 | >>> tmpl.substitute(gift='phone') 73 | 'Congratulations! You won several phones' 74 | ``` 75 | 76 | ### Sustitución segura { #safety-sub } 77 | 78 | En el caso de que alguna de las variables que estamos interpolando no exista o no tenga ningún valor, obtendremos un error al sustituir: 79 | 80 | ```pycon 81 | >>> tmpl = Template('$lang is the best programming language in the $place!') 82 | 83 | >>> tmpl.substitute(lang='Python') 84 | Traceback (most recent call last): 85 | Cell In[2], line 1 86 | tmpl.substitute(lang='Python') 87 | File ~/.local/share/uv/python/cpython-3.13.2-macos-aarch64-none/lib/python3.13/string.py:121 in substitute 88 | return self.pattern.sub(convert, self.template) 89 | File ~/.local/share/uv/python/cpython-3.13.2-macos-aarch64-none/lib/python3.13/string.py:114 in convert 90 | return str(mapping[named]) 91 | KeyError: 'place' 92 | ``` 93 | 94 | Para estos casos el módulo proporciona el método `self_substitute()` que no emite error si alguna variable no es especificada: 95 | 96 | ```pycon 97 | >>> tmpl.safe_substitute(lang='Python') 98 | 'Python is the best programming language in the $place!' 99 | ``` 100 | 101 | ### Casos de uso { #tmpl-use-cases } 102 | 103 | A primera vista podría parecer que este sistema de plantillas no aporta gran ventaja sobre los [f-strings](../../core/datatypes/strings.md#fstrings) que ya hemos visto. Sin embargo hay ocasiones en los que puede resultar muy útil. 104 | 105 | La mayoría de estas escenarios tienen que ver con **la oportunidad** de definir el «string». Si en el momento de crear la plantilla aún no están disponibles las variables de sustitución, podría interesar utilizar la estrategia que nos proporciona este módulo. 106 | 107 | Supongamos un ejemplo:material-flash: en el que tenemos una estructura de «url» y queremos únicamente sustituir una parte de ella. Para no tener que repetir la cadena de texto completa en un «f-string», podríamos seguir este enfoque: 108 | 109 | ```pycon 110 | >>> from string import Template 111 | 112 | >>> urlbase = Template('https://python.org/3/library/$module.html') 113 | 114 | >>> for module in ('string', 're', 'difflib'): 115 | ... url = urlbase.substitute(module=module) 116 | ... print(url) 117 | ... 118 | https://python.org/3/library/string.html 119 | https://python.org/3/library/re.html 120 | https://python.org/3/library/difflib.html 121 | ``` 122 | -------------------------------------------------------------------------------- /docs/third-party/config/index.md: -------------------------------------------------------------------------------- 1 | # Configuraciones 2 | 3 | Las configuraciones en programación se refieren a la personalización y ajustes de los parámetros que permiten que un programa se adapte a diferentes entornos, usuarios o necesidades específicas. Estas configuraciones pueden incluir variables de entorno, archivos de configuración, parámetros de ejecución o ajustes de sistema, y son esenciales para hacer que el software sea flexible y reutilizable. En Python, se pueden gestionar configuraciones de manera eficiente utilizando herramientas como archivos JSON, YAML o INI, que permiten almacenar y leer datos de configuración de forma sencilla. En este capítulo, exploraremos cómo manejar y aplicar configuraciones en Python, asegurando que tus programas sean fácilmente adaptables y mantenibles en diferentes escenarios y entornos de ejecución. 4 | -------------------------------------------------------------------------------- /docs/third-party/config/prettyconf.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: material/image-filter-center-focus-weak 3 | --- 4 | 5 | # Pretty Conf { #prettyconf } 6 | 7 | [`prettyconf`](https://prettyconf.readthedocs.io/en/latest/index.html) es un paquete Python que facilita la creación de ficheros de configuración mediante la parametrización de sus variables. 8 | 9 | Es habitual no incluir credenciales o datos sensibles en el control de versiones de ciertos proyectos de software. Para esto hay varias soluciones, pero la que nos propone `prettyconf` es utilizar una función genérica `config()` que se encargará de recuperar estos datos bien desde _variables de entorno_ o bien desde un fichero `.env`. 10 | 11 | ## Instalación { #install } 12 | 13 | ```console 14 | pip install prettyconf 15 | ``` 16 | 17 | ## Modo de uso { #usage } 18 | 19 | Su modo de uso es muy sencillo: 20 | 21 | === "Valor obligatorio" 22 | 23 | ```python title="settings.py" 24 | from prettyconf import config 25 | 26 | PASSWD = config('PASSWORD')#(1)! 27 | ``` 28 | { .annotate } 29 | 30 | 1. - Se busca `PASSWORD` en ^^variables de entorno^^ o en fichero `.env` 31 | - Si se encuentra, se asigna su valor a la variable `PASSWD` 32 | - Si no se encuentra, se eleva una excepción `UnknownConfiguration`. 33 | 34 | === "Valor opcional" 35 | 36 | ```python title="settings.py" 37 | from prettyconf import config 38 | 39 | UNAME = config('USERNAME', default='guido')#(1)! 40 | ``` 41 | { .annotate } 42 | 43 | 1. - Se busca `USERNAME` en ^^variables de entorno^^ o en fichero `.env` 44 | - Si se encuentra, se asigna su valor a la variable `UNAME` 45 | - Si no se encuentra, se asigna el valor por defecto `#!python 'guido'` a `UNAME` 46 | 47 | ## Ficheros .env { #dotenv } 48 | 49 | Aunque también existe la posibilidad de definir los valores mediate _variables de entorno_ suele ser habitual utilizar un fichero de configuración `.env` para ello. 50 | 51 | Su estructura es realmente simple: 52 | 53 | ```ini title=".env" 54 | USERNAME="thisisme" 55 | PASSWORD=verycomplicated#(1)! 56 | MESSAGE="Talk is cheap, show me the code" 57 | ``` 58 | { .annotate } 59 | 60 | 1. Aunque podría ir sin comillas dobles, lo más fácil —para evitar errores— es ponerlas siempre. 61 | 62 | !!! danger "Fuera de control de versiones" 63 | 64 | Es crucial dejar fuera del **control de versiones** el archivo `.env` mediante su inclusión en el fichero `.gitignore`. 65 | 66 | ## Conversiones { #casts } 67 | 68 | Por defecto, cualquier valor que le demos a una variable mediante `prettyconf` se interpretará como una **cadena de texto** (`#!python str`). 69 | 70 | Pero es posible indicar **conversiones explícitas** en la propia llamada a la función: 71 | 72 |
73 | | Conversión | Explicación | Valor `ITEM` | Ejemplo | 74 | | --- | --- | --- | --- | 75 | | `config.boolean` | Convierte a [booleano](../../core/datatypes/numbers.md#booleans)(1) | `#!python 'On'` | `#!python config(ITEM, cast=config.boolean)` :material-arrow-right-box: `#!python True` 76 | | `config.list` | Convierte a [lista](../../core/datastructures/lists.md)(2) | `#!python 'A,B,C'` | `#!python config(ITEM, cast=config.list)` :material-arrow-right-box: `#!python ['A','B','C']` 77 | | `config.tuple` | Convierte a [tupla](../../core/datastructures/tuples.md)(3) | `#!python 'A,B,C'` | `#!python config(ITEM, cast=config.tuple)` :material-arrow-right-box: `#!python ('A','B','C')` 78 | | `config.json` | Convierte a objeto Python(4) | `#!python '{"a": [1, 2], "b": [3, 4]}'` | `#!python config(ITEM, cast=config.json)` :material-arrow-right-box: `#!python {'a': [1, 2], 'b': [3, 4]}` 79 |
80 | 1. Ejemplos: `On|Off`, `1|0`, `yes|no`, `true|false`, `t|f` 81 | 2. Desde cadenas de texto separadas por **comas**. 82 | 3. Desde cadenas de texto separadas por **comas**. 83 | 4. Desde cadena de texto con objeto JSON. 84 | 85 | ### Conversiones personalizadas { #custom-casts } 86 | 87 | Además de las conversiones predefinidas es posible crear conversiones personalizadas mediante una función propia. 88 | 89 | Por ejemplo:material-flash:, supongamos una configuración que almacena **latitud y longitud** de un determinado lugar (_geolocalización_): 90 | 91 | ```python title="settings.py" 92 | def geoloc(loc: str) -> tuple[float, float]: 93 | return tuple(float(v) for v in loc.split(',')) 94 | 95 | TEIDE_GPS = config('TEIDE_GPS', cast=geoloc) 96 | ``` 97 | 98 | Con esto podríamos «leer» un fichero de configuración tipo: 99 | 100 | ```ini title=".env" 101 | TEIDE_GPS="28.2723364,-16.6631076"#(1)! 102 | ``` 103 | { .annotate } 104 | 105 | 1. Esto se convertiría en una tupla: `#!python (28.2723364, -16.6631076)` (_cuyos valores ya estarían en formato flotante_). 106 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/jupyter/equations.tex: -------------------------------------------------------------------------------- 1 | % Ecuación 1 2 | $$ 3 | \int_a^b f'(x)dx = f(b) - f(a) 4 | $$ 5 | 6 | % Ecuación 2 7 | $$ 8 | t' = t \frac{1}{\sqrt{1 - \frac{v^2}{c^2}}} 9 | $$ 10 | 11 | % Ecuación 3 12 | $$ 13 | \Big[ 14 | M \frac{\partial}{\partial M} + 15 | \beta(g) \frac{\partial}{\partial g} + 16 | \eta \gamma 17 | \Big] 18 | G^n(x_1, x_2, \dots, x_n; M, g) = 0 19 | $$ 20 | 21 | % Ecuación 4 22 | $$ 23 | R_{00} \approx 24 | -\frac{1}{2} 25 | \sum_i 26 | \frac{\partial^2 h_{00}}{\partial(x^i)^2} 27 | = 28 | \frac{4\pi G}{c^2} 29 | (\rho c^2) 30 | \Rightarrow 31 | \bigtriangledown^2 \phi_g 32 | = 33 | 4\pi G \rho 34 | $$ 35 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/jupyter/timeit.py: -------------------------------------------------------------------------------- 1 | print('Poisson') 2 | %timeit numpy.random.poisson(size=100) 3 | %timeit numpy.random.poisson(size=10_000) 4 | %timeit numpy.random.poisson(size=1_000_000) 5 | 6 | print('Uniform') 7 | %timeit numpy.random.uniform(size=100) 8 | %timeit numpy.random.uniform(size=10_000) 9 | %timeit numpy.random.uniform(size=1_000_000) 10 | 11 | print('Logistic') 12 | %timeit numpy.random.logistic(size=100) 13 | %timeit numpy.random.logistic(size=10_000) 14 | %timeit numpy.random.logistic(size=1_000_000) 15 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/matplotlib/bmw_plot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import pandas as pd 3 | 4 | df = pd.read_csv('pypi/datascience/files/bmw-clean.csv') 5 | 6 | fig, ax = plt.subplots(figsize=(6, 4), dpi=100) 7 | 8 | x = df['mpg'] 9 | y = df['price'] 10 | colors = df['year'] 11 | 12 | p = ax.scatter( 13 | x, 14 | y, 15 | s=30, 16 | c=colors, 17 | cmap='plasma_r', 18 | vmin=colors.min(), 19 | vmax=colors.max(), # normalización de colores 20 | alpha=0.7, 21 | edgecolors='none', 22 | ) 23 | 24 | cb = fig.colorbar(p, ax=ax, label='Año', extend='max') 25 | cb.outline.set_visible(False) 26 | 27 | ax.set_xlabel('Consumo (mpg)') 28 | ax.set_ylabel('Precio (€)') 29 | 30 | ax.spines['right'].set_visible(False) 31 | ax.spines['top'].set_visible(False) 32 | 33 | fig.tight_layout() 34 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/matplotlib/euro_dollar.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import pandas as pd 3 | 4 | df = pd.read_csv('pypi/datascience/files/euro-dollar-clean.csv') 5 | eurodollar = df.groupby(['year', 'month'])['dollar'].mean().unstack() 6 | 7 | fig, ax = plt.subplots(figsize=(6, 4), dpi=100) 8 | 9 | text_colors = ('black', 'white') 10 | im = ax.imshow(eurodollar, cmap='Blues') 11 | cbar = fig.colorbar(im, ax=ax, extend='both') 12 | cbar.outline.set_visible(False) 13 | 14 | x = eurodollar.columns 15 | y = eurodollar.index 16 | 17 | # Mostrar las etiquetas. El color del texto cambia en función de su normalización 18 | for i in range(len(y)): 19 | for j in range(len(x)): 20 | value = eurodollar.iloc[i, j] 21 | text_color = text_colors[int(im.norm(value) > 0.5)] # color etiqueta 22 | ax.text(j, i, f'{value:.2f}', color=text_color, va='center', ha='center', size=6) 23 | 24 | # Formateo de los ejes 25 | ax.set_xticks(range(len(x))) 26 | ax.set_xticklabels( 27 | ['ENE', 'FEB', 'MAR', 'ABR', 'MAY', 'JUN', 'JUL', 'AGO', 'SEP', 'OCT', 'NOV', 'DIC'], 28 | rotation=90, 29 | ) 30 | ax.set_yticks(range(len(y))) 31 | ax.set_yticklabels(y) 32 | ax.invert_yaxis() 33 | 34 | ax.spines[:].set_visible(False) 35 | 36 | fig.tight_layout() 37 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/matplotlib/medals.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/files/matplotlib/medals.xlsx -------------------------------------------------------------------------------- /docs/third-party/data-science/files/matplotlib/mwh-spain-2021-clean.csv: -------------------------------------------------------------------------------- 1 | Fecha,MWh 2 | 2021-01-02,48.72 3 | 2021-01-03,46.93 4 | 2021-01-04,59.85 5 | 2021-01-05,67.55 6 | 2021-01-06,70.6 7 | 2021-01-07,88.93 8 | 2021-01-08,94.99 9 | 2021-01-09,80.66 10 | 2021-01-10,66.27 11 | 2021-01-11,82.45 12 | 2021-01-12,84.25 13 | 2021-01-13,89.94 14 | 2021-01-14,87.25 15 | 2021-01-15,78.42 16 | 2021-01-16,67.72 17 | 2021-01-17,64.51 18 | 2021-01-18,82.08 19 | 2021-01-19,76.47 20 | 2021-01-20,51.66 21 | 2021-01-21,41.64 22 | 2021-01-22,41.97 23 | 2021-01-23,27.5 24 | 2021-01-24,28.73 25 | 2021-01-25,59.42 26 | 2021-01-26,65.98 27 | 2021-01-27,59.77 28 | 2021-01-28,55.39 29 | 2021-01-29,47.39 30 | 2021-01-30,4.19 31 | 2021-01-31,1.42 32 | 2021-02-01,11.9 33 | 2021-02-02,26.34 34 | 2021-02-03,36.26 35 | 2021-02-04,52.2 36 | 2021-02-05,50.99 37 | 2021-02-06,36.02 38 | 2021-02-07,12.58 39 | 2021-02-08,8.3 40 | 2021-02-09,7.1 41 | 2021-02-10,26.26 42 | 2021-02-11,48.0 43 | 2021-02-12,36.94 44 | 2021-02-13,36.9 45 | 2021-02-14,13.38 46 | 2021-02-15,14.85 47 | 2021-02-16,23.98 48 | 2021-02-17,41.93 49 | 2021-02-18,36.18 50 | 2021-02-19,22.27 51 | 2021-02-20,2.19 52 | 2021-02-21,5.67 53 | 2021-02-22,39.39 54 | 2021-02-23,43.65 55 | 2021-02-24,24.82 56 | 2021-02-25,45.83 57 | 2021-02-26,46.09 58 | 2021-02-27,29.24 59 | 2021-02-28,18.53 60 | 2021-03-01,42.24 61 | 2021-03-02,52.67 62 | 2021-03-03,53.24 63 | 2021-03-04,55.43 64 | 2021-03-05,52.45 65 | 2021-03-06,45.07 66 | 2021-03-07,47.05 67 | 2021-03-08,54.43 68 | 2021-03-09,56.88 69 | 2021-03-10,55.87 70 | 2021-03-11,40.76 71 | 2021-03-12,40.16 72 | 2021-03-13,27.75 73 | 2021-03-14,24.54 74 | 2021-03-15,47.59 75 | 2021-03-16,34.51 76 | 2021-03-17,17.35 77 | 2021-03-18,32.77 78 | 2021-03-19,29.66 79 | 2021-03-20,22.19 80 | 2021-03-21,30.28 81 | 2021-03-22,55.79 82 | 2021-03-23,64.47 83 | 2021-03-24,64.82 84 | 2021-03-25,66.35 85 | 2021-03-26,60.31 86 | 2021-03-27,41.11 87 | 2021-03-28,38.6 88 | 2021-03-29,45.69 89 | 2021-03-30,53.53 90 | 2021-03-31,55.16 91 | 2021-04-01,52.12 92 | 2021-04-02,51.0 93 | 2021-04-03,35.18 94 | 2021-04-04,27.74 95 | 2021-04-05,44.55 96 | 2021-04-06,55.97 97 | 2021-04-07,66.11 98 | 2021-04-08,69.78 99 | 2021-04-09,71.87 100 | 2021-04-10,65.01 101 | 2021-04-11,52.01 102 | 2021-04-12,63.04 103 | 2021-04-13,75.5 104 | 2021-04-14,73.96 105 | 2021-04-15,68.19 106 | 2021-04-16,68.93 107 | 2021-04-17,64.19 108 | 2021-04-18,64.54 109 | 2021-04-19,79.03 110 | 2021-04-20,78.58 111 | 2021-04-21,79.6 112 | 2021-04-22,74.41 113 | 2021-04-23,68.56 114 | 2021-04-24,57.31 115 | 2021-04-25,61.09 116 | 2021-04-26,75.99 117 | 2021-04-27,77.95 118 | 2021-04-28,74.4 119 | 2021-04-29,74.67 120 | 2021-04-30,79.29 121 | 2021-05-01,59.36 122 | 2021-05-02,61.39 123 | 2021-05-03,73.54 124 | 2021-05-04,81.27 125 | 2021-05-05,75.71 126 | 2021-05-06,73.11 127 | 2021-05-07,73.5 128 | 2021-05-08,47.25 129 | 2021-05-09,10.53 130 | 2021-05-10,59.26 131 | 2021-05-11,54.05 132 | 2021-05-12,53.04 133 | 2021-05-13,59.8 134 | 2021-05-14,71.53 135 | 2021-05-15,43.16 136 | 2021-05-16,26.65 137 | 2021-05-17,76.82 138 | 2021-05-18,77.65 139 | 2021-05-19,77.11 140 | 2021-05-20,79.79 141 | 2021-05-21,69.54 142 | 2021-05-22,66.41 143 | 2021-05-23,68.67 144 | 2021-05-24,67.4 145 | 2021-05-25,76.64 146 | 2021-05-26,80.72 147 | 2021-05-27,86.23 148 | 2021-05-28,88.95 149 | 2021-05-29,81.77 150 | 2021-05-30,71.93 151 | 2021-05-31,88.08 152 | 2021-06-01,86.56 153 | 2021-06-02,84.85 154 | 2021-06-03,79.8 155 | 2021-06-04,80.59 156 | 2021-06-05,76.17 157 | 2021-06-06,68.87 158 | 2021-06-07,79.69 159 | 2021-06-08,82.33 160 | 2021-06-09,81.6 161 | 2021-06-10,83.34 162 | 2021-06-11,82.53 163 | 2021-06-12,77.6 164 | 2021-06-13,79.2 165 | 2021-06-14,88.47 166 | 2021-06-15,90.95 167 | 2021-06-16,94.63 168 | 2021-06-17,93.0 169 | 2021-06-18,92.67 170 | 2021-06-19,87.22 171 | 2021-06-20,52.63 172 | 2021-06-21,82.55 173 | 2021-06-22,89.53 174 | 2021-06-23,89.88 175 | 2021-06-24,85.73 176 | 2021-06-25,86.57 177 | 2021-06-26,83.99 178 | 2021-06-27,64.21 179 | 2021-06-28,86.44 180 | 2021-06-29,93.49 181 | 2021-06-30,93.89 182 | 2021-07-01,92.44 183 | 2021-07-02,99.8 184 | 2021-07-03,94.23 185 | 2021-07-04,79.43 186 | 2021-07-05,93.85 187 | 2021-07-06,93.57 188 | 2021-07-07,98.72 189 | 2021-07-08,93.67 190 | 2021-07-09,93.5 191 | 2021-07-10,90.48 192 | 2021-07-11,90.77 193 | 2021-07-12,86.68 194 | 2021-07-13,94.39 195 | 2021-07-14,84.46 196 | 2021-07-15,87.18 197 | 2021-07-16,87.32 198 | 2021-07-17,90.95 199 | 2021-07-18,74.19 200 | 2021-07-19,98.8 201 | 2021-07-20,101.82 202 | 2021-07-21,106.57 203 | 2021-07-22,101.52 204 | 2021-07-23,95.89 205 | 2021-07-24,92.02 206 | 2021-07-25,93.2 207 | 2021-07-26,99.52 208 | 2021-07-27,99.05 209 | 2021-07-28,95.57 210 | 2021-07-29,98.83 211 | 2021-07-30,95.37 212 | 2021-07-31,61.09 213 | 2021-08-01,76.89 214 | 2021-08-02,103.07 215 | 2021-08-03,106.27 216 | 2021-08-04,105.24 217 | 2021-08-05,101.6 218 | 2021-08-06,97.22 219 | 2021-08-07,65.64 220 | 2021-08-08,85.29 221 | 2021-08-09,106.74 222 | 2021-08-10,111.88 223 | 2021-08-11,113.99 224 | 2021-08-12,115.83 225 | 2021-08-13,117.29 226 | 2021-08-14,114.63 227 | 2021-08-15,110.02 228 | 2021-08-16,88.92 229 | 2021-08-17,89.5 230 | 2021-08-18,105.4 231 | 2021-08-19,113.4 232 | 2021-08-20,117.14 233 | 2021-08-21,110.14 234 | 2021-08-22,100.51 235 | 2021-08-23,99.76 236 | 2021-08-24,102.06 237 | 2021-08-25,116.73 238 | 2021-08-26,122.76 239 | 2021-08-27,118.99 240 | 2021-08-28,110.22 241 | 2021-08-29,102.03 242 | 2021-08-30,124.45 243 | 2021-08-31,130.53 244 | 2021-09-01,132.47 245 | 2021-09-02,140.23 246 | 2021-09-03,137.7 247 | 2021-09-04,134.89 248 | 2021-09-05,128.7 249 | 2021-09-06,132.65 250 | 2021-09-07,127.36 251 | 2021-09-08,135.65 252 | 2021-09-09,141.71 253 | 2021-09-10,152.32 254 | 2021-09-11,150.78 255 | 2021-09-12,144.18 256 | 2021-09-13,154.16 257 | 2021-09-14,153.43 258 | 2021-09-15,172.78 259 | 2021-09-16,188.18 260 | 2021-09-17,166.29 261 | 2021-09-18,159.37 262 | 2021-09-19,146.57 263 | 2021-09-20,156.75 264 | 2021-09-21,150.26 265 | 2021-09-22,175.87 266 | 2021-09-23,165.19 267 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/matplotlib/mwh_spain.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import pandas as pd 3 | from matplotlib.dates import DateFormatter, DayLocator 4 | 5 | df = pd.read_csv( 6 | 'pypi/datascience/files/mwh-spain-2021-clean.csv', 7 | parse_dates=['Fecha'], 8 | index_col='Fecha', 9 | ) 10 | 11 | fig, ax = plt.subplots(figsize=(6, 3), dpi=100) 12 | 13 | x = df.index 14 | y = df.iloc[:, 0] 15 | 16 | ax.plot(x, y, color='goldenrod') 17 | plt.fill_between(x, y, alpha=0.2, color='gold') # área 18 | 19 | # Anotación del valor máximo 20 | xmax, ymax = y.idxmax(), y.max() 21 | ax.annotate( 22 | f'max={ymax}€', 23 | xy=(xmax, ymax), 24 | xytext=(-75, 0), 25 | textcoords='offset points', 26 | ha='center', 27 | va='center', 28 | arrowprops=dict(facecolor='black', shrink=0.05, width=3), 29 | ) 30 | 31 | # Estilos para el eje x 32 | ax.set_xlim(x.min(), x.max()) 33 | ax.xaxis.set_major_locator(DayLocator(interval=8)) 34 | ax.xaxis.set_major_formatter(DateFormatter('%d %b')) 35 | ax.tick_params(axis='x', which='major', rotation=90) 36 | 37 | # Estilos para el eje y 38 | ax.set_ylim(0, 200) 39 | 40 | # Rejilla 41 | ax.grid(color='lightgray', linestyle='dashed') 42 | 43 | ax.spines['top'].set_visible(False) 44 | ax.spines['right'].set_visible(False) 45 | 46 | fig.tight_layout() 47 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/matplotlib/pokemon_speed.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import pandas as pd 3 | 4 | df = pd.read_csv('pypi/datascience/files/pokemon.csv') 5 | 6 | fig, ax = plt.subplots(figsize=(6, 4), dpi=100) 7 | bins = range(0, 161, 10) 8 | ax.hist(df['Speed'], rwidth=0.8, color='tomato', bins=bins, zorder=2) 9 | ax.yaxis.grid(color='mistyrose') 10 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/matplotlib/soften_wave.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | x = np.linspace(0, 2 * np.pi, 1000) 5 | alpha = 0.7 6 | beta = 10 7 | y = np.e ** (-alpha * x) * np.sin(beta * x) 8 | 9 | fig, ax = plt.subplots(figsize=(8, 4), dpi=100) 10 | ax.plot(x, y, color='olivedrab', linewidth=3) 11 | ax.grid(color='lightgray') 12 | 13 | fig.tight_layout() 14 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/matplotlib/tiobe-2020-clean.csv: -------------------------------------------------------------------------------- 1 | Language,Ratings 2 | C,17.38 3 | Java,11.96 4 | Python,11.72 5 | C++,7.56 6 | C#,3.95 7 | Visual Basic,3.84 8 | JavaScript,2.2 9 | PHP,1.99 10 | R,1.9 11 | Groovy,1.84 12 | Assembly language,1.64 13 | SQL,1.61 14 | Swift,1.43 15 | Go,1.41 16 | Ruby,1.3 17 | MATLAB,1.15 18 | Perl,1.02 19 | Objective-C,1.0 20 | Delphi/Object Pascal,0.79 21 | Classic Visual Basic,0.79 22 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/matplotlib/tiobe_2020.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import pandas as pd 4 | 5 | df = pd.read_csv('pypi/datascience/files/tiobe-2020-clean.csv', index_col='Language') 6 | 7 | fig, ax = plt.subplots(figsize=(6, 4), dpi=100) 8 | 9 | bar_width = 0.30 10 | x = np.arange(df.index.size) 11 | 12 | barplot = ax.bar(x, df['Ratings'], zorder=2, color='turquoise', alpha=0.7) 13 | 14 | ax.set_xticks(x) 15 | ax.set_xticklabels(df.index, rotation=90) 16 | 17 | ax.yaxis.grid(color='lightgray') 18 | ax.set_ylabel('Rating TIOBE (%)') 19 | 20 | ax.spines['right'].set_visible(False) 21 | ax.spines['top'].set_visible(False) 22 | 23 | fig.tight_layout() 24 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/numpy/diag.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | np.diag(range(50)) 4 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/numpy/diag_transform.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | matrix = np.random.randint(0, 100, size=(10, 10)) 4 | 5 | matrix[np.diag_indices(matrix.shape[0])] = 50 6 | matrix[matrix > 50] = 100 7 | matrix[matrix < 50] = 0 8 | 9 | print(matrix) 10 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/numpy/euler_product.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | import numpy as np 4 | 5 | theta = 2 * math.pi 6 | k = 20 7 | 8 | values = np.arange(1, k, dtype='float64') 9 | z = np.cos(theta / np.power(2, values)) 10 | 11 | lhs = np.sin(theta) / theta 12 | rhs = np.prod(z) 13 | 14 | print(math.isclose(lhs, rhs)) 15 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/numpy/flip_powers.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | A = np.array([[4, 5, -1], [-3, -4, 1], [-3, -4, 0]]) 4 | 5 | for power in range(2, 129): 6 | print(np.linalg.matrix_power(A, power)) 7 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/numpy/identity_equation.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | matrix = np.array([[1, 2], [3, 5]]) 4 | identity = np.identity(2) 5 | zeros = np.zeros((2, 2)) 6 | 7 | result = np.linalg.matrix_power(matrix, 2) - 6 * matrix - identity 8 | 9 | np.array_equal(result, zeros) 10 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/numpy/lineq.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | # AX = B 4 | A = np.array([[1, 4, -1], [5, -2, 1], [2, -2, 1]]) 5 | B = np.array([8, 4, 1]).reshape(3, -1) 6 | 7 | np.linalg.solve(A, B) 8 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/numpy/np_matrix.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | array1 = np.array([88, 23, 39, 41]) 4 | array2 = np.array([[76.4, 21.7, 38.4], [41.2, 52.8, 68.9]]) 5 | array3 = np.array([[12], [4], [9], [8]]) 6 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/numpy/np_odds.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | values = np.arange(10, 22).reshape(3, 4) 4 | print(values[values % 2 != 0]) 5 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/numpy/np_random.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | float_values = np.linspace(1, 10, 100).reshape(20, 5) 4 | normal_dist = np.random.normal(1, 2, size=128) 5 | quiniela = np.random.choice(list('1X2'), size=15, p=[0.5, 0.3, 0.2]) 6 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/numpy/np_transform.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | matrix = np.array([[17, 12, 31], [49, 11, 51], [21, 31, 62], [63, 75, 22]]) 4 | 5 | print('Matrix:') 6 | print(matrix) 7 | print() 8 | 9 | last_row = matrix[-1] 10 | matrix2 = np.delete(matrix, -1, axis=0) 11 | last_row_as_column = last_row.reshape(3, -1) 12 | matrix2 = np.append(matrix2, last_row_as_column, axis=1) 13 | 14 | print('Matrix 2:') 15 | print(matrix2) 16 | print() 17 | 18 | matrix3 = matrix2 19 | matrix3[1] = matrix3[1, 0] 20 | matrix3[:, -1] = matrix3[0, -1] 21 | 22 | print('Matrix 3:') 23 | print(matrix3) 24 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/numpy/transpose.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | A = np.array([[-1, 2, 1], [3, 0, 1]]) 4 | B = np.array([[4, 0, -1], [-2, 1, 0]]) 5 | 6 | print('(A + B)^T = A^T + B^T??', np.array_equal((A + B).T, A.T + B.T)) 7 | 8 | print('(3A)^T = 3A^T??', np.array_equal((3 * A).T, 3 * A.T)) 9 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/numpy/vectorize.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | vect_avg = np.vectorize(lambda a, b: (a + b) / 2) 4 | 5 | A = np.random.uniform(0, 1000, size=(20, 20)) 6 | B = np.random.uniform(0, 1000, size=(20, 20)) 7 | 8 | %timeit vect_avg(A, B) 9 | 10 | %timeit (A + B) / 2 11 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/above_mean.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | democan = pd.read_csv('democan.csv', index_col='Island') 4 | 5 | mean_population = democan['Population'].mean() 6 | mask = democan['Population'] > mean_population 7 | islands = democan[mask].index.to_list() 8 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/comunidades.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | URL = 'https://es.wikipedia.org/wiki/Comunidad_aut%C3%B3noma' 4 | 5 | tables = pd.read_html(URL) 6 | 7 | df_area = tables[3] 8 | df_area = df_area.iloc[:-1, 1:3] 9 | df_area.columns = ('Comunidad', 'Superficie') 10 | df_area['Superficie'] = ( 11 | df_area['Superficie'].str.replace(r'\s+', '', regex=True).astype('int') 12 | ) 13 | 14 | df_population = tables[4] 15 | df_population = df_population.iloc[:-1, 1:3] 16 | df_population.columns = ('Comunidad', 'Población') 17 | df_population['Población'] = ( 18 | df_population['Población'].str.replace(r'\s+', '', regex=True).astype('int') 19 | ) 20 | 21 | df = pd.merge(df_area, df_population) 22 | df['Densidad'] = df['Población'] / df['Superficie'] 23 | 24 | print(df.sort_values('Densidad', ascending=False)) 25 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/create_dataframe.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | islands = [ 4 | 'El Hierro', 5 | 'Fuerteventura', 6 | 'Gran Canaria', 7 | 'La Gomera', 8 | 'Lanzarote', 9 | 'La Palma', 10 | 'Tenerife', 11 | ] 12 | populations = [11423, 120021, 853262, 21798, 156112, 83439, 931646] 13 | areas = [268.71, 1665.74, 1560.10, 369.76, 888.07, 708.32, 2034.38] 14 | provinces = ['TF', 'LP', 'LP', 'TF', 'LP', 'TF', 'TF'] 15 | 16 | data = dict(Island=islands, Population=populations, Area=areas, Province=provinces) 17 | 18 | democan = pd.DataFrame(data) 19 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/create_series.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | import pandas as pd 4 | 5 | pd.Series(range(1, 27), list(string.ascii_uppercase)) 6 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/democan.csv: -------------------------------------------------------------------------------- 1 | Island,Population,Area,Province 2 | El Hierro,11423,268.71,TF 3 | Fuerteventura,120021,1665.74,LP 4 | Gran Canaria,853262,1560.10,LP 5 | La Gomera,21798,369.76,TF 6 | Lanzarote,156112,888.07,LP 7 | La Palma,83439,708.32,TF 8 | Tenerife,931646,2034.38,TF 9 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/df_access.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | democan = pd.read_csv('democan.csv', index_col='Island') 4 | 5 | ds1 = democan.loc[['El Hierro', 'La Gomera']] 6 | ds2 = democan.loc[:, 'Province'] 7 | ds3 = democan.iloc[::2, 1] 8 | ds4 = democan[democan['Area'] > 1000] 9 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/df_oasis.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | df = pd.read_csv('oasis.csv') 4 | df['album_release_date'] = pd.to_datetime(df['album_release_date']) 5 | album_names = df.query('2000 <= album_release_date <= 2005')['album_name'] 6 | print(album_names.unique()) 7 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/grants.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | democan = pd.read_csv('democan.csv', index_col='Island') 4 | 5 | 6 | def handle_grants(row): 7 | area, population = row['Area'], row['Population'] 8 | if area < 1000: 9 | grant = 0.3 * population 10 | else: 11 | grant = 0.2 * population 12 | return grant 13 | 14 | 15 | democan['Grant'] = democan.apply(handle_grants, axis=1) 16 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/index_dataframe.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | # ============================================================================== 4 | # Creación del DataFrame 5 | # ============================================================================== 6 | 7 | islands = [ 8 | 'El Hierro', 9 | 'Fuerteventura', 10 | 'Gran Canaria', 11 | 'La Gomera', 12 | 'Lanzarote', 13 | 'La Palma', 14 | 'Tenerife', 15 | ] 16 | populations = [11423, 120021, 853262, 21798, 156112, 83439, 931646] 17 | areas = [268.71, 1665.74, 1560.10, 369.76, 888.07, 708.32, 2034.38] 18 | provinces = ['TF', 'LP', 'LP', 'TF', 'LP', 'TF', 'TF'] 19 | 20 | data = dict(Island=islands, Population=populations, Area=areas, Province=provinces) 21 | 22 | democan = pd.DataFrame(data) 23 | 24 | # ============================================================================== 25 | # Ejercicio 26 | # ============================================================================== 27 | 28 | democan.set_index('Island') 29 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/load_dataframe.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | democan = pd.read_csv('democan.csv', index_col=0) 4 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/pop_density.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | democan = pd.read_csv('democan.csv', index_col='Island') 4 | 5 | democan['Density'] = democan['Population'] / democan['Area'] 6 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/pop_percentage.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | democan = pd.read_csv('democan.csv', index_col='Island') 4 | 5 | total_population = democan['Population'].sum() 6 | provinces_by_pop = democan.groupby('Province')['Population'].sum() 7 | pop_percentages = provinces_by_pop / total_population 8 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/recoding.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | democan = pd.read_csv('democan.csv', index_col='Island') 4 | 5 | recoding = {'LPGC': 'Las Palmas de Gran Canaria', 'SCTF': 'Santa Cruz de Tenerife'} 6 | democan.replace(recoding, inplace=True) 7 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/smallest_density.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | democan = pd.read_csv('democan.csv', index_col='Island') 4 | 5 | democan['Density'] = democan['Population'] / democan['Area'] 6 | democan.nsmallest(3, 'Density') 7 | -------------------------------------------------------------------------------- /docs/third-party/data-science/files/pandas/tech.csv: -------------------------------------------------------------------------------- 1 | Company,Revenue,Employees,City,Country 2 | Amazon,574.8,1525000,Seattle,United States 3 | Apple,394.33,164000,Cupertino,United States 4 | Alphabet,282.84,190234,Mountain View,United States 5 | Samsung Electronics,234.13,270372,Suwon,South Korea 6 | Foxconn,222.54,767062,New Taipei City,Taiwan 7 | Microsoft,198.27,221000,Redmond,United States 8 | Jingdong,152.8,310000,Beijing,China 9 | Alibaba,130.35,204891,Yuhang,China 10 | AT&T,122.4,149900,Dallas,United States 11 | Meta,116.61,86482,Menlo Park,United States 12 | Deutsche Telekom,112.0,205000,Bonn,Germany 13 | Dell Technologies,102.30,133000,Round Rock,United States 14 | Huawei,95.49,207000,Shenzhen,China 15 | Sony,85.25,112994,Tokyo,Japan 16 | Tencent,82.44,108436,Shenzhen,China 17 | Hitachi,80.39,322525,Tokyo,Japan 18 | TSMC,76.02,73090,New Taipei City,Taiwan 19 | LG Electronics,64.95,74000,Seoul,South Korea 20 | Intel,63.05,131900,Santa Clara,United States 21 | HP Inc.,62.98,53000,Palo Alto,United States 22 | Lenovo,61.95,71500,Hong Kong,Hong Kong 23 | Panasonic,61.90,233391,Osaka,Japan 24 | Accenture,61.59,721000,Dublin,Ireland 25 | Nvidia,60.93,29600,Santa Clara,United States 26 | IBM,60.53,303100,Armonk,United States 27 | -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/basic-plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/basic-plot.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/canaryislands-googlemaps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/canaryislands-googlemaps.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/google-colab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/google-colab.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/jupyter-browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/jupyter-browser.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/jupyter-busy-kernel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/jupyter-busy-kernel.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/jupyter-cell-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/jupyter-cell-menu.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/jupyter-cells.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/jupyter-cells.jpg -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/jupyter-edit-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/jupyter-edit-menu.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/jupyter-file-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/jupyter-file-menu.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/jupyter-help-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/jupyter-help-menu.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/jupyter-insert-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/jupyter-insert-menu.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/jupyter-kernel-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/jupyter-kernel-menu.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/jupyter-view-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/jupyter-view-menu.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/jupyter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/jupyter.jpg -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/jupyterlab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/jupyterlab.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/jupyter/kaggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/jupyter/kaggle.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/avengers-plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/avengers-plot.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/axes-2by2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/axes-2by2.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/axis-labels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/axis-labels.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/axis-lim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/axis-lim.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/barplot-tiobe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/barplot-tiobe.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/blank-figure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/blank-figure.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/bluered-grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/bluered-grid.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/centering-legend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/centering-legend.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/default-grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/default-grid.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/dist-boxplot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/dist-boxplot.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/eth-evolution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/eth-evolution.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/gbar-plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/gbar-plot.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/global-temperatures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/global-temperatures.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/heatmap-eurodollar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/heatmap-eurodollar.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/hist-pokemon-speed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/hist-pokemon-speed.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/imdb-heatmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/imdb-heatmap.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/label-ticks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/label-ticks.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/mandala.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/mandala.jpg -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/minor-ticks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/minor-ticks.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/mwh-spain-2021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/mwh-spain-2021.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/nba-scatter-plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/nba-scatter-plot.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/plot-annotations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/plot-annotations.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/plot-legend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/plot-legend.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/plot-sin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/plot-sin.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/plot-sincos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/plot-sincos.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/plot-styles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/plot-styles.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/scatter-bmw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/scatter-bmw.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/soften-wave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/soften-wave.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/matplotlib/tex-legend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/matplotlib/tex-legend.png -------------------------------------------------------------------------------- /docs/third-party/data-science/images/numpy/blocks.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/numpy/blocks.jpg -------------------------------------------------------------------------------- /docs/third-party/data-science/images/pandas/panda.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/data-science/images/pandas/panda.jpg -------------------------------------------------------------------------------- /docs/third-party/data-science/index.md: -------------------------------------------------------------------------------- 1 | # Ciencia de datos 2 | 3 | La ciencia de datos es un campo multidisciplinar que utiliza técnicas estadísticas, matemáticas y de programación para extraer conocimiento y patrones útiles a partir de grandes volúmenes de datos. En la era digital, la capacidad de analizar datos de manera eficiente se ha vuelto crucial para tomar decisiones informadas en una variedad de industrias, desde la tecnología hasta la medicina. Python se ha consolidado como uno de los lenguajes más populares para la ciencia de datos debido a su simplicidad y a la potencia de sus bibliotecas especializadas, como Pandas, NumPy, Matplotlib y Scikit-learn. En este capítulo, exploraremos cómo Python puede ser utilizado para realizar análisis de datos y manipular grandes conjuntos de información, sentando las bases para adentrarse en el fascinante mundo de la ciencia de datos. 4 | -------------------------------------------------------------------------------- /docs/third-party/data-science/pandas/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: simple/pandas 3 | --- 4 | 5 | # Pandas { #pandas } 6 | 7 | ![Panda](../images/pandas/panda.jpg) 8 | (1) 9 | { .annotate } 10 | 11 | 1. :fontawesome-regular-copyright: [Sid Balachandran](https://unsplash.com/@itookthose) :material-at: [Unsplash](https://unsplash.com) 12 | 13 | [`pandas`](https://pandas.pydata.org/docs/) es un paquete «open-source» especializada en la manipulación y el análisis de datos, ofreciendo estructuras de datos y operaciones para trabajar de forma sencilla y potente con gran cantidad de información. 14 | 15 | ## Instalación { #install } 16 | 17 | ```console 18 | pip install pandas 19 | ``` 20 | 21 | ## Modo de uso { #usage } 22 | 23 | La forma más habitual de importar esta librería es utilizar el alias `pd`: 24 | 25 | ```pycon 26 | >>> import pandas as pd 27 | ``` 28 | 29 | Si bien en [NumPy](../numpy.md) la estructura de datos fundamental es el `ndarray`, en pandas existen dos estructuras de datos sobre las que giran todas las operaciones: 30 | 31 | - [x] [Series](series.md). 32 | - [x] [Dataframes](dataframes.md). 33 | -------------------------------------------------------------------------------- /docs/third-party/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: material/package-variant 3 | --- 4 | 5 | # Paquetes de terceros 6 | 7 | Los paquetes de terceros son bibliotecas externas que amplían la funcionalidad de Python más allá de su librería estándar, permitiendo a los programadores acceder a herramientas avanzadas y soluciones especializadas sin tener que escribir todo desde cero. Estos paquetes cubren una amplia gama de áreas, como análisis de datos, aprendizaje automático, desarrollo web, interfaces gráficas y más. Gracias a la gestión de dependencias a través de herramientas como pip, instalar y usar estos paquetes es sencillo. En este bloque, exploraremos cómo instalar y trabajar con algunos de los paquetes más populares y útiles en Python, y cómo aprovechar su poder para mejorar la eficiencia y versatilidad de tus proyectos. 8 | -------------------------------------------------------------------------------- /docs/third-party/networking/files/requests/req.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | response = requests.get('https://twitter.com') 4 | print(response.status_code) 5 | print(len(response.text)) 6 | print(response.cookies.get('guest_id')) 7 | print(response.headers.get('content-encoding')) 8 | -------------------------------------------------------------------------------- /docs/third-party/networking/images/requests/wing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/networking/images/requests/wing.jpg -------------------------------------------------------------------------------- /docs/third-party/networking/index.md: -------------------------------------------------------------------------------- 1 | # Redes 2 | 3 | El desarrollo de redes es un área fundamental de la programación que permite la comunicación entre sistemas a través de internet o redes locales. En el contexto de Python, trabajar con redes implica conocer cómo enviar y recibir datos entre dispositivos, gestionar conexiones de red y crear aplicaciones que interactúan con servidores, bases de datos remotas o servicios web. Python proporciona una variedad de bibliotecas como socket, requests y asyncio, que facilitan la implementación de protocolos de comunicación como HTTP, FTP o incluso la creación de servidores y clientes personalizados. En este capítulo, exploraremos cómo utilizar Python para desarrollar aplicaciones que puedan enviar y recibir datos a través de redes, sentando las bases para proyectos como chatbots, servidores web o aplicaciones distribuidas. 4 | -------------------------------------------------------------------------------- /docs/third-party/pdf/index.md: -------------------------------------------------------------------------------- 1 | # PDF 2 | 3 | Trabajar con archivos PDF es una habilidad útil y necesaria en muchos proyectos de programación, especialmente cuando se necesita generar, leer, modificar o extraer información de documentos en este formato. Los archivos PDF son ampliamente utilizados para distribuir documentos debido a su capacidad para mantener el formato original en diferentes dispositivos. Python ofrece diversas bibliotecas que permiten manipular estos archivos de manera sencilla y eficiente. Ya sea para automatizar la generación de reportes, extraer texto o combinar varios documentos en uno solo, Python brinda herramientas poderosas para trabajar con PDFs. En este capítulo, exploraremos cómo utilizar estas bibliotecas para realizar operaciones comunes con archivos PDF, facilitando la automatización y el procesamiento de documentos en tus proyectos. 4 | -------------------------------------------------------------------------------- /docs/third-party/pdf/weasyprint.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: material/file-document-arrow-right-outline 3 | --- 4 | 5 | # WeasyPrint { #weasyprint } 6 | 7 | [WeasyPrint](https://doc.courtbouillon.org/weasyprint/stable/) es un paquete Python que permite generar ficheros PDF. Pensado especialmente para entornos de desarrollo, convierte ficheros HTML en formato PDF. 8 | 9 | ## Instalación { #install } 10 | 11 | ```console 12 | pip install weasyprint 13 | ``` 14 | 15 | ??? example ":simple-apple: macOS" 16 | 17 | En determinadas versiones de **macOS** es necesario instalar ciertos paquetes de sistema para que _weasyprint_ funcione correctamente: 18 | 19 | ```console 20 | brew install pango glib 21 | ``` 22 | 23 | Si el problema persiste, es posible que haya que realizar algunos [ajustes de enlaces simbólicos](https://github.com/Kozea/WeasyPrint/issues/1448#issuecomment-925549118): 24 | 25 | ```console 26 | sudo ln -s /opt/homebrew/opt/glib/lib/libgobject-2.0.0.dylib /usr/local/lib/gobject-2.0 27 | sudo ln -s /opt/homebrew/opt/pango/lib/libpango-1.0.dylib /usr/local/lib/pango-1.0 28 | sudo ln -s /opt/homebrew/opt/harfbuzz/lib/libharfbuzz.dylib /usr/local/lib/harfbuzz 29 | sudo ln -s /opt/homebrew/opt/fontconfig/lib/libfontconfig.1.dylib /usr/local/lib/fontconfig-1 30 | sudo ln -s /opt/homebrew/opt/pango/lib/libpangoft2-1.0.dylib /usr/local/lib/pangoft2-1.0 31 | ``` 32 | 33 | ## Modo de uso { #usage } 34 | 35 | Aunque existen [otros casos de uso](https://doc.courtbouillon.org/weasyprint/stable/common_use_cases.html), aquí cubriremos el más habitual. Partiendo de un fichero HTML lo convertiremos a PDF. 36 | 37 | Para ello vamos a hacer uso de la clase [`HTML`](https://doc.courtbouillon.org/weasyprint/stable/api_reference.html#weasyprint.HTML) que proporciona _WeasyPrint_: 38 | 39 | ```python 40 | from weasyprint import HTML#(1)! 41 | 42 | HTML(string=html_content).write_pdf('report.pdf')#(2)! 43 | ``` 44 | { .annotate } 45 | 46 | 1. Importamos la clase `HTML`. 47 | 2. - También es posible usar `HTML` con parámetro posicional. En ese caso _WeasyPrint_ tratará de averiguar si se trata de un nombre de fichero, de una URL absoluta o de un [`file object`](https://docs.python.org/3/glossary.html#term-file-object). 48 | - Usamos el método [`write_pdf()`](https://doc.courtbouillon.org/weasyprint/stable/api_reference.html#weasyprint.HTML.write_pdf) para generar el PDF de salida, indicando su ruta. 49 | 50 | ### URL base { #base-url } 51 | 52 | Si queremos usar **rutas relativas** dentro del fichero HTML y no son relativas a la carpeta «actual» de trabajo, hay que especificarlo utilizando el parámetro `base_url` que pasaremos al constructor de la clase `HTML`. 53 | 54 | Su uso depende del tipo de aplicación que estemos desarrolando: 55 | 56 | === "Aplicaciones de escritorio" 57 | 58 | ```python 59 | base_url = f'file://{absolute_path_to_assets}/'#(1)! 60 | HTML('input.html', base_url=base_url).write_pdf('output.pdf') 61 | ``` 62 | { .annotate } 63 | 64 | 1. Fundamental acabar la ruta con barra `/` 65 | 66 | === "Aplicaciones web" 67 | 68 | ```python 69 | base_url = f'http://{absolute_path_to_assets}/'#(1)! 70 | HTML('input.html', base_url=base_url).write_pdf('output.pdf') 71 | ``` 72 | { .annotate } 73 | 74 | 1. Fundamental acabar la ruta con barra `/` 75 | 76 | !!! tip "Django" 77 | 78 | En [Django](../webdev/django/webdev.md#django) podemos utilizar la función [`request.build_absolute_uri()`](https://docs.djangoproject.com/en/stable/ref/request-response/#django.http.HttpRequest.build_absolute_uri) para este cometido. 79 | -------------------------------------------------------------------------------- /docs/third-party/scraping/files/beautifulsoup/pypi-trend.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from bs4 import BeautifulSoup 3 | 4 | URL = 'https://pypi.org' 5 | 6 | response = requests.get(URL) 7 | soup = BeautifulSoup(response.text, features='html.parser') 8 | 9 | links = soup.find(attrs={'aria-labelledby': 'pypi-trending-packages'})('a') 10 | for link in links: 11 | name, version = link.h3('span') 12 | description = link.p 13 | url = URL + link['href'] 14 | data = [name.string, version.string, description.string, url] 15 | print(','.join(data)) 16 | -------------------------------------------------------------------------------- /docs/third-party/scraping/files/selenium/mercadona.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | from selenium.webdriver.common.by import By 3 | from selenium.webdriver.firefox.options import Options 4 | from selenium.webdriver.support import expected_conditions as EC 5 | from selenium.webdriver.support.ui import WebDriverWait 6 | 7 | GEOLOC = (28.1247618, -15.4358226) 8 | URL = f'https://info.mercadona.es/es/supermercados?coord={GEOLOC[0]}%2C{GEOLOC[1]}' 9 | 10 | options = Options() 11 | options.add_argument('-headless') 12 | 13 | driver = webdriver.Firefox(options=options) 14 | driver.get(URL) 15 | 16 | css_selector = 'p.blq-drcha-cookies a#third-btn' 17 | elem = driver.find_element(By.CSS_SELECTOR, css_selector) 18 | elem.click() 19 | 20 | elem = driver.find_element(By.TAG_NAME, 'body') 21 | driver.execute_script('arguments[0].scrollIntoView(false)', elem) 22 | 23 | css_selector = 'div.verTodosLista button' 24 | elem = WebDriverWait(driver, 10).until( 25 | EC.presence_of_element_located((By.CSS_SELECTOR, css_selector)) 26 | ) 27 | elem.click() 28 | 29 | print(f'Supermercados MERCADONA cerca de {GEOLOC}') 30 | print('----------------------------------------------------------') 31 | 32 | css_selector = 'h3.panelLateralResultadosDireccion' 33 | for res in driver.find_elements(By.CSS_SELECTOR, css_selector): 34 | print(res.text) 35 | 36 | driver.quit() 37 | -------------------------------------------------------------------------------- /docs/third-party/scraping/files/selenium/wordle_play.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | 3 | URL = 'https://wordle.danielfrg.com/' 4 | 5 | driver = webdriver.Firefox() 6 | 7 | driver.get(URL) 8 | 9 | play_btn_xpath = '//*[@id="headlessui-dialog-1"]/div/div[2]/div[5]/button' 10 | play_btn = driver.find_element_by_xpath(play_btn_xpath) 11 | play_btn.click() 12 | -------------------------------------------------------------------------------- /docs/third-party/scraping/files/selenium/wordle_try.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from selenium import webdriver 4 | from selenium.webdriver.common.keys import Keys 5 | 6 | URL = 'https://wordle.danielfrg.com/' 7 | 8 | 9 | def init_webdriver(): 10 | return webdriver.Firefox() 11 | 12 | 13 | def play(driver): 14 | play_btn_xpath = '//*[@id="headlessui-dialog-1"]/div/div[2]/div[5]/button' 15 | play_btn = driver.find_element_by_xpath(play_btn_xpath) 16 | play_btn.click() 17 | 18 | 19 | def try_word(driver, word: str): 20 | body = driver.find_element_by_tag_name('body') 21 | for char in word: 22 | body.send_keys(char) 23 | time.sleep(0.5) 24 | body.send_keys(Keys.ENTER) 25 | 26 | 27 | driver = init_webdriver() 28 | driver.get(URL) 29 | play(driver) 30 | try_word(driver, 'vamos') 31 | -------------------------------------------------------------------------------- /docs/third-party/scraping/images/beautifulsoup/soup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/scraping/images/beautifulsoup/soup.jpg -------------------------------------------------------------------------------- /docs/third-party/scraping/images/selenium/dom-inspector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/scraping/images/selenium/dom-inspector.png -------------------------------------------------------------------------------- /docs/third-party/scraping/images/selenium/robot-assistant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/scraping/images/selenium/robot-assistant.jpg -------------------------------------------------------------------------------- /docs/third-party/scraping/images/selenium/selenium-python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/scraping/images/selenium/selenium-python.png -------------------------------------------------------------------------------- /docs/third-party/scraping/index.md: -------------------------------------------------------------------------------- 1 | # Scraping 2 | 3 | El «web scraping» es una técnica utilizada para extraer información de sitios web de forma automática, lo que permite recolectar datos que no siempre están disponibles en un formato estructurado. Esta práctica es especialmente útil cuando se necesita obtener grandes volúmenes de datos de diversas páginas web para análisis, investigación o proyectos de inteligencia de negocios. En Python, existen poderosas herramientas como requests, BeautifulSoup y Selenium que facilitan el proceso de scraping al permitir hacer peticiones HTTP, analizar contenido HTML y automatizar la navegación en sitios dinámicos. En este capítulo, exploraremos cómo realizar scraping de manera ética y eficiente, aprenderemos a manejar el contenido web y a extraer información valiosa de páginas estáticas y dinámicas, abriendo nuevas posibilidades para la recopilación y el análisis de datos. 4 | -------------------------------------------------------------------------------- /docs/third-party/webdev/django/apps.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: material/application-outline 3 | --- 4 | 5 | # Aplicaciones { #apps } 6 | 7 | :simple-django: Básico :material-tag-multiple-outline: 8 | 9 | Un proyecto Django está formado por aplicaciones. En este contexto podemos entender una aplicación como una «zona» o «sección» de nuestro sitio web. 10 | 11 | ## Crear una aplicación { #creation } 12 | 13 | Para crear una nueva aplicación en un proyecto usaremos el subcomando `startapp`. 14 | 15 | Supongamos un ejemplo:material-flash: en el que queremos crear una aplicación para gestionar los «posts» de un «blog». Para ello ejecutamos el siguiente comando: 16 | 17 | ```console 18 | $ ./manage.py startapp posts 19 | ``` 20 | 21 | !!! tip "Nombres en plural" 22 | 23 | Suele ser habitual usar **nombres en plural** para las aplicaciones, pero obviamente depende del contexto y no es una regla fija. 24 | 25 | ## Estructura de una aplicación { #structure } 26 | 27 | La estructura de una aplicación es la siguiente: 28 | 29 | ```python 30 | . 31 | ├── __init__.py#(1)! 32 | ├── admin.py#(2)! 33 | ├── apps.py#(3)! 34 | ├── migrations#(4)! 35 | │   └── __init__.py 36 | ├── models.py#(5)! 37 | ├── tests.py#(6)! 38 | └── views.py#(7)! 39 | ``` 40 | { .annotate } 41 | 42 | 1. Este tipo de archivos se utilizan para indicar que la carpeta actual es un [paquete](https://docs.python.org/3/tutorial/modules.html#packages) en Python. 43 | 2. Este archivo permite especificar las características de los modelos de cara a la [interfaz administrativa](https://docs.djangoproject.com/en/dev/ref/contrib/admin/) de Django. 44 | 3. Este archivo permite «registrar» la aplicación creada y definir algunas configuraciones a nivel global. 45 | 4. Esta carpeta contendrá las migraciones (como ficheros) realizadas sobre los modelos de la aplicación actual. 46 | 5. Este archivo permite definir los modelos para la aplicación actual. 47 | 6. Este archivo permite escribir las pruebas («tests») de la aplicación actual. 48 | 7. Este archivo permite definir las vistas para la aplicación actual. 49 | 50 | ## Instalar la aplicación { #installation } 51 | 52 | Para que Django reconozca una nueva aplicación en nuestro proyecto, necesitamos darla de alta («instalar») en el fichero `settings.py`. 53 | 54 | Existe una variable `INSTALLED_APPS` que contiene una lista con todas las aplicaciones dadas de alta en el proyecto. Si miramos su contenido actual veremos lo siguiente: 55 | 56 | ```python 57 | INSTALLED_APPS = [ 58 | 'django.contrib.admin',#(1)! 59 | 'django.contrib.auth',#(2)! 60 | 'django.contrib.contenttypes',#(3)! 61 | 'django.contrib.sessions',#(4)! 62 | 'django.contrib.messages',#(5)! 63 | 'django.contrib.staticfiles',#(6)! 64 | ] 65 | ``` 66 | { .annotate } 67 | 68 | 1. Interfaz administrativa. 69 | 2. Sistema de autenticación. 70 | 3. Herramientas para trabajar con los modelos del proyecto. 71 | 4. Sistema para almacenar información en sesiones. 72 | 5. Notificaciones. 73 | 6. Gestión de archivos estáticos. 74 | 75 | Siguiendo con el ejemplo:material-flash: anterior vamos a «instalar» nuestra aplicación `posts`. Basta con añadir su fichero de configuración a `settings.py`: 76 | 77 | ```python hl_lines="8" 78 | INSTALLED_APPS = [ 79 | 'django.contrib.admin', 80 | 'django.contrib.auth', 81 | 'django.contrib.contenttypes', 82 | 'django.contrib.sessions', 83 | 'django.contrib.messages', 84 | 'django.contrib.staticfiles', 85 | 'posts.apps.PostsConfig', 86 | ] 87 | ``` 88 | 89 | :material-check-all:{ .blue } Como regla general, lo que debemos añadir a la lista `INSTALLED_APPS` de `settings.py` es la **clase** que configura la aplicación. 90 | 91 | !!! note "Clase de configuración" 92 | 93 | Si la aplicación se llama `foos` la clase de configuración se llamará `FoosConfig` y estará en la ruta: `#!console foos/apps.py` 94 | 95 | ## Aplicación compartida { #shared } 96 | 97 | En cualquier proyecto hay una gran cantidad de recursos que se comparten por todas las aplicaciones. Por tanto resulta interesante crear una aplicación que centralice dichos recursos y sirva de referencia para ellos. 98 | 99 | En este sentido **es recomendable** [crear una aplicación](#creation) `shared`{ .red } que contenga artefactos compartidos: plantillas base, estáticos comunes, funciones genéricas, etc. 100 | 101 | ```console 102 | $ ./manage.py startapp shared 103 | ``` 104 | -------------------------------------------------------------------------------- /docs/third-party/webdev/django/images/webdev/client-side-rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/webdev/django/images/webdev/client-side-rendering.png -------------------------------------------------------------------------------- /docs/third-party/webdev/django/images/webdev/django-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/third-party/webdev/django/images/webdev/django-reinhardt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/webdev/django/images/webdev/django-reinhardt.jpg -------------------------------------------------------------------------------- /docs/third-party/webdev/django/images/webdev/html-and-css.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/webdev/django/images/webdev/html-and-css.png -------------------------------------------------------------------------------- /docs/third-party/webdev/django/images/webdev/server-side-rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/webdev/django/images/webdev/server-side-rendering.png -------------------------------------------------------------------------------- /docs/third-party/webdev/django/images/webdev/webdev-layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/docs/third-party/webdev/django/images/webdev/webdev-layers.png -------------------------------------------------------------------------------- /docs/third-party/webdev/django/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: simple/django 3 | --- 4 | 5 | # Django 6 | 7 | Django :simple-django:{ .green .beat } es un framework de desarrollo web de código abierto, escrito en Python, que respeta el patrón de diseño conocido como modelo–vista–controlador (MVC). Fue desarrollado originalmente para gestionar páginas web orientadas a noticias de la World Company de Lawrence, Kansas, y fue liberada al público bajo una licencia BSD en julio de 2005; el framework fue nombrado en alusión al guitarrista de jazz gitano Django Reinhardt. 8 | -------------------------------------------------------------------------------- /docs/third-party/webdev/django/static.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: material/folder-outline 3 | --- 4 | 5 | # Estáticos { #static } 6 | 7 | :simple-django: Básico :material-tag-multiple-outline: 8 | 9 | Los ficheros estáticos («assets») son ficheros que no necesitan un preprocesamiento y que se utilizan «tal cual son». Nos estamos refiriendo a: 10 | 11 | - Imágenes. 12 | - Vídeos. 13 | - Fuentes tipográficas. 14 | - Hojas de estilo CSS. 15 | - Código JavaScript. 16 | 17 | ## Estáticos en desarrollo { #static-during-development } 18 | 19 | Siempre y cuando tengamos activada la aplicación `#!python 'django.contrib.staticfiles'` (_que ya viene por defecto_) Django se encarga de servir los ficheros estáticos cuando así sea necesario. 20 | 21 | !!! warning "Producción" 22 | 23 | Esto sólo es válido para un entorno de desarrollo, cuando pasamos a producción habrá que configurar el servidor web correspondiente para gestionar los ficheros estáticos. 24 | 25 | ## Ubicación { #location } 26 | 27 | Los ficheros estáticos «deberían» estar ubicados en la carpeta `static` de cada [aplicación](apps.md) del proyecto. Cuando hacemos referencia a un estático usamos una ruta. Funciona de manera análoga a la [ubicación de las plantillas](templates.md#location). 28 | 29 | Por ejemplo:material-flash: en una aplicación `posts` para un proyecto de «blog» podríamos tener la siguiente estructura de estáticos: 30 | 31 | ```hl_lines="3 5" 32 | posts 33 | └── static 34 | ├── blog.svg 35 | └── posts 36 | └── book.svg 37 | ``` 38 | 39 | - La ruta para acceder a `blog.svg` sería `blog.svg` 40 | - La ruta para acceder a `book.svg` sería `posts/book.svg` 41 | 42 | Django se encarga de rastrear las carpetas `static` de las aplicaciones para encontrar los estáticos indicados. 43 | 44 | :material-check-all:{ .blue } Por lo tanto los **espacios de nombres** también son importantes a la hora de organizar los estáticos de nuestro proyecto Django. 45 | 46 | ## Acceso a estáticos { #access } 47 | 48 | En este apartado veremos cómo acceder a ficheros estáticos tanto desde una plantilla como desde una vista. 49 | 50 | ### Estáticos en plantillas { #template-usage } 51 | 52 | Para acceder a ficheros estáticos desde una plantilla Django debemos utilizar la etiqueta [`{% static %}`](https://docs.djangoproject.com/en/stable/ref/templates/builtins/#static). 53 | 54 | Supongamos que tratamos de acceder a las imágenes (ficheros estáticos) definidas en el ejemplo:material-flash: anterior del «blog»: 55 | 56 | ```htmldjango 57 | {% load static %} 58 | 59 | 60 | 61 | ``` 62 | { .annotate } 63 | 64 | 1. Es necesario cargar la etiqueta `static`. 65 | 2. Acceso a un fichero estático. En este caso se generará la URL :material-arrow-right-box: `/static/blog.svg` 66 | 3. Acceso a un fichero estático. En este caso se generará la URL :material-arrow-right-box: `/static/posts/blog.svg` 67 | 68 | ### Estáticos en vistas { #view-usage } 69 | 70 | Para acceder a ficheros estáticos desde una vista Django debemos utilizar 71 | 72 | ## Bootstrap { #bootstrap } 73 | 74 | :simple-django: Avanzado :material-tag-multiple-outline: 75 | 76 | [Bootstrap :simple-bootstrap:](https://getbootstrap.com/) ofrece un conjunto de herramientas que facilitan el desarrollo de interfaces «frontend» para aplicaciones web. 77 | 78 | ### Instalación { #install-bootstrap } 79 | 80 | Hay varias maneras de instalar Bootstrap y de integrarlo en un proyecto Django. En esta sección veremos cómo implantarlo usando [npm :simple-npm:](https://www.npmjs.com/) y acceso a ficheros estáticos. 81 | 82 | Lo primero será [instalar](https://getbootstrap.com/docs/5.3/getting-started/download/#npm) los paquetes _JavaScript_ correspondientes: 83 | 84 | ```bash 85 | npm install bootstrap bootstrap-icons #(1)! 86 | ``` 87 | { .annotate } 88 | 89 | 1. Desde el raíz de nuestro proyecto Django. 90 | 91 | El comando anterior creará una carpeta `node_modules` con **multitud** de ficheros y carpetas, correspondientes a los paquetes instalados y a todas sus dependencias. 92 | 93 | También creará dos ficheros `package.json` y `package-lock.json` donde quedan fijadas las versiones de los paquetes instalados. 94 | 95 | !!! warning "Control de versiones" 96 | 97 | Recuerda excluir la carpeta `node_modules` del control de versiones añadiéndola al fichero `.gitignore` de tu proyecto. 98 | 99 | ### Configuración { #config-bootstrap } 100 | 101 | Para poder acceder a los archivos creados en `node_modules` desde las plantillas Django, necesitamos especificar en la configuración del proyecto que dicha carpeta contiene **estáticos**. 102 | 103 | Para ello añadimos la siguiente línea al fichero `settings.py`: 104 | 105 | ```python title="main/settings.py" 106 | STATICFILES_DIRS = [BASE_DIR / 'node_modules']#(1)! 107 | ``` 108 | { .annotate } 109 | 110 | 1. Esta variable permite añadir **rutas extras** donde Django irá a buscar ficheros estáticos. 111 | 112 | ### Plantillas { #templates-bootstrap } 113 | 114 | Dado que Bootstrap utiliza ficheros `.css` y `.js` necesitamos cargarlos correctamente desde nuestras plantillas. 115 | 116 | Suponiendo que disponemos de una [plantilla base](templates.md#inheritance) tendríamos que añadir lo siguiente: 117 | 118 | ```htmldjango title="shared/templates/base.html" hl_lines="1 9-10 21" 119 | {% load static %} 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 |
134 | {% block content %} 135 | {% endblock %} 136 |
137 | 138 | 139 | 140 | 141 | ``` 142 | { .annotate } 143 | 144 | 1. Necesitamos cargar las utilidades para estáticos. 145 | 2. Cargamos los estilos de Bootstrap. 146 | 3. Cargamos los iconos de Bootstrap. 147 | 4. Cargamos estilos propios (opcional). 148 | 5. La clase [`container`](https://getbootstrap.com/docs/5.3/layout/containers/) es el bloque fundamental de Bootstrap. 149 | 6. Cargamos los scripts de Bootstrap. 150 | 151 | :material-check-all:{ .blue } A partir de aquí ya podremos usar todos los recursos que nos proporciona Bootstrap para diseñar una interfaz de usuario moderna, responsiva y funcional. 152 | -------------------------------------------------------------------------------- /docs/third-party/webdev/django/views.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: octicons/eye-16 3 | --- 4 | 5 | # Vistas { #views } 6 | 7 | :simple-django: Básico :material-tag-multiple-outline: 8 | 9 | En el [MVC](webdev.md#web-framework) de Django se podría decir que las **vistas** se corresponden con los **controladores**. En esta sección veremos cómo manejar las vistas y explotar sus principales funcionalidades. 10 | 11 | ## La primera vista { #first-view } 12 | 13 | Una vista no es más que una **función** Python que recibe (como primer parámetro) la petición HTTP y retorna una respuesta HTTP: 14 | 15 | ```mermaid 16 | flowchart LR 17 | request["HttpRequest"] 18 | response["HttpResponse"] 19 | view{{View}} 20 | request --> view --> response 21 | ``` 22 | 23 | Supongamos una primera vista que por ejemplo:material-flash: devuelva un «Hello, World!»: 24 | 25 | ```python 26 | from django.http import HttpResponse#(1)! 27 | 28 | def hello_world(request):#(2)! 29 | return HttpResponse('Hello, World!')#(3)! 30 | ``` 31 | { .annotate } 32 | 33 | 1. La clase [`HttpResponse`](https://docs.djangoproject.com/en/stable/ref/request-response/#httpresponse-objects) permite devolver una respuesta HTTP al usuario. 34 | 2. Todas las vistas reciben **como primer parámetro** un objeto de tipo [`HttpRequest`](https://docs.djangoproject.com/en/stable/ref/request-response/#httprequest-objects) que — por convención — se nombra como `request`. 35 | 3. Las vistas siempre deben devolver una respuesta (HTTP), de lo contrario se lanzará una excepción. 36 | 37 | !!! tip "Contenido" 38 | 39 | En el fichero `views.py` sólo deben ir **vistas**. Cualquier otro artefacto que queramos implementar debe ir bien en el modelo o bien en un fichero auxiliar. 40 | 41 | ## Renderizando plantillas { #render-templates } 42 | 43 | Si quisiéramos devolver un HTML mediante el objeto `HttpResponse` nos quedaría algo relativamente incómodo: 44 | 45 | ```python 46 | from django.http import HttpResponse 47 | 48 | def hello_world(request): 49 | return HttpResponse(''' 50 | 51 | 52 | 53 | 54 | 55 | Hello World 56 | 57 | 58 | 59 |

Hello, World!

60 | 61 | ''') 62 | ``` 63 | 64 | Es por ello que Django nos facilita esta tarea mediante el «shortcut» [`render`](https://docs.djangoproject.com/en/stable/topics/http/shortcuts/#render) que se encarga de renderizar una plantilla y devolver el contenido de la misma mediante un objeto de tipo `HttpResponse`. 65 | 66 | Veamos el mismo ejemplo:material-flash: que antes pero utilizando esta funcionalidad: 67 | 68 | ```python 69 | from django.shortcuts import render#(1)! 70 | 71 | def hello_world(request): 72 | return render(request, 'helloworld.html')#(2)! 73 | ``` 74 | { .annotate } 75 | 76 | 1. Importamos la función `render()` desde los «shortcuts» de Django. 77 | 2. La función `render()` siempre recibe como primer parámetro la petición `HttpRequest` y como segundo parámetro la [ruta a la plantilla](templates.md#location). 78 | 79 | ### Pasando un contexto { #passing-context } 80 | 81 | Una de las ventajas importantes del uso de plantillas en Django es la posibilidad de «inyectar» variables. Dicho de otro modo, cuando estamos renderizando una plantilla podemos pasar un **contexto** con las variables que vamos a utilizar. 82 | 83 | El ejemplo:material-flash: anterior se puede escribir de otra manera haciendo uso del contexto: 84 | 85 | ```python 86 | from django.shortcuts import render 87 | 88 | def hello_world(request): 89 | return render(request, 'caption.html', {'message': 'Hello, World!'})#(1)! 90 | ``` 91 | { .annotate } 92 | 93 | 1. - La función `render()` admite un tercer parámetro (_contexto_) que es un **diccionario**. 94 | - De esta forma podemos «generalizar» la plantilla `caption.html` y parametrizarla con el contexto en función del mensaje que queramos mostrar. 95 | 96 | ## Método de la petición { #request-method } 97 | 98 | Hay ocasiones, especialmente en el manejo de [formularios](forms.md) que nos interesa detectar el método de la petición HTTP para tomar una acción u otra en función de ello. 99 | 100 | Veamos un fragmento de código en el que identificamos el método HTTP utilizado en la petición: 101 | 102 | ```python 103 | def view(request): 104 | if request.method == 'POST':#(1)! 105 | # This is a POST method HTTP request 106 | else:#(2)! 107 | # This is (probably) a GET method HTTP request 108 | ``` 109 | { .annotate } 110 | 111 | 1. El atributo [`method`](https://docs.djangoproject.com/en/stable/ref/request-response/#django.http.HttpRequest.method) de los objetos `HttpRequest` nos informan del método HTTP mediante una cadena de texto ^^en mayúsculas^^. 112 | 2. - Aunque existen [múltiples métodos HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) para una petición, lo habitual es trabajar con dos de ellos: [`GET`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET) y [`POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST). 113 | - En cualquier caso si se quiere asegurar que es un método `GET` basta con indicarlo explícitamente :material-arrow-right-box: `#!python if request.method == 'GET':` 114 | 115 | ## Tipos de respuestas { #response-types } 116 | 117 | :simple-django: Intermedio :material-tag-multiple-outline: 118 | 119 | La clase [`HttpResponse`](https://docs.djangoproject.com/en/stable/ref/request-response/#httpresponse-objects) permite indicar el código de estado de la respuesta. Esto hace posible ser más exactos en el mensaje que trasladamos a un cliente. 120 | 121 | Para ello usaremos el atributo `status_code` con un valor numérico (_del código de estado_) que podemos encontrar en [este enlace](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status). 122 | 123 | Por ejemplo:material-flash: si queremos indicar que un determinado recurso no se encuentra, lo podemos implementar así: 124 | 125 | ```python hl_lines="5" 126 | from django.http import HttpResponse 127 | 128 | 129 | def my_view(request): 130 | # ... 131 | return HttpResponse(status_code=404) 132 | ``` 133 | 134 | Pero Django ofrece [ciertas clases ya predefinidas](https://docs.djangoproject.com/en/stable/ref/request-response/#httpresponse-subclasses) para cubrir los códigos de estado HTTP más habituales: 135 | 136 | | `status_code` | Significado | Clase | 137 | | --- | --- | --- | 138 | | [400](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400) | Bad request | `HttpResponseBadRequest()` | 139 | | [401](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401) | Unauthorized | | 140 | | [403](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403) | Forbidden | `HttpResponseForbidden()` | 141 | | [404](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404) | Not Found | `HttpResponseNotFound()` | 142 | | [405](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405) | Method Not Allowed | `HttpResponseNotAllowed()` | 143 | | [500](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500) | Internal Server Error | `HttpResponseServerError()` | 144 | 145 | ### Consulta no encontrada { #not-found-query } 146 | 147 | Django proporciona un «shortcut» (atajo) para cuando queremos [recuperar un objeto](models.md#retrieve-one) pero —en vez de lanzar una excepción de tipo `DoesNotExist`— devolver un [`Http404`](https://docs.djangoproject.com/en/stable/topics/http/views/#django.http.Http404). 148 | 149 | Por ejemplo:material-flash:, supongamos una vista que recupera un «post» de la base de datos a partir de su «slug»: 150 | 151 | ```python title="posts/views.py" hl_lines="1 7" 152 | from django.shortcuts import get_object_or_404 153 | 154 | from .models import Post 155 | 156 | 157 | def post_detail(request, post_slug: str): 158 | post = get_object_or_404(Post, slug=post_slug)#(1)! 159 | ``` 160 | { .annotate } 161 | 162 | 1. El primer parámetro es el modelo y el segundo es el filtro/condición a aplicar. 163 | -------------------------------------------------------------------------------- /docs/third-party/webdev/index.md: -------------------------------------------------------------------------------- 1 | # Desarrollo web 2 | 3 | El desarrollo web es el proceso de crear aplicaciones y sitios web dinámicos y funcionales que puedan ser accedidos a través de internet. En el mundo actual, donde la interacción digital es fundamental, comprender cómo construir y gestionar aplicaciones web es una habilidad esencial para los programadores. Python, con su simplicidad y flexibilidad, se ha convertido en uno de los lenguajes más populares para el desarrollo web, gracias a frameworks como Django y Flask. Estos frameworks facilitan la creación de aplicaciones robustas, escalables y seguras. En este capítulo, exploraremos cómo Python puede ser utilizado para desarrollar sitios web interactivos, gestionar bases de datos y crear interfaces de usuario, proporcionándote las herramientas necesarias para comenzar a crear tu propio entorno web. 4 | -------------------------------------------------------------------------------- /includes/abbreviations.md: -------------------------------------------------------------------------------- 1 | *[API]: Application Programming Interface 2 | *[APL]: A Programming Language 3 | *[ASCII]: American Standard Code for Information Interchange 4 | *[ASGI]: Asynchronous Server Gateway Interface 5 | *[COBOL]: Common Business-Oriented Language 6 | *[CP/M]: Control Program for Microcomputers 7 | *[CPU]: Central Processing Unit 8 | *[CSR]: Client Side Rendering 9 | *[CSRF]: Cross Site Request Forgery 10 | *[CSS]: Cascading Style Sheets 11 | *[DoD]: Department of Defense (United States) 12 | *[DOM]: Document Object Model 13 | *[DPI]: Dots Per Inch 14 | *[DRY]: Don't Repeat Yourself 15 | *[ENIAC]: Electronic Numerical Integrator And Computer 16 | *[FFT]: Fast Fourier Transform 17 | *[FORTRAN]: The IBM Mathematical Formula Translating System 18 | *[GIL]: Global Interpreter Locker 19 | *[GPU]: Graphics Processing Unit 20 | *[HTML]: Hypertext Markup Language 21 | *[HTTP]: Hypertext Transfer Protocol 22 | *[IBM]: International Business Machines Corporation 23 | *[IDE]: Integrated Development Environment 24 | *[IEEE]: Institute of Electrical and Electronics Engineers 25 | *[JSON]: JavaScript Object Notation 26 | *[JWT]: JSON Web Token 27 | *[LHS]: Left Hand Side 28 | *[LISP]: List Processing 29 | *[ML]: Meta Language 30 | *[MTV]: Model Template View 31 | *[MVC]: Model View Controller 32 | *[OOP]: Object Oriented Programming 33 | *[ORM]: Object Relational Mapping 34 | *[PEP]: Python Enhacement Proposals 35 | *[PDF]: Portable Document Format 36 | *[PNG]: Portable Network Graphics 37 | *[PC]: Personal Computer 38 | *[RAM]: Random Access Memory 39 | *[RDBMS]: Relational Database Management System 40 | *[RHS]: Right Hand Side 41 | *[RST]: Restructured Text 42 | *[SMTP]: Simple Mail Transfer Protocol 43 | *[SPA]: Single Page Application 44 | *[SQL]: Structured Query Language 45 | *[SSR]: Server Side Rendering 46 | *[SVG]: Scalable Vector Graphics 47 | *[TIOBE]: The Importance Of Being Earnest 48 | *[TPU]: Tensor Processing Unit 49 | *[URL]: Uniform Resource Locators 50 | *[UUID]: Universally Unique Identifier 51 | *[WSGI]: Web Server Gateway Interface 52 | *[WSL]: Windows Subsystem for Linux 53 | *[XSS]: Cross Site Scripting 54 | 55 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | runserver port="8000": 2 | uv run mkdocs serve -a localhost:{{ port }} 3 | 4 | rundirty port="8000": 5 | uv run mkdocs serve -a localhost:{{ port }} --dirty 6 | 7 | build: 8 | uv run mkdocs build --clean 9 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | # Inspired by: https://github.com/astral-sh/uv/blob/main/mkdocs.template.yml 2 | 3 | site_name: Aprende Python 4 | site_author: sdelquin 5 | site_url: https://aprendepython.es 6 | copyright: Copyright © Sergio Delgado Quintero 7 | 8 | theme: 9 | name: material 10 | logo: assets/images/aprendepython-logo.svg 11 | favicon: assets/images/favicon.svg 12 | features: 13 | - content.code.annotate 14 | - content.code.copy 15 | - content.tabs.link 16 | - navigation.footer 17 | - navigation.indexes 18 | - navigation.prune 19 | - navigation.tabs 20 | - navigation.top 21 | - search.share 22 | - search.suggest 23 | - toc.follow 24 | palette: 25 | - media: "(prefers-color-scheme)" 26 | toggle: 27 | icon: material/brightness-auto 28 | name: Switch to light mode 29 | primary: teal 30 | accent: pink 31 | - media: "(prefers-color-scheme: light)" 32 | scheme: default 33 | primary: teal 34 | accent: pink 35 | toggle: 36 | icon: material/brightness-7 37 | name: Switch to dark mode 38 | - media: "(prefers-color-scheme: dark)" 39 | scheme: slate 40 | primary: teal 41 | accent: pink 42 | toggle: 43 | icon: material/brightness-4 44 | name: Switch to system preference 45 | language: es 46 | 47 | repo_url: https://github.com/sdelquin/aprendepython 48 | repo_name: aprendepython 49 | 50 | markdown_extensions: 51 | - abbr 52 | - admonition 53 | - attr_list 54 | - def_list 55 | - footnotes 56 | - markdown.extensions.attr_list 57 | - md_in_html 58 | - pymdownx.arithmatex: 59 | generic: true 60 | - pymdownx.caret 61 | - pymdownx.critic 62 | - pymdownx.details 63 | - pymdownx.emoji: 64 | emoji_index: !!python/name:material.extensions.emoji.twemoji 65 | emoji_generator: !!python/name:material.extensions.emoji.to_svg 66 | - pymdownx.highlight: 67 | anchor_linenums: true 68 | - pymdownx.inlinehilite 69 | - pymdownx.keys 70 | - pymdownx.magiclink 71 | - pymdownx.mark 72 | - pymdownx.snippets: 73 | auto_append: 74 | - includes/abbreviations.md 75 | - pymdownx.superfences: 76 | custom_fences: 77 | - name: mermaid 78 | class: mermaid 79 | format: !!python/name:pymdownx.superfences.fence_code_format 80 | - pymdownx.tabbed: 81 | alternate_style: true 82 | - pymdownx.tasklist: 83 | custom_checkbox: true 84 | - pymdownx.tilde 85 | - toc: 86 | permalink: true 87 | toc_depth: 3 88 | 89 | plugins: 90 | - search 91 | # https://github.com/byrnereese/mkdocs-minify-plugin?tab=readme-ov-file#options 92 | - minify: 93 | cache_safe: true 94 | minify_css: true 95 | css_files: 96 | - assets/css/custom.css 97 | 98 | watch: 99 | - includes 100 | 101 | extra_css: 102 | - assets/css/custom.css 103 | extra_javascript: 104 | - assets/js/clipboard.js 105 | - assets/js/mathjax.js 106 | - https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js 107 | 108 | extra: 109 | social: 110 | - icon: material/human-greeting-variant 111 | link: https://sdelquin.matraka.es 112 | 113 | validation: 114 | links: 115 | absolute_links: relative_to_docs 116 | 117 | not_in_nav: | 118 | index.md 119 | 120 | nav: 121 | - Fundamentos del lenguaje: 122 | - core/index.md 123 | - Introducción: 124 | - core/introduction/index.md 125 | - core/introduction/machine.md 126 | - core/introduction/history.md 127 | - core/introduction/python.md 128 | - Entornos de desarrollo: 129 | - core/devenv/index.md 130 | - core/devenv/thonny.md 131 | - core/devenv/real-context.md 132 | - core/devenv/vscode.md 133 | - Tipos de datos: 134 | - core/datatypes/index.md 135 | - core/datatypes/data.md 136 | - core/datatypes/numbers.md 137 | - core/datatypes/strings.md 138 | - Control de flujo: 139 | - core/controlflow/index.md 140 | - core/controlflow/conditionals.md 141 | - core/controlflow/loops.md 142 | - Estructuras de datos: 143 | - core/datastructures/index.md 144 | - core/datastructures/lists.md 145 | - core/datastructures/tuples.md 146 | - core/datastructures/dicts.md 147 | - core/datastructures/sets.md 148 | - core/datastructures/files.md 149 | - Modularidad: 150 | - core/modularity/index.md 151 | - core/modularity/functions.md 152 | - core/modularity/oop.md 153 | - core/modularity/exceptions.md 154 | - core/modularity/modules.md 155 | - Librería estándar: 156 | - stdlib/index.md 157 | - Procesamiento de texto: 158 | - stdlib/text-processing/index.md 159 | - stdlib/text-processing/re.md 160 | - stdlib/text-processing/string.md 161 | - Acceso a datos: 162 | - stdlib/data-access/index.md 163 | - stdlib/data-access/sqlite.md 164 | - Paquetes de terceros: 165 | - third-party/index.md 166 | - Ciencia de datos: 167 | - third-party/data-science/index.md 168 | - third-party/data-science/jupyter.md 169 | - third-party/data-science/numpy.md 170 | - Pandas: 171 | - third-party/data-science/pandas/index.md 172 | - third-party/data-science/pandas/series.md 173 | - third-party/data-science/pandas/dataframes.md 174 | - third-party/data-science/matplotlib.md 175 | - Configuraciones: 176 | - third-party/config/index.md 177 | - third-party/config/prettyconf.md 178 | - Desarrollo web: 179 | - third-party/webdev/index.md 180 | - Django: 181 | - third-party/webdev/django/index.md 182 | - third-party/webdev/django/webdev.md 183 | - third-party/webdev/django/setup.md 184 | - third-party/webdev/django/apps.md 185 | - third-party/webdev/django/models.md 186 | - third-party/webdev/django/urls.md 187 | - third-party/webdev/django/views.md 188 | - third-party/webdev/django/templates.md 189 | - third-party/webdev/django/admin.md 190 | - third-party/webdev/django/forms.md 191 | - third-party/webdev/django/static.md 192 | - third-party/webdev/django/auth.md 193 | - third-party/webdev/django/i18n.md 194 | - third-party/webdev/django/extras.md 195 | - third-party/webdev/django/api.md 196 | - PDF: 197 | - third-party/pdf/index.md 198 | - third-party/pdf/weasyprint.md 199 | - Redes: 200 | - third-party/networking/index.md 201 | - third-party/networking/requests.md 202 | - Scraping: 203 | - third-party/scraping/index.md 204 | - third-party/scraping/beautifulsoup.md 205 | - third-party/scraping/selenium.md 206 | -------------------------------------------------------------------------------- /promo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdelquin/aprendepython/dd373ec204bdb2c0415c8de9aa4f2a7c5942a07c/promo.jpg -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "aprendepython" 3 | version = "0.1.0" 4 | requires-python = ">=3.13" 5 | dependencies = ["mkdocs-material>=9.6.8", "mkdocs-minify-plugin>=0.8.0"] 6 | 7 | [dependency-groups] 8 | dev = ["ipython>=9.0.2", "pytest>=8.3.5"] 9 | --------------------------------------------------------------------------------