diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 119800cb..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,24 +0,0 @@ -version: 2 -updates: - - - package-ecosystem: "pip" - directory: "/" - schedule: - interval: "weekly" - commit-message: - prefix: "dependabot" - assignees: - - "octocat" - labels: - - "dependencies" - - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - commit-message: - prefix: "dependabot" - assignees: - - "octocat" - labels: - - "dependencies" diff --git a/.github/workflows/cd-prod.yml b/.github/workflows/cd-prod.yml index b8c82e5f..a0bae4b9 100644 --- a/.github/workflows/cd-prod.yml +++ b/.github/workflows/cd-prod.yml @@ -1,57 +1,57 @@ -name: cd-prod - -on: - workflow_dispatch: - push: - branches: - - master - -env: - PUBLISH_BRANCH: pycourse-page-prod - -jobs: - - deploy: - runs-on: ubuntu-latest - timeout-minutes: 4 - - steps: - - - name: checkout code - uses: actions/checkout@v4 - - - name: setup python - uses: actions/setup-python@v4 - with: - python-version: '3.10' - cache: 'pip' - - - name: caching - uses: actions/cache@v3 - with: - key: ${{ github.ref }} - path: .cache - - - name: install deps - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - - - name: image processing deps - run: | - sudo pip install pillow cairosvg - sudo apt-get install libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev - sudo apt-get install pngquant - - - name: deploy mkdocs - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GOOGLE_ANALYTICS_KEY: ${{ secrets.GOOGLE_ANALYTICS_KEY }} - run: mkdocs build -v - - - name: update publish dir to build branch - uses: peaceiris/actions-gh-pages@v3.9.3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_branch: ${{ env.PUBLISH_BRANCH }} - publish_dir: ./site +# name: cd-prod + +# on: +# workflow_dispatch: +# push: +# branches: +# - master + +# env: +# PUBLISH_BRANCH: pycourse-page-prod + +# jobs: + +# deploy: +# runs-on: ubuntu-latest +# timeout-minutes: 4 + +# steps: + +# - name: checkout code +# uses: actions/checkout@v4 + +# - name: setup python +# uses: actions/setup-python@v4 +# with: +# python-version: '3.10' +# cache: 'pip' + +# - name: caching +# uses: actions/cache@v3 +# with: +# key: ${{ github.ref }} +# path: .cache + +# - name: install deps +# run: | +# python -m pip install --upgrade pip +# pip install -r requirements.txt + +# - name: image processing deps +# run: | +# sudo pip install pillow cairosvg +# sudo apt-get install libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev +# sudo apt-get install pngquant + +# - name: deploy mkdocs +# env: +# GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# GOOGLE_ANALYTICS_KEY: ${{ secrets.GOOGLE_ANALYTICS_KEY }} +# run: mkdocs build -v + +# - name: update publish dir to build branch +# uses: peaceiris/actions-gh-pages@v3.9.3 +# with: +# github_token: ${{ secrets.GITHUB_TOKEN }} +# publish_branch: ${{ env.PUBLISH_BRANCH }} +# publish_dir: ./site diff --git a/.github/workflows/cd-stage.yml b/.github/workflows/cd-stage.yml index 69731457..ff1c7c83 100644 --- a/.github/workflows/cd-stage.yml +++ b/.github/workflows/cd-stage.yml @@ -1,59 +1,59 @@ -name: cd-stage - -on: - workflow_dispatch: - push: - branches: - - 'dependabot/**' - -env: - PUBLISH_BRANCH: pycourse-page-stage - -jobs: - - deploy: - runs-on: ubuntu-latest - timeout-minutes: 4 - permissions: - contents: write - environment: - name: pycourse-page-stage - url: https://pycourse-page-stage.netlify.app/ - - steps: - - - name: checkout code - uses: actions/checkout@v4 - - - name: setup python - uses: actions/setup-python@v4 - with: - python-version: '3.10' - cache: 'pip' - - - name: caching - uses: actions/cache@v3 - with: - key: ${{ github.ref }} - path: .cache - - - name: install deps - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - - - name: image processing deps - run: | - sudo pip install pillow cairosvg - sudo apt-get install libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev - sudo apt-get install pngquant - - - name: deploy mkdocs - run: mkdocs build -v - - - name: update publish dir to build branch - uses: peaceiris/actions-gh-pages@v3.9.3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_branch: ${{ env.PUBLISH_BRANCH }} - publish_dir: ./site +# name: cd-stage + +# on: +# workflow_dispatch: +# push: +# branches: +# - 'dependabot/**' + +# env: +# PUBLISH_BRANCH: pycourse-page-stage + +# jobs: + +# deploy: +# runs-on: ubuntu-latest +# timeout-minutes: 4 +# permissions: +# contents: write +# environment: +# name: pycourse-page-stage +# url: https://pycourse-page-stage.netlify.app/ + +# steps: + +# - name: checkout code +# uses: actions/checkout@v4 + +# - name: setup python +# uses: actions/setup-python@v4 +# with: +# python-version: '3.10' +# cache: 'pip' + +# - name: caching +# uses: actions/cache@v3 +# with: +# key: ${{ github.ref }} +# path: .cache + +# - name: install deps +# run: | +# python -m pip install --upgrade pip +# pip install -r requirements.txt + +# - name: image processing deps +# run: | +# sudo pip install pillow cairosvg +# sudo apt-get install libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev +# sudo apt-get install pngquant + +# - name: deploy mkdocs +# run: mkdocs build -v + +# - name: update publish dir to build branch +# uses: peaceiris/actions-gh-pages@v3.9.3 +# with: +# github_token: ${{ secrets.GITHUB_TOKEN }} +# publish_branch: ${{ env.PUBLISH_BRANCH }} +# publish_dir: ./site diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c65f34f..baebaa80 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: - name: set up py3.8 uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.11' cache: 'pip' - name: run pre-commit action diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 824a9bbd..00000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: codeql - -on: - workflow_dispatch: - push: - branches: - - master - pull_request: - branches: - - master - -jobs: - - analyze: - name: analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - strategy: - fail-fast: false - matrix: - language: [ 'python' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - - steps: - - - name: checkout repository - uses: actions/checkout@v4 - - - name: initialize codeql - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: perform codeql analysis - uses: github/codeql-action/analyze@v2 diff --git a/.gitignore b/.gitignore index a3c9dacc..68bc17f9 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,6 @@ parts/ sdist/ var/ wheels/ -pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg @@ -50,6 +49,7 @@ coverage.xml *.py,cover .hypothesis/ .pytest_cache/ +cover/ # Translations *.mo @@ -72,6 +72,7 @@ instance/ docs/_build/ # PyBuilder +.pybuilder/ target/ # Jupyter Notebook @@ -82,7 +83,9 @@ profile_default/ ipython_config.py # pyenv -.python-version +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. @@ -91,7 +94,22 @@ ipython_config.py # install all needed dependencies. #Pipfile.lock -# PEP 582; used by e.g. github.com/David-OConnor/pyflow +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm __pypackages__/ # Celery stuff @@ -128,5 +146,15 @@ dmypy.json # Pyre type checker .pyre/ -# Idea project settings -.idea +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 81c6ac83..8f9b0b04 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -54,7 +54,7 @@ repos: - id: mypy - repo: https://github.com/ComPWA/mirrors-pyright - rev: v1.1.299 + rev: v1.1.331 hooks: - id: pyright diff --git a/contributing.md b/contributing.md deleted file mode 100644 index eb3f49c2..00000000 --- a/contributing.md +++ /dev/null @@ -1,90 +0,0 @@ -# contributing - -## issue - -- если увидели открытый issue и готовы им заняться, отпишите что берете на себя и сколько потребуется предварительно времени -- если хотите добавить что-то новое, следует начать с создания issue и описания - -## pull request - -- создайте fork и клонируйте репозиторий -- создайте новую ветку (к примеру, `git checkout -b issue-id-short-name`) -- изменяйте/добавляйте что нужно -- push -- pull request -- ожидайте комментариев от команды курса - -если состоите в какой-нибудь из команд курса, то начинайте со 2 шага - -### pre-commit - -как часть непрерывной интеграции (ci) - -- установить [`pre-commit`](https://pre-commit.com/) - - ``` - pip install pre-commit - ``` - -- запустить - - ``` - pre-commit run -a - ``` - -после чего, автоматически произойдёт запуск указанных в `.pre-commit-config.yaml` библиотек где часть автоматически изменит что нужно (добавить пустую строку в конце), а остальная с ошибкой подскажет что требуется править. для проверки всё ли нормально смело можете запускать сколько потребуется раз - -## добавить лекцию - -все лекции лежат в `./docs/` в соответствующих директориях - -всё содержание книги находится в `./mkdocs.yml` по ключу `nav` - -картинки и иже находятся в `_static/` в нужном разделе/вкладке (к примеру, в `./docs/base/` – «основы python» – не более) - -## авторство - -если была создана лекция и/или любое иное важное улучшение, то смело добавляйте себя в неё и в общий [список авторов курса](./docs/authors.md) - -## окружение/среда - -курс разрабатывается на движке [mkdocs](https://github.com/squidfunk/mkdocs-material) - -### собрать промежуточную версию книги - -#### gh actions (для членов команды курса) - -- [перейти во вкладку `actions` и выбрать `cd-stage` процесс](https://github.com/open-data-science/pycourse/actions/workflows/cd-stage.yml) -- справа в таблице в выпадающем меню `run workflow` выбрать нужную ветку и нажать зелёную кнопку запуска -- после пары минут по адресу [pycourse-page-stage.netlify.app](https://pycourse-page-stage.netlify.app/) можно лицезреть собранную книгу - -#### локально - -- клонировать нужную ветку (или fork) -- установить нужные библиотеки (лучше в отдельном виртуальном окружении) - - ``` - pip install -r requirements.txt - ``` - -- запустить - - ``` - mkdocs serve --dirtyreload - ``` - -- перейти по предложенной внутренней ссылке, дабы открыть книгу - -### стилистика - -на странице движка – [https://squidfunk.github.io/mkdocs-material/reference/](https://squidfunk.github.io/mkdocs-material/reference/) – имеются примеры (`sponsors only` не наш случай) как можно во всю его использовать, не ограничивайте себя, главное чтобы было понятно даже школьнику - -меж тем - -- вместо `–` использовать `–` (`option` + `-` для macos) -- рисунки в `.png` формате -- примеры кода всегда содержат нумерацию строк -- `""` в коде -- `«»` в простом тексте -- лучше не использовать «мы»/«вы»/«вас»/«нас»/.. -- .. diff --git a/docs/assets/aero_python.png b/docs/assets/aero_python.png deleted file mode 100644 index 004538a0..00000000 Binary files a/docs/assets/aero_python.png and /dev/null differ diff --git a/docs/assets/blackhole.png b/docs/assets/blackhole.png deleted file mode 100644 index 3fe24b3c..00000000 Binary files a/docs/assets/blackhole.png and /dev/null differ diff --git a/docs/assets/logo.png b/docs/assets/logo.png deleted file mode 100644 index 1560be82..00000000 Binary files a/docs/assets/logo.png and /dev/null differ diff --git a/docs/assets/why_py_stackoverflow_1.png b/docs/assets/why_py_stackoverflow_1.png deleted file mode 100644 index e1e751bd..00000000 Binary files a/docs/assets/why_py_stackoverflow_1.png and /dev/null differ diff --git a/docs/assets/why_py_stackoverflow_2.png b/docs/assets/why_py_stackoverflow_2.png deleted file mode 100644 index f03ed774..00000000 Binary files a/docs/assets/why_py_stackoverflow_2.png and /dev/null differ diff --git a/docs/assets/why_py_stackoverflow_3.png b/docs/assets/why_py_stackoverflow_3.png deleted file mode 100644 index 50cb2582..00000000 Binary files a/docs/assets/why_py_stackoverflow_3.png and /dev/null differ diff --git a/docs/assets/why_py_tiobe_rating.png b/docs/assets/why_py_tiobe_rating.png deleted file mode 100644 index bf4e2db8..00000000 Binary files a/docs/assets/why_py_tiobe_rating.png and /dev/null differ diff --git a/docs/authors.md b/docs/authors.md deleted file mode 100644 index 924a1d02..00000000 --- a/docs/authors.md +++ /dev/null @@ -1,20 +0,0 @@ -# авторы - -## создатель - -- [vvssttkk](https://github.com/vvssttkk) - -## авторы - -- [Котенков Игорь](https://github.com/stalkermustang) -- [Овсянникова Александра](https://github.com/alexmorphine) -- [Чернов Илья](https://github.com/ch3rn0v/) -- [Baushenko Mark](https://github.com/e0xextazy) -- [Kosarevsky Dmitry](https://github.com/dKosarevsky) -- [vvssttkk](https://github.com/vvssttkk) -- .. - -## техническая поддержка - -- [vvssttkk](https://github.com/vvssttkk) -- .. diff --git a/docs/base/_static/box_with_a_name.png b/docs/base/_static/box_with_a_name.png deleted file mode 100644 index 3f44b8aa..00000000 Binary files a/docs/base/_static/box_with_a_name.png and /dev/null differ diff --git a/docs/base/_static/class_and_obj1.png b/docs/base/_static/class_and_obj1.png deleted file mode 100644 index 9afc1755..00000000 Binary files a/docs/base/_static/class_and_obj1.png and /dev/null differ diff --git a/docs/base/_static/class_and_obj_house.png b/docs/base/_static/class_and_obj_house.png deleted file mode 100644 index 1e8e4a89..00000000 Binary files a/docs/base/_static/class_and_obj_house.png and /dev/null differ diff --git a/docs/base/_static/class_and_obj_pika.png b/docs/base/_static/class_and_obj_pika.png deleted file mode 100644 index fcbeba51..00000000 Binary files a/docs/base/_static/class_and_obj_pika.png and /dev/null differ diff --git a/docs/base/_static/debug_hard.png b/docs/base/_static/debug_hard.png deleted file mode 100644 index d56cb68f..00000000 Binary files a/docs/base/_static/debug_hard.png and /dev/null differ diff --git a/docs/base/_static/debug_solved.png b/docs/base/_static/debug_solved.png deleted file mode 100644 index 87efdcfa..00000000 Binary files a/docs/base/_static/debug_solved.png and /dev/null differ diff --git a/docs/base/_static/example_debug.png b/docs/base/_static/example_debug.png deleted file mode 100644 index 33328445..00000000 Binary files a/docs/base/_static/example_debug.png and /dev/null differ diff --git a/docs/base/_static/example_traceback.png b/docs/base/_static/example_traceback.png deleted file mode 100644 index 0e842d90..00000000 Binary files a/docs/base/_static/example_traceback.png and /dev/null differ diff --git a/docs/base/_static/interactive_map.gif b/docs/base/_static/interactive_map.gif deleted file mode 100644 index 14395730..00000000 Binary files a/docs/base/_static/interactive_map.gif and /dev/null differ diff --git a/docs/base/_static/jupyter_console.png b/docs/base/_static/jupyter_console.png deleted file mode 100644 index d84862fb..00000000 Binary files a/docs/base/_static/jupyter_console.png and /dev/null differ diff --git a/docs/base/_static/jupyter_create.png b/docs/base/_static/jupyter_create.png deleted file mode 100644 index bc63f6cb..00000000 Binary files a/docs/base/_static/jupyter_create.png and /dev/null differ diff --git a/docs/base/_static/jupyter_test_code_run.png b/docs/base/_static/jupyter_test_code_run.png deleted file mode 100644 index 5d095fb8..00000000 Binary files a/docs/base/_static/jupyter_test_code_run.png and /dev/null differ diff --git a/docs/base/_static/jupyter_ui_1.png b/docs/base/_static/jupyter_ui_1.png deleted file mode 100644 index 5b1a9332..00000000 Binary files a/docs/base/_static/jupyter_ui_1.png and /dev/null differ diff --git a/docs/base/_static/jupyter_ui_10.png b/docs/base/_static/jupyter_ui_10.png deleted file mode 100644 index ef84da32..00000000 Binary files a/docs/base/_static/jupyter_ui_10.png and /dev/null differ diff --git a/docs/base/_static/jupyter_ui_2.png b/docs/base/_static/jupyter_ui_2.png deleted file mode 100644 index bc4bd1c4..00000000 Binary files a/docs/base/_static/jupyter_ui_2.png and /dev/null differ diff --git a/docs/base/_static/jupyter_ui_3.png b/docs/base/_static/jupyter_ui_3.png deleted file mode 100644 index 9d92377e..00000000 Binary files a/docs/base/_static/jupyter_ui_3.png and /dev/null differ diff --git a/docs/base/_static/jupyter_ui_4.png b/docs/base/_static/jupyter_ui_4.png deleted file mode 100644 index eb0589f3..00000000 Binary files a/docs/base/_static/jupyter_ui_4.png and /dev/null differ diff --git a/docs/base/_static/jupyter_ui_5.png b/docs/base/_static/jupyter_ui_5.png deleted file mode 100644 index e7422d31..00000000 Binary files a/docs/base/_static/jupyter_ui_5.png and /dev/null differ diff --git a/docs/base/_static/jupyter_ui_6.png b/docs/base/_static/jupyter_ui_6.png deleted file mode 100644 index 454aa17f..00000000 Binary files a/docs/base/_static/jupyter_ui_6.png and /dev/null differ diff --git a/docs/base/_static/jupyter_ui_7.png b/docs/base/_static/jupyter_ui_7.png deleted file mode 100644 index 55e9f4eb..00000000 Binary files a/docs/base/_static/jupyter_ui_7.png and /dev/null differ diff --git a/docs/base/_static/jupyter_ui_8.png b/docs/base/_static/jupyter_ui_8.png deleted file mode 100644 index c1096008..00000000 Binary files a/docs/base/_static/jupyter_ui_8.png and /dev/null differ diff --git a/docs/base/_static/jupyter_ui_9.png b/docs/base/_static/jupyter_ui_9.png deleted file mode 100644 index 6fcb32d4..00000000 Binary files a/docs/base/_static/jupyter_ui_9.png and /dev/null differ diff --git a/docs/base/_static/legb.png b/docs/base/_static/legb.png deleted file mode 100644 index 0b822766..00000000 Binary files a/docs/base/_static/legb.png and /dev/null differ diff --git a/docs/base/_static/list_indexing_1.png b/docs/base/_static/list_indexing_1.png deleted file mode 100644 index 19e88d69..00000000 Binary files a/docs/base/_static/list_indexing_1.png and /dev/null differ diff --git a/docs/base/_static/match_case.png b/docs/base/_static/match_case.png deleted file mode 100644 index 175cd05a..00000000 Binary files a/docs/base/_static/match_case.png and /dev/null differ diff --git a/docs/base/_static/operators_table.png b/docs/base/_static/operators_table.png deleted file mode 100644 index d75b0227..00000000 Binary files a/docs/base/_static/operators_table.png and /dev/null differ diff --git a/docs/base/_static/output_plt_scatter.png b/docs/base/_static/output_plt_scatter.png deleted file mode 100644 index bd52be9e..00000000 Binary files a/docs/base/_static/output_plt_scatter.png and /dev/null differ diff --git a/docs/base/_static/walrus.png b/docs/base/_static/walrus.png deleted file mode 100644 index c27b91be..00000000 Binary files a/docs/base/_static/walrus.png and /dev/null differ diff --git a/docs/base/conditional_comparison.md b/docs/base/conditional_comparison.md deleted file mode 100644 index d356b9b8..00000000 --- a/docs/base/conditional_comparison.md +++ /dev/null @@ -1,417 +0,0 @@ -# Условные конструкции, булева логика и сравнения - -!!! info "Автор(ы)" - - - [Котенков Игорь](https://github.com/stalkermustang) - - [Baushenko Mark](https://github.com/e0xextazy) - -## Ветвление логики - -В прошлых лекциях рассмотрели программы с линейной структурой: сначала выполнялась первая конструкция (например, объявление переменной), затем вторая (преобразование переменной или расчет по формуле), после – третья (`print` для вывода результатов). Можно сказать, что происходило последовательное исполнение команд, причем каждая инструкция выполнялась ^^обязательно^^. Но что делать, если хочется опираться на обстоятельства и принимать решения о том, выполнять одну часть кода или другую? - -Допустим, по числу `x` нужно определить его абсолютную величину, то есть модуль. Программа должна напечатать значение переменной `x`, если `x > 0` или же величину `-x` в противном случае (`-(-5) = 5`). Эту логику можно записать следующим образом: - -```python linenums="1" -x = -3 # попробуйте поменять значение переменной - -if x > 0: - print("Исходный x больше нуля") - print(x) -else: - print("Исходный x меньше или равен нулю") - print(-x) -``` -```bash -Исходный x меньше или равен нулю -3 -``` - -В этой программе используется условная инструкция `if` (в переводе с английского _«если»_) – это ключевое зарезервированное слово (так нельзя назвать свою переменную), указывающее на условную конструкцию. После `if` следует указать вычислимое выражение, которое можно проверить на истинность (то есть можно сказать, правда это или нет). Общий вид конструкции следующий: - -```python linenums="1" -if (Условие): - <Блок инструкций 1> -else: - <Блок инструкций 2> -``` - -`else` – тоже ключевое слово (в переводе – «иначе»). Таким образом, можно в голове придерживаться такой интерпретации: «^^если^^ условие верно (истинно), ^^то^^ выполни первый блок команд, ^^иначе^^ выполни второй блок». - -Условная инструкция содержит как минимум ключевое слово `if` (единожды), затем может идти любое количество (включая ноль) блоков с условием `else if <условие>` (_иначе если_, то есть будет выполнена проверка нового условия в случае, если первая проверка в `if` не прошла, кратко `else if` записывается как `elif`), затем – опционально – конструкция `else`. Логика чтения и выполнения кода сохраняет порядок ^^сверху вниз^^. Как только одно из условий будет выполнено, выполнится соответствующая инструкция (или набор инструкций), а все последующие блоки будут проигнорированы. Это проиллюстрировано в коде: - -```python linenums="1" -x = -3.8 # попробуйте поменять значение переменной - -if x > 0: - print("x больше нуля") -elif x < 0: # можно написать "else if x < 0:" - print("x меньше нуля") -else: - print("x в точности равен нулю") -print("Такие дела!") -``` -```bash -x меньше нуля -Такие дела! -``` - -Понятно, что `x` не может одновременно быть и больше нуля, и меньше (или равен ему). Среди всех трех `print`-блоков будет выполнен ^^только один^^. Если `x` действительно больше нуля, то второе условие (`x < 0`) даже не будет проверяться – Python сразу же перейдет к последней строке и выведет надпись «Такие дела!». - -Чтобы лучше разобраться в том, как работает код, можно использовать ^^визуализаторы^^ – например, [такой](https://pythontutor.com/visualize.html). Прогоняйте через него весь код (даже в несколько строк) и сверяйте со своими ожиданиями от его работы. - -## А что вообще такое эти ваши условия? - -Выше было указано, что после конструкций `if`/`else if`/`elif` необходимо указать условие, которое еще и должно быть истинным или ложным («правда или нет»). Давайте попробуем определить необходимый тип переменной. - -```python linenums="1" -x = -3.8 - -condition_1 = x > 0 -condition_2 = x < 0 - -print(condition_1, type(condition_1)) -print(condition_2, type(condition_2)) -``` -```bash -False -True -``` - -Видно, что оба условия имеют один и тот же тип - `bool`, то есть `boolean`. По [определению](https://developer.mozilla.org/ru/docs/Glossary/Boolean): - -!!! note "Замечание" - - Boolean (Булев, Логический тип данных) – примитивный тип данных в информатике, которые могут принимать 2 возможных значения, иногда называемых истиной (True) и ложью (False). - -Оказывается, что в коде выше были получены ^^все^^ возможные варианты булевой переменной – это истина (`True`, пишется только с заглавной буквы) и ложь (`False`, аналогично). Никаких других значений быть для условия не может. Вот такой это простой тип данных. - -## Способы получения `bool` - -Какими вообще могут быть условия? Как с ними можно обращаться? Согласно [официальной документации](https://docs.python.org/3/library/stdtypes.html), в Python есть такие операторы сравнения: - -
- ![](./_static/operators_table.png) -
- Все операции сравнения работают нативно (так же, как и в математике) -
-
- -```python linenums="1" -print(3.0 > 3) -print(3.0 == 3) -``` -```bash -False -True -``` - -Здесь практически нечего рассматривать, операторы сравнения они и в Python операторы. Куда интереснее принцип ^^объединения различных условий в одно^^ – для создания комплексной логики. - -Пусть стоит задача определения четверти точки по ее координатам на двумерной плоскости. Решение такой задачи может быть записано следующим образом: - -```python linenums="1" -x = -3.6 -y = 2.5432 - -if x > 0: - if y > 0: - # x > 0, y > 0 - print("Первая четверть") - else: - # x > 0, y < 0 - print("Четвертая четверть") -else: - if y > 0: - # x < 0, y > 0 - print("Вторая четверть") - else: - # x < 0, y < 0 - print("Третья четверть") -``` -```bash -Вторая четверть -``` - -Пример показывает, что выполняемым блоком кода может быть любой блок Python, включая новый логический блок с `if-else` конструкцией. Однако его можно сократить с помощью ^^логических операторов^^ `and`, `or` и `not`. Это стандартные логические операторы [булевой алгебры](https://ru.wikipedia.org/wiki/Булева_алгебра). - -Логическое ^^И^^ является бинарным оператором (то есть оператором с двумя операндами: левым и правым) и имеет вид `and`. Оператор `and` возвращает `True` тогда и только тогда, когда ^^оба его операнда имеют значение^^ `True`. - -Логическое ^^ИЛИ^^ является бинарным оператором и возвращает `True` тогда и только тогда, когда ^^хотя бы один операнд равен^^ `True`. Оператор «логическое ИЛИ» имеет вид `or`. - -Логическое ^^НЕ^^ (отрицание) является унарным (то есть ^^с одним операндом^^) оператором и имеет вид `not`, за которым следует единственный операнд. Логическое НЕ возвращает `True`, ^^если операнд равен^^ `False` и ^^наоборот^^. - -Эти правила необходимо запомнить для успешного создания сложных условий с целью разделения логики, заложенной в Python-коде. - -Проиллюстрируем правила в коде на простых примерах. Обратите внимание на то, как можно объявлять `bool`-переменные – это не сложнее, чем создание целочисленного значения: - -```python linenums="1" -true_value = True -false_value = False - -# False потому, что один из операндов является False -some_value = true_value and false_value -print(some_value) - -# True потому, что хотя бы один из операндов равен True -some_value = true_value or false_value -print(some_value) - -# отрицание True (истины) есть False (ложь) -some_value = not true_value -print(some_value == false_value) - -# пример сложного условия - порядок лучше в явном виде задавать скобками -hard_condition = (not true_value or false_value) or (true_value != false_value) -print(hard_condition) -``` -```bash -False -True -True -True -``` - -Теперь попробуем их применить на приближенных к практике примерах: - -```python linenums="1" -x = -3.6 -y = 2.5432 - -if x > 0 and y > 0: # конструкция заменяет два вложенных if - print("Первая четверть") -elif x > 0 and y < 0: - print("Четвертая четверть") -elif y > 0: - print("Вторая четверть") -else: - print("Третья четверть") - -# определим, большое ли число x (в терминах модуля) -x_is_small = (x < 3) and (x > -3) -# число большое, если оно не маленькое (по модулю) -x_is_large = not x_is_small # можно отрицать факт малости x - -print("Is x small? ", x_is_small) -print("Is x large? ", x_is_large) - -# так тоже можно писать - на манер неравенств в математике -another_x_is_small = -3 < x < 3 -print(another_x_is_small) -print(another_x_is_small == x_is_small) -``` -```bash -Вторая четверть -Is x small? False -Is x large? True -False -True -``` - -Так как вторая переменная `x_is_large` – это отрицание (`not`) первой (`x_is_small`), то они ^^никогда^^ не будут равны. - -## Блоки кода и отступы - -В примерах выше наверняка заметили упоминание термина «блок кода», а также откуда-то взявшиеся отступы после условий, и это не случайно. Во-первых, давайте признаем, что так условные конструкции (особенно вложенные!) читать куда легче, и глаза не разбегаются. Во-вторых, это особенность языка Python – здесь не используются скобки `{`, `}` для указания блоков, все форматирование происходит с помощью отступов. Отступы ^^всегда^^ добавляются в строки кода ^^после двоеточия^^. - -Для выделения блока инструкций (строк кода, выполняющихся подряд при любых условиях), относящихся к инструкциям `if`, `else` или другим, изучаемым далее, в языке Python используются ^^отступы^^. Все инструкции, которые относятся к одному блоку, должны иметь ^^равную величину отступа^^, то есть одинаковое число ^^пробелов в начале строки^^. В качестве отступа [PEP 8](https://www.python.org/dev/peps/pep-0008/#tabs-or-spaces) рекомендует использовать ^^отступ в четыре пробела^^ и не рекомендует использовать символ табуляции. Если нужно сделать еще одно вложение блока инструкций, достаточно добавить еще четыре пробела (см. пример выше с поиском четверти на плоскости). - -!!! tip "Совет" - - Хоть и не рекомендуется использовать символ табуляции для создания отступов, кнопка ++tab++ на клавиатуре в `Jupyter`-ноутбуке (при курсоре, указывающим на начало строки кода) создаст отступ в четыре пробела. Пользуйтесь этим, чтобы не перегружать клавишу пробела лишними постукиваниями. - -## Контекстные менеджеры - -Контекстные менеджеры это ^^специальные конструкции^^, которые представляют из себя блоки кода, заключенные в инструкцию `with`. Простейшей функцией, использующей данный протокол является функция `open()`. Каждый раз, когда открывается файл его необходимо закрыть, чтобы записать выходные данные на диск (на самом деле Python вызывает метод `close()` автоматически, но явное его использование ^^является хорошим тоном^^). Например: - -```python linenums="1" -fp = open("./file.txt", "w") -fp.write("Hello, World!") -fp.close() -``` - -Чтобы каждый раз не вызывать метод `close()`, можно воспользоваться контекстным менеджером функции `open()`, который автоматически закроет файл после выхода из блока: - -```python linenums="1" -with open("./file.txt", "w") as fp: - fp.write("Hello, World!") -``` - -Для определения переменной, которая будет содержать контекстный менеджер используется инструкция `as` после которой идет сама переменная. Но есть и другой способ задать переменную для контекстного менеджера: - -```python linenums="1" -with (fp := open("file.txt", "w")): - fp.write("Hello, World!") -``` - -В данном случае используется оператор `:=`. - -Что же делать, если нужно вести запись в 2 файла одновременно? На помощь приходят контекстные менеджеры в круглых скобках: - -```python linenums="1" -with ( - open("./file1.txt", "w") as fp1, - open("./file2.txt", "w") as fp2 -): - fp1.write("Hello, World 1!") - fp2.write("Hello, World 2!") -``` - -В данном случае создадутся 2 файла на диске с именем `file1.txt` и `file2.txt`, которые будут содержать строчки «Hello, World 1!» и «Hello, World 2!» соответственно. Но какой ещё вид могут иметь контекстные менеджеры в круглых скобках? Вот несколько примеров как их можно использовать в коде: - -```python linenums="1" -with (CtxManager() as example): - ... # Какой-то блок кода - -with ( - CtxManager1(), - CtxManager2() -): - ... # Какой-то блок кода - -with ( - CtxManager1() as example, - CtxManager2() -): - ... # Какой-то блок кода - -with ( - CtxManager1(), - CtxManager2() as example -): - ... # Какой-то блок кода - -with ( - CtxManager1() as example1, - CtxManager2() as example2 -): - ... # Какой-то блок кода -``` - -!!! warning "Внимание" - - В данном разделе, все примеры содержали только одну функцию/протокол `open()`, так как цель раздела ознакомиться со структурой контекстного менеджера, а не с функционалом протоколов. Позже будут разбираться протоколы и как их писать с нуля. - -## `Match-case` конструкция (структурное сопоставление с шаблоном) - -Сопоставление подразумевает определение при операторе `match` искомого значения, после которого можно перечислить несколько ^^потенциальных вариантов ветвления^^ («кейсов» от слова case), каждый с оператором `case`. В месте обнаружения совпадения между `match` и `case` выполняется соответствующий блок кода. Например: - -```python linenums="1" -http_code = "418" - -match http_code: - case "200": - print("OK") - case "404": - print("Not Found") - case "418": - print("I'm a teapot") - case _: - print("Code not found") -``` -```bash -I'm a teapot -``` - -Здесь происходит проверка ^^нескольких условий^^ и выполнение разных операций на основе значения, которое находится внутри `http_code`. - -![](./_static/match_case.png) - -Сразу становится очевидным, что «да», можно выстроить ту же логику, используя набор инструкций `if-elif-else`, например: - -```python linenums="1" -http_code = "418" - -if http_code == "418": - print("OK") -elif http_code == "404": - print("Not Found") -elif http_code == "418" - print("I'm a teapot") -else: - print("Code not found") -``` -```bash -I'm a teapot -``` - -Тем не менее, с помощью инструкций `match-case` можно избавиться от повторения `http_code ==`, что ^^повышает чистоту кода^^ при тестировании на соответствие многим разным условиям. - -!!! note "Замечание" - - Инструкция `match-case` позволяет проверять на совпадение не только тип субъекта, но и его структуру. - -Если все ещё не верите в удобство этой инструкции, давайте посмотрим на пример, после которого точно не будет сомнений: - -```python linenums="1" -x = ("0.0.0.0", "8000") - -match x: - case host, port: - mode = "http" - case host, port, mode: - pass - -print(host, port, mode) -``` -```bash -0.0.0.0 8000 http -``` - -Здесь ожидается получение деталей соединения в формате [кортежа](./list_loop.md#tuple) и присваивание их нужным переменным. - -В этом случае, если `mode` соединения в кортеже не определен (например, было передано только два значения – `host` и `port`), предполагается, что режим соединения `http`. Тем не менее в других случаях можно ожидать, что режим будет определен явно. Тогда вместо этого будет передан кортеж вида `(, , "ftp")`, и `mode` уже не устанавливается как `http`, например: - -```python linenums="1" -x = ("0.0.0.0", "8000", "ftp") - -match x: - case host, port: - mode = "http" - case host, port, mode: - pass - -print(host, port, mode) -``` -```bash -0.0.0.0 8000 ftp -``` - -Если прописать ту же логику с помощью `if-elif-esle`, то получится громоздкая конструкция: - -```python linenums="1" -if isinstance(x, tuple) and len(x) == 2: - host, port = x - mode = "http" -elif isinstance(x, tuple) and len(x) == 3: - host, port, mode = x -``` - -```python linenums="1" -x = ("0.0.0.0", "8000") -print(host, port, mode) -``` -```bash -0.0.0.0 8000 http -``` - -```python linenums="1" -x = ("0.0.0.0", "8000", "ftp") -print(host, port, mode) -``` -```bash -0.0.0.0 8000 ftp -``` - -Как можно видеть, здесь явно проверяется ^^тип входного значения^^ с помощью функции `isinstance()` и ^^структура^^ с помощью функции `len()`. - -## Что узнали из лекции - -- Для задания логики выполнения кода и создания нелинейности используются ^^условные инструкции^^, поскольку они следуют некоторым условиям. -- Условная инструкция задается ключевым словом `if`, после которого может следовать несколько (от нуля) блоков `else if`/`elif`, и – опционально – в конце добавляется `else`, если ни один из блоков выше не сработал. -- Условия должны быть ^^булевого типа^^ (`bool`) и могут принимать ^^всего два значения^^ – `True` и `False`. Выполнится тот блок кода, который задан истинным (`True`) условием (и только первый!). -- Условные конструкции можно вкладывать друг в друга, а также объединять с помощью ^^логических операторов^^ `and`, `or` и `not`. -- ^^Блок кода^^ – это несколько подряд идущих команд, которые будут выполнены последовательно. -- Чтобы выделить блок кода после условия, используйте ^^отступы^^ – четыре пробела. -- Чтобы создать отступ в `Jupyter`, нужно нажать ++tab++ в начале строки кода. -- Упростить закрытие файлов можно с помощью контекстного менеджера. -- Если логика кода подразумевает ^^большое использование сравнений^^ или ^^сложные логические конструкции^^, то лучшим вариантом будет воспользоваться инструкцией `match-case`. diff --git a/docs/base/dictionary.md b/docs/base/dictionary.md deleted file mode 100644 index 62f00e26..00000000 --- a/docs/base/dictionary.md +++ /dev/null @@ -1,549 +0,0 @@ -# Словари - -!!! info "Автор(ы)" - - - [Овсянникова Александра](https://github.com/alexmorphine) - -## Что такое `dict` - -`dict` (от английского «dictionary», словарь) – еще один тип данных в Python. Словари хранят пары `ключ`: `значение`. То есть в списках можно достать элемент, если указать его позицию в виде целого числа, а в словарях – тот самый `ключ`. `dict` – ^^неупорядоченный^^ тип данных, поэтому достать элемент по номеру не получится, но отображение содержимого будет ^^в порядке добавления^^ элементов. ^^Уникальность^^ ключей должна поддерживаться, чтобы всегда можно было быстро найти одно единственно верное `значение`. - -В некоторых языках программирования можно встретить ассоциативные массивы – полную аналогию `dict`. Также вспомним базы данных, широко использующиеся во всём мире для хранения информации: в таблице можно установить первичный ключ, который уникально идентифицирует запись, как и `ключ` соответствует `значению` в словаре. Самый простой пример ключа - порядковый номер объекта! - -### Создание словаря - -Использовать словарь стоит, когда нужно сохранять объекты с какими-то ключами и обращаться к объектам по известным ключам. Один из способов определения словаря: указание пар `ключ`: `значение` через^запятую внутри фигурных скобок `{}`. Напоминает `set`, правда? `{}` позволяет создать пустой словарь, но не пустое множество. - -Например, решили упростить себе жизнь и больше не запоминать дни рождения коллег. Вместо этого, лучше хранить их в одном месте: - -```python linenums="1" -# локально попробуйте поменять значение переменной dates -dates = {"Кунг Фьюри": "1968-09-09", "Наташа Романова": "1985-03-15"} -print(dates) -``` -```bash -{'Кунг Фьюри': '1968-09-09', 'Наташа Романова': '1985-03-15'} -``` - -В примере `dates` имеет две пары значений. В первой паре строка `"Кунг Фьюри"` является _ключом_, а `"1968-09-09"` – его _значением_. - -### Получение значения по ключу - -Чтобы получить значение по ключу, необходимо обратиться к переменной, содержащей словарь, и указать ключ в квадратных скобках `[]`: - -```python linenums="1" -dates["Кунг Фьюри"] -``` -```bash -'1968-09-09' -``` - -Если указать неверный ключ в `[]`, Python будет ругаться: выбросит ошибку `KeyError` и перестанет выполнять код. Чуть ниже посмотрим, как можно избежать таких ситуаций. - -```python linenums="1" -# пока этого ключа нет в словаре, будет ошибка при обращении -# поэтому используем перехват ошибок -try: - print(dates["Капитан Ямайка"]) - -except KeyError as e: - print(f"Ключа действительно нет: {e}") -``` -```bash -Ключа действительно нет: 'Капитан Ямайка' -``` - -### Изменение и добавление значений - -Синтаксис изменения значения по ключу и добавления нового ключа со значением одинаковый: в `[]` нужно указать ключ, поставить `=` и указать значение, которое теперь будет соответствовать ключу. - -```python linenums="1" -# этот ключ уже был в примере -dates["Кунг Фьюри"] = "1960-09-09" - -# а такого не было -dates["Капитан Ямайка"] = "1930-10-04" - -print(dates) -``` -```bash -{'Кунг Фьюри': '1960-09-09', 'Наташа Романова': '1985-03-15', 'Капитан Ямайка': '1930-10-04'} -``` - -Если ключ уже был в словаре, значение по нему изменится на новое, а старое будет удалено. Указание нового ключа со значением добавляет пару в словарь. - -## Основные методы словаря - -### Проверка вхождения и `get()` - -Помните, ранее говорили, что обращение к несуществующему ключу приводит к ошибке? Пришло время посмотреть пару способов борьбы! - -Можно проверить, есть ли интересующий ключ среди множества ключей словаря. Это делается при помощи бинарного оператора `in`. Слева должен быть указан ключ, справа – переменная со словарем: - -```python linenums="1" -# еще способ создания: пары можно передавать как аргументы dict через `=` -marks = dict(линал=100, английский=92) - -print(f'{"матан" in marks = }') -print(f'{"линал" in marks = }') -``` -```bash -"матан" in marks = False -"линал" in marks = True -``` - -В коде проверку можно использовать в условной конструкции `if`, чтобы принимать решение в зависимости от наличия ключа: - -```python linenums="1" -if "матан" in marks: - print(marks["матан"]) - -else: - print("Нет оценки по матану :(") -``` -```bash -Нет оценки по матану :( -``` - -Теперь о методе `get()`: при помощи его тоже можно получать значения из словаря по ключу. `KeyError` никогда не появится: если ключа нет, по умолчанию возвращается `None`: - -```python linenums="1" -empty_dict = {} - -print(empty_dict.get("ключ")) -``` -```bash -None -``` - -Вторым аргументом метода `get()` можно указать значение, которое должно возвращаться вместо `None`, когда ключ не был найден: - -```python linenums="1" -print(empty_dict.get("ключ", -1)) -``` -```bash --1 -``` - -### Что такое "длина словаря"? - -Функция `len()` для словаря будет возвращать количество пар `ключ`: `значение` (их столько же, сколько ключей), которое в нём содержится: - -```python linenums="1" -# empty_dict – пустой словарь, поэтому длина равна 0 -print(f"{len(empty_dict) = }") - -# а вот словарь marks уже содержит две пары, поэтому длина 2 -print(f"{len(marks) = }") -``` -```bash -len(empty_dict) = 0 -len(marks) = 2 -``` - -### Удаление из словаря - -Есть несколько способов очистки в словаре: можно убирать по ключу, а можно сразу удалить все! - -- при помощи инструкции `del` (от английского _«delete»_) можно удалить пару `ключ`: `значение` (_удаление ключа эквивалентно удалению пары `ключ`: `значение`, так как теряем возможность найти то самое `значение`_), в общем виде: - - ```python linenums="1" - # таким образом из словаря "словарь" будет удален ключ "название_ключа" - # и соответствующее ему значение - del словарь[название_ключа] - ``` - - Предположим, коллега из самого первого примера уволился и больше нет смысла хранить его день рождения: - - ```python linenums="1" - # из словаря dates удаляется ключ "Наташа Романова" - del dates["Наташа Романова"] - - print(dates.get("Наташа Романова")) - ``` - ```bash - None - ``` - -- `pop()` - метод, который достает значение, хранящееся по переданному ключу, и сразу удаляет ключ из словаря: - - ```python linenums="1" - # ещё один способ создания словаря из последовательности пар - holidays = dict([("January", [1, 2, 3, 4]), ("Feburary", [23]), ("March", [8])]) - - # pop() возвращает значение, соответствующее ключу, значит его можно присвоить переменной - january_days = holidays.pop("January") - - # напечатается соответствующий массив - print(f"{january_days = }") - print(f"{holidays = }") - ``` - ```bash - january_days = [1, 2, 3, 4] - holidays = {'Feburary': [23], 'March': [8]} - ``` - - Для метода `pop()` есть возможность указать значение, которое будет возвращено при обращении к несуществующему ключу. Почти как `get()`, но всё-таки, без указания этого значения, `pop()` выбрасывает `KeyError`. - -- `popitem()` имеет схожее название, но не путайте с предыдущим методом: этот на вход не принимает `ключ`, а возвращает пару `ключ`: `значение`, которая была добавлена последней (_такое поведение гарантируется с Python ^^3.7^^_). - - ```python linenums="1" - # в результате – последняя добавленная пара - print(f"{holidays.popitem() = }") - print(f"{holidays = }") - ``` - ```bash - holidays.popitem() = ('March', [8]) - holidays = {'Feburary': [23]} - ``` - -- `clear()` позволяет удалить сразу все ключи словаря, то есть полностью его очистить: - - ```python linenums="1" - # вернёмся к предыдущему примеру - # словарь становится пустой - holidays.clear() - - # значит, длина равна 0 - print(f"{len(holidays) = }") - ``` - ```bash - len(holidays) = 0 - ``` - -!!! danger "Важно" - - Обратите внимание на то, как работают методы `pop()`, `popitem()` и `clear()`: как только вызываются, словарь меняет свой состав (_изменения происходят in place_, то изменить по месту без копирования). - -### Обновление и добавление ключей - -Лицезрели, что значения в словарь можно добавлять или менять, обращаясь по ключу. Python предоставляет возможность не писать кучу присваиваний, а использовать лаконичный метод `update()`, который на вход может принимать либо другой словарь, либо пары `ключ`: `значение` в какой-то последовательности (например, [кортежи](./list_loop.md#tuple) по два значения в списке: первое – ключ, второе – значение) - -```python linenums="1" -# создадим два словаря: в первом уже есть два ключа -quidditch_team = {"Fred Weasley": "3rd year", "George Weasley": "3rd year"} - -# во втором – один ключ -new_members = {"Harry Potter": "1st year"} - -# добавим пары из new_members -# метод update() также работает in place, поэтому после выполнения данной -# строки кода, в словаре quidditch_team станет три ключа -quidditch_team.update(new_members) - -print(quidditch_team["Harry Potter"]) -``` -```bash -1st year -``` - -А что, если в `update()` передать пары, ключ которых уже был в словаре? Значения по дублирующимся ключам будут ^^перезаписаны^^ на новые: - -```python linenums="1" -# данный ключ (то, что записано первым в кортеже) уже есть в quidditch_team -member_update = [("Harry Potter", "2nd year")] - -# значение, соответствующее "Harry Potter", будет переписано -quidditch_team.update(member_update) - -print(quidditch_team["Harry Potter"]) -``` -```bash -2nd year -``` - -## Доступ к ключам и значениям - -В Python можно без проблем извлекать отдельно по ключам или значениям, а также итерироваться по элементам словарей в цикле `for`. Осталось разобраться, как это работает. - -### Ключи - -По умолчанию, в конструкциях вида - -```python linenums="1" -# после in указано название переменной, хранящей словарь -for key in dict_var: - ... -``` - -переменные цикла (тут – `key`) будут принимать значения из множества ^^ключей^^ словаря. Аналогично можно использовать метод `keys()` (позволяет достать все ключи), который явно говорит, что цикл идет по ключам, например: - -```python linenums="1" -# словарь в качестве ключей хранит имена игроков -for player in quidditch_team: - - # на каждой итерации будет напечатан ключ и значение - print(f"{player = }: {quidditch_team[player] = }") -``` -```bash -player = 'Fred Weasley': quidditch_team[player] = '3rd year' -player = 'George Weasley': quidditch_team[player] = '3rd year' -player = 'Harry Potter': quidditch_team[player] = '2nd year' -``` - -### Значения - -При помощи метода `values()` можно получить все значения, хранящиеся по всем ключам словаря: - -```python linenums="1" -# словарь в качестве значений хранит годы обучения -for year in quidditch_team.values(): - - # на каждой итерации будет год обучения игрока - print(year) -``` -```bash -3rd year -3rd year -2nd year -``` - -!!! info "Между тем" - - Напрямую по значению получить ключ нельзя. - -### Всё и сразу - -Существует метод `items()`, который достает пары `ключ`: `значение` в виде последовательности кортежей. Его же часто удобно использовать в циклах, дабы не тащить длинную запись в виде названия словаря и квадратных скобок с ключом при обращении к значению: - -```python linenums="1" -# сразу две переменные: первая последовательно будет ключами, -# вторая – значениями -for player, year in quidditch_team.items(): - - # items() избавляет от необходимости обращаться quidditch_team[player], - # чтобы получить значение. Оно уже в year - print(f"Player {player} is in {year}") -``` -```bash -Player Fred Weasley is in 3rd year -Player George Weasley is in 3rd year -Player Harry Potter is in 2nd year -``` - -## Сортировка - -Функция `sorted()` доступна и для словарей. По умолчанию ключи словаря поддерживают порядок, в котором были добавлены, но можно отсортировать их в нужном направлении (в зависимости от типа): - -```python linenums="1" -# вспомним про рабочие дни, ключи - целые числа по номеру дня недели -week = {7: "weekend", 6: "weekend", 1: "workday"} - -# в sorted_week окажутся ключи, отсортированные в порядке возрастания -sorted_week = sorted(week) -print(f"Порядок возрастания: {sorted_week}") -``` -```bash -Порядок возрастания: [1, 6, 7] -``` - -!!! warning "Не забудьте" - - Когда в функции передаётся просто название переменной со словарем, работа идет только над множеством ключей. - -!!! question "Можно ли отсортировать словарь по значениям?" - - Да, можно попробовать самостоятельно разобраться с аргументами функции [`sorted()`](https://docs.python.org/3/howto/sorting.html). - -## Что можно хранить - -Теперь добавим немного технических подробностей: возможно, уже заметили самостоятельно, что `dict` может принимать в качестве ключа не всякое значение. На самом деле только [^^хешируемые^^](https://docs-python.ru/tutorial/vstroennye-funktsii-interpretatora-python/funktsija-hash/) объекты (можно вызвать функцию `hash()` и получить значение) могут быть ключами словаря, на значения это ограничение не распространяется. В `dict` и `set` значение хеша от объекта используется для поиска внутри структуры. - -Ключом словаря нельзя сделать объект ^^изменяемого^^ типа, например, `list`, `set` или сам `dict`, так как значение их хеша может измениться со временем. Неизменяемый кортеж может быть ключом только если не содержит внутри изменяемые объекты. - -### Изменяемость и неизменяемость - -В англоязычной литературе изменяемые типы называют ^^mutable^^, а неизменяемые – ^^immutable^^, [почитать документацию](https://docs.python.org/3/reference/datamodel.html#objects-values-and-types). - -В Python всё есть объект. Когда пользователь присваивает значение переменной, она начинает ассоциироваться с ячейкой памяти, где лежит это значение. Переменная знает адрес, откуда можно получить значение. `id()` и `hex()` показывают адрес в памяти компьютера. `id()` - адрес в _десятичном виде_, а `hex()` поможет перевести в _шестнадцатеричный_. - -По адресу лежит так называемое ^^внутреннее состояние^^ переменной: - -- ^^неизменяемые^^ типы не позволяют менять внутреннее состояние, значение переменной может поменяться только вместе с адресом -- ^^изменяемые^^ типы позволяют менять внутреннее состояние переменной при сохранении адреса (возвращаемое `id()` значение не меняется, но _значение_ переменной каким-то образом преобразовывается). Изменение по ссылке называется изменением _in place_. - -#### Неизменяемые типы - -Из стандартных неизменяемыми являются: - -- `int` -- `float` -- `bool` -- `str` -- `tuple` - -Давайте сразу рассмотрим пример: - -```python linenums="1" -counter = 100 - -# полученное вами значение адреса может отличаться -print(f"{counter = }, {hex(id(counter)) = }") -``` -```bash -counter = 100, hex(id(counter)) = '0x10c678d50' -``` - -```mermaid -flowchart LR - - subgraph 100 - 0x10c678d50 - end - - counter --> 100 -``` - -А теперь поменяем значение `counter`: - -```python linenums="1" -counter = 200 -print(f"{counter = }, {hex(id(counter)) = }") -``` -```bash -counter = 200, hex(id(counter)) = '0x10c6799d0' -``` - -Кажется, что раз значение переменной `counter` поменялось, то и содержимое по предыдущему адресу изменилось? Нет, на самом деле `counter` теперь указывает в другое место: - -```mermaid -flowchart LR - - subgraph 100 - 0x10c678d50 - end - - subgraph 200 - 0x10c6799d0 - end - - counter --> 200 -``` - -Из интересного: Python [заранее создает объекты](https://docs.python.org/3/c-api/long.html#c.PyLong_FromLong) для чисел от -5 до 256, поэтому для переменных со значением из этого диапазона берутся заранее готовые ссылки. - -```python linenums="1" -# создадим две переменные с одинаковыми значениями в диапазоне от -5 до 256 -a = 20 -b = 20 - -# a и b указывают на одно и то же место в памяти -# попробуйте у себя поменять значение a и b на число больше 256 или меньше -5 -id(a) == id(b) -``` -```bash -True -``` - -#### Изменяемые типы - -Стандартные изменяемые типы это: - -- `list` -- `set` -- `dict` - -У списков есть метод `append()`, позволяющий добавить в него значение: - -```python linenums="1" -# создадим список и напечатаем его адрес -ratings = [1, 2, 3] -print(f"Было: {hex(id(ratings))}") - -ratings.append(4) -print(f"Стало: {hex(id(ratings))} - ничего не поменялось!") -``` -```bash -Было: 0x10df8d1c0 -Стало: 0x10df8d1c0 - ничего не поменялось! -``` - -```mermaid -flowchart LR - - subgraph list ["[1, 2, 3]"] - 0x10df8d1c0 - end - - ratings --> list -``` - -После добавления ещё одного, адрес `ratings` не изменился. - -```mermaid -flowchart LR - - subgraph list ["[1, 2, 3, 4]"] - 0x10df8d1c0 - end - - ratings --> list -``` - -## Что узнали из лекции - -- новый тип данных – ^^словарь^^! Позволяет хранить соответствие `ключ`: `значение`; -- несколько способов создания `dict`, примеры: - - ```python linenums="1" - # при помощи "литерала" - фигурных скобок {} - flowers = {"roses": "red", "violets": "blue"} - - # при помощи вызова - # dict() и последовательности с парами значений - anime = dict( - [ - ("Ведьмак", "Кошмар волка"), - ("Призрак в доспехах", ["Призрак в доспехах", "Синдром одиночки", "Невинность"]) - ] - ) - - # dict() и "ключ=значение" - literature = dict(poem_flowers=flowers) - - print(f"{flowers = }\n{anime = }\n{literature = }") - ``` - ```bash - flowers = {'roses': 'red', 'violets': 'blue'} - anime = {'Ведьмак': 'Кошмар волка', 'Призрак в доспехах': ['Призрак в доспехах', 'Синдром одиночки', 'Невинность']} - literature = {'poem_flowers': {'roses': 'red', 'violets': 'blue'}} - ``` - -- методы для изменения состояния или получения доступа к элементам: - - ```python linenums="1" - # доступ к элементу, если ключа нет - ошибка - print(f'{flowers["violets"] = }') - - # при помощи get() - print(f'{flowers.get("magnolias") = }') - ``` - ```bash - flowers["violets"] = 'blue' - flowers.get("magnolias") = None - ``` - - ```python linenums="1" - days = ["Пн", "Вт", "Ср", "Чт", "Пт"] - - # создадим пустой словарь - numbered_days = {} - - # будем добавлять в него элементы в цикле - for num in range(len(days)): - numbered_days[num] = days[num] - - # получим отдельно ключи и значения - # пары из tuple можно сразу получить при помощи метода items() - keys = numbered_days.keys() - values = numbered_days.values() - - print(f"Ключи: {keys}\nЗначения: {values}") - ``` - ```bash - Ключи: dict_keys([0, 1, 2, 3, 4]) - Значения: dict_values(['Пн', 'Вт', 'Ср', 'Чт', 'Пт']) - ``` - -- требование к ключу: возможность хеширования, свойство ключа внутри словаря: уникальность; -- разобрали, что есть изменяемые (`dict`, `set`, `list`) и неизменяемые (`int`, `float`, `bool`, `tuple`, `str`) стандартные типы данных. diff --git a/docs/base/final.md b/docs/base/final.md deleted file mode 100644 index cae93a9c..00000000 --- a/docs/base/final.md +++ /dev/null @@ -1,160 +0,0 @@ -# Финальная лекция обо всём и ни о чём - -!!! info "Автор(ы)" - - - [Котенков Игорь](https://github.com/stalkermustang) - - [vvssttkk](https://github.com/vvssttkk) - -## Заметки по прохождению - -Хоть в пройденных лекциях по Python и содержится большое количество материала, проиллюстрированного примерами, с указанием на дополнительные темы для самостоятельного изучения – это все еще малая доля того, с чем вам придется столкнуться, если захочется продолжить развитие в этой теме. Да, грустно, но такова правда жизни. А еще столкнетесь с кучей проблем и ошибок во время время больше погружения. Если ^^попытались разобраться^^ с чем-либо, но не получилось – приходите к нам в сообщество, задавайте вопросы. Не забывайте и о взаимопомощи другим студентам – если материал или тема дались вам легко, то кому-то они могут показаться адски сложными. - -Помните, что абсолютное большинство возникающих ошибок в Python неуникально; иного кто наступил на эти грабли. Не стесняйтесь пользоваться поисковиками для нахождения решений. Но перед этим обязательно прочитайте текст ошибки, попробуйте осознать, о чем Python хочет «сказать» - в этом языке программирования одни из самых понятных и доступных подсказок и указателей на проблемы. К примеру, `IndexError: list index out of range` явно говорит о том, что во время обращения к `i`-тому объекту некоторого списка (который, кстати, будет указан в так называемом traceback) возник выход за границы `list`. Возьмем для примера список `sample_list` чисел длины `5`. Что произойдет, если обратиться к седьмому объекту `sample_list[7]`? - -
- ![](./_static/example_traceback.png) -
- Получим ошибку -
-
- -Обратите внимание на стрелочку слева, указывающую на строку номер 5 (кстати, в Jupyter Notebook для каждой отдельной ячейки можно включить нумерацию строк для удобства навигации с помощью клавиши `l`). Это место возникновения ошибки, та строка, на которой Python не смог выполнить инструкцию. Как можно решить проблему? Для начала ^^методом пристального взгляда^^ поймите, написано ли в коде то, что хотели – очень часто код, к примеру, копируется (хотя нужно избегать этого с помощью написания функций), но переменные в нем не меняются в силу невнимательности. Если все переменные в строке те же, что и должны быть, и ошибка не ясна, то следует заняться [отладкой кода](https://ru.wikipedia.org/wiki/Отладка_программы). - -Самый простой способ отладки в Jupyter – это расстановка `print`-ов до проблемной строки. Да-да, так кустарно и грубо. Есть более продвинутые технологии (например, [отладчики](https://code.visualstudio.com/docs/python/debugging) в IDE, то есть средах разработки), однако они выходят за рамки этого места. Очевидный совет - нужно размещать такой `print`, который помогает проверить какую-либо ^^гипотезу^^ о происхождении ошибки. Предложение таких гипотез – это отдельный навык, который приходит с опытом, так что не переживайте, что поначалу получается плохо «угадывать» и «понимать» ошибки. - -В случае обращения по неверному индексу (`list index out of range`) логично предположить, что индекс оказался больше максимально возможного значения. Давайте выведем длину списка и индекс, по которому хотим обратиться: - -
- ![](./_static/example_debug.png) -
- Строчку с вашим отладочным выводом легко потерять - для удобства можно добавлять какие-то символы или текст -
-
- -И исходя из аргументов выше становится очевидно, в чем именно проблема. Конечно, рассмотренный случай крайне тривиален, однако он показывает базовые приемы поиска причин ошибок. Отметим также такой полезный прием как разбитие проблемной строки кода на подстроки, то есть разнесение кода на отдельные изолированные куски. В данном примере в отдельную переменную был записан индекс. Однако попробуйте угадать, в каком месте происходит ошибка в коде ниже: - -
- ![](./_static/debug_hard.png) -
- Traceback ошибки предательски указывает на функцию, при вызове которой возникла ошибка - `third_f` -
-
- -Это уже более сложный пример, когда traceback состоит из двух блоков. Указатель на ошибку как бы «проваливается» внутрь вызываемой функции и показывает, что не так. В данном случае ошибка `TypeError: unsupported operand type(s) for +: 'int' and 'str'` указывает на несовместимость типов операндов в операции сложения. Слева `int`, справа `str` – ну и как же их суммировать? - -Однако исходная строчка, порождающая ошибку, крайне сложна. Получается что вызываем функцию (`print`) от функции (`first_f`) от функции... Будь логика в коде чуть сложнее – легко можно запутаться, что именно породило ошибку (главное обращайте внимание на заголовки traceback, указывающие на названия методов и функций). С разбиением всё проще: - -
- ![](./_static/debug_solved.png) -
- Указатель в виде стрелочки прямо рапортует о том, что проблема в вычислении `third_f`. Дальше можно было бы добавить `print(tmp1)` для того, чтобы увидеть входные параметры и попытаться понять, в чем же проблема -
-
- -На этом остановимся. Главное помните, что можно распечатать и аргументы функции/метода, и атрибуты класса (в том числе скрытые/промежуточные состояния квантовой среды), и результаты расчетов. - -## Примеры кода, не разобранные в лекциях - -Ранее весь код, который упоминался в лекциях (за вычетом примера из первой) был написан на чистом Python без сторонних библиотек, которые так нахваливали. В жизни, разумеется, они встретятся. Полезно поговорить о двух вещах - об ^^импортах^^ библиотек и их алиасах. - -Для того, чтобы использовать какой-либо объект из сторонней библиотеки, будь то функция, класс или даже словарь (например, с физическими константами), необходимо знать, в какой библиотеке и по какому пути он лежит. Все это в основном описано в их документации, а также в примерах кода. Не переживайте, если они плохо запоминаются - чаще всего их копируют, и со временем в голове откладывается паттерн. И все же для того, чтобы получить доступ к библиотеке, нужно сделать следующее – рассмотрим на примере [`numpy`](https://numpy.org/), библиотеки для алгебраических расчетов. Сначала следует ключевое слово `import`, затем через пробел название пакета. Опционально через `as` можно добавить алиас - название, под которым можно будет обращаться в коде для доступа к функциям. У многих пакетов есть общепринятые алиасы, с которыми все знакомы. Для `numpy` это `np`. Итак, - -```python linenums="1" -import numpy as np - -np_example_array = np.array([1, 2, 3]) -print(f"{np_example_array.shape = }") - -abs_res = np.abs(-2) -print(f"{abs_res = }") -``` -```bash -np_example_array.shape = (3,) -abs_res = 2 -``` - -По сути обращение схоже с объявлением объекта класса или же каким то методом - ведь можно импортировать не целый пакет, а его часть! - -```python linenums="1" -from numpy import zeros - -zeros_matrix = zeros(shape=(1, 3)) -print(f"{zeros_matrix = }") -``` -```bash -zeros_matrix = array([[0., 0., 0.]]) -``` - -Здесь `zeros` - ^^функция^^, формирующая матрицу из нулей заданного размера. - -Или, к примеру, для отрисовки визуализаций часто используют следующую библиотеку (мы уже с ней сталкивались): - -```python linenums="1" -import matplotlib.pyplot as plt - -plt.scatter(np.random.randn(10), np.random.randn(10)); -plt.show(); -``` -![](./_static/output_plt_scatter.png) - -!!! info "В коде выше в последних строках стоит `;`" - - Это необязательный символ, означающий конец команды. В большинстве других языков программирования необходимо всегда в конце строки оставлять этот символ, однако в питоне сигналом о конце инстуркции служит перенос строки. - Почему же здесь они поставлены? Во-первых, дабы показать, что они означают – чтоб не переживали, когда встретите подобное. Во-вторых, `plt.show()` возвращает объект после вызова метода. `Jupyter` же по умолчанию выводит последнее возвращенное значение. Попробуйте убрать точку с запятой и посмотреть в своем ноутбуке, что получится. Таким образом, в данном случае окончание команды `;` «говорит», что возвращаемая переменная никуда не будет записана и будет удалена - поэтому при её наличии подпись объекта не возвращается. - -В коде сначала происходит импорт, затем вызывается отрисовка точек (см. [документацию тут](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.scatter.html?highlight=scatter#matplotlib.pyplot.scatter)), где координаты `X` и `Y` получаются случайно из нормального распределения от `-1` до `1`. Но сам по себе вызов `scatter()` лишь добавляет точки на график, но не отрисовывает его - за это отвечает вызов `plt.show()`. Стоит заметить, что `plt` хранит в себе «полотно», на котором рисует, и результат добавления точек через `scatter` не нужно записывать в какую-либо переменную – все это хранится во внутреннем состоянии самой библиотеки. Помните урок про классы и их объекты, задающие состояние системы? Здесь ровно то же самое! Теперь, надеемся, картинка начинает складываться! - -## Блок дополнительных ссылок - -Ниже представлен набор ссылок, которые предлагается просмотреть для расширения кругозора и лучшего понимания материала. Это бонусный материал, необязательный к изучению. Но если захватила идея получше познакомится со своим инструментом, то почему нет? - -1. [Видеоуроки Python для анализа данных](https://dfedorov.spb.ru/python3/) от СПбГЭУ -2. [Учите питон](https://pythontutor.ru/) от pythontutor -3. [Курс по Python](https://github.com/trekhleb/learn-python) в виде примеров кода с очевидными и не очень механиками языка. Хорошо подойдет как дополнение к примерам в курсе -4. [realpython](https://realpython.com/) – сайт с большим количеством разнообразных уроков по Python на английском -5. [Огромный список](https://github.com/kirang89/pycrumbs) ссылок на разные статьи по всем темам - от основ Python и до продвинутых приемов в разработке -6. [И другой](https://github.com/vinta/awesome-python) – с набором ссылок на код разных программ. Игры, видеопроигрыватели и прочее - все тут -7. [Простой отладчик](https://github.com/alexmojaki/snoop) на случай, если начали путаться в своем коде, а продвинутые инструменты кажутся очень сложными и громоздкими - -!!! info "Между тем" - - Как ставить новые библиотеки в Python – вот хотя бы тот же отладчик из пункта 5? Вспоминайте совет – яндекс/google/.. лучший друг. «how to install python library» (да, прямо дословно «library» = «библиотека»). - -## Вместо заключения - -Что ж, вот и подошел к концу «основы Python». Его можно назвать самым сложным – нет, не с точки зрения материала и научности, но по количеству усилий, которые необходимо приложить, чтобы не сбиться с пути и продолжить обучение несмотря на трудности. Если читаете это, то безумно рады за твои достижения и подвиги, и желаем дальнейших успехов! - -``` -........................................................................... -.................................,,,....................................... -.................................,:::,...........................,::,...... -.................................:::;;:,......................,::;;;,...... -.................................:;;;;++;:,,................,:;+;;+*+,..... -.................................:+;;;++*+**++;;+++++;;::::;++++++*?+,..... -.................................,:;;+++**+*?%?*??*??%%%?++?**+;*%?*;...... -..................,,,::;;;;;;+++;:+%%*;;+*??%%?*****?SS%?***++++++**,...... -................:;+****?*******??;+%%*++****%*++:;+%+*%*+??*?*+?S*;;,...... -.............,:+******??**?*****?*+?++++*?;+S;:,,,:*;;S*;???**?%SS+:,...... -.............;***?****+**+++*****;;;+*?*+++;+::,,,,:;:+++++*??*+*?+:,...... -...........,;**+**+*++*?***?%%??+;+?%%%+%S#S%*:,,,,:;*%#S%%*?%S%*++:....... -........,:;++++**+++++*%S%???%%%+*%?+**++????S+,,,,,+S%%%??****?S?+:....... -.......,;+;+*+;+*+;+***?%*?%%?%%++++++*?%%?*;;,,,:,,:::;*?%?*+++?S*:....... -......:;**+**++*+++*?**???%%%%?*+**?%%%%%?+:,,,;;;;:,,,,:+*???*+**+,....... -.....:;+****?*+*++??*+?%%%??????????????%%?;:,,:;+;:,,,,,:;*?%%%?*;,....... -....,:++*?%%?+**++??**?S%????%%%%%????????%%?+++*?+;:::;+*?%S%%%?+:........ -....,:;+?%S%?+**++*?*?%%%??%%%%%%%%%%%%%?%??%%%%*****??%%%%%%?????*+:...... -....,;;+?%?%?++**+*??%%%%???%%%%%%%%%%%%%%%%???%%%%%%%???????????????:..... -....,+++*??%?**?*+?%%%%?%???%%%%%%%%%%%%%%%%%???????????????%%%??????*,.... -....,:++**?%??*?*+???%%?%?*?%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%?*,.... -......:;++*?**??*+***%%????%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%?%*..... -.......,;;+**?*??**?*????%%??%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%?:..... -.......,;+**?%?%%**??*?+;;;+*?%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%?%?;...... -......,,,::;++****???*****???**?%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*,....... -........,,,,,,,,,:::;;+*?????*???%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%?+,........ -..............,,,,,,,,:;+*?S%??%%S%%%%%%%%%%%%%%%%%%%%%%%%%%%%%?+,......... -.....................,,,,:;++*%%SSSS%%%%%%%%%%%%%%%%%%%%%%%%??+;:,,........ -........................,,,,,,::;++*???%S%S%%%%%%%%%%%%%%??+;;:::,,,....... -...........................,,,,,,,,:::;+*?%SS%SSSS%%%%?*++;;:::,,,,........ -................................,,,,,,,,,,:::;;;;;:::,,,,,,,,,,,........... -........................................................................... -``` diff --git a/docs/base/functions.md b/docs/base/functions.md deleted file mode 100644 index 97779ecf..00000000 --- a/docs/base/functions.md +++ /dev/null @@ -1,866 +0,0 @@ -# Функции - -!!! info "Автор(ы)" - - - [Овсянникова Александра](https://github.com/alexmorphine) - - [Чернов Илья](https://github.com/ch3rn0v/) - - [Kosarevsky Dmitry](https://github.com/dKosarevsky) - -## Что такое функция - -В общем случае функцией можно назвать набор связанных инструкций, которые выполняют определенную задачу. Функции во всех языках программирования помогают: - -- структурировать код и улучшить читаемость; -- переиспользовать код; -- уменьшать количество мест, в которых можно ошибиться, при копировании и вставке кода. - -Таким образом, функция — это инструмент композиции кода. Однажды определив набор инструкций, можно многократно использовать его, в том числе и как составную часть других функций. - -В Python функции можно разделить на три типа: - -- [x] встроенные ([список built-in функций](https://docs.python.org/3/library/functions.html)); -- [x] именованные (определенные пользователем при помощи `def`); -- [x] анонимные (`lambda`-функции). - -Все функции являются объектами типа `function`. - -Мы уже использовали встроенные функции, например: - -- `print()` – вывод данных на экран; -- `str()` – создание объектов строкового типа; -- `type()` – определение типа объекта. - -Ими можно пользоваться как черным ящиком, который принимает что-то на вход и творит свою магию. О том, что готовые функции ожидают получить, написано в документации вместе с описанием принципа работы. - -!!! info "Совет" - - После разбора лекции советуем открыть [документацию `print()`](https://docs.python.org/3/library/functions.html#print), например, и разобраться с подробностями работы. - -Очевидно, стандартные функции дают лишь базовый инструментарий. Реализовать более сложную логику можно самостоятельно. - -### Пример - -Представим, что необходимо находить количество корней квадратного уравнения — это легко можно реализовать на Python! - -```python linenums="1" -def count_roots(a, b, c): - - d = b ** 2 - 4 * a * c - - if d == 0: - return "один" - - elif d < 0: - return "нет корней" - - else: - return "два" -``` - -## Именованные функции - -### Определение - -Определение функции позволяет ^^создать объект^^ функции. После определения к функции можно будет обратиться по заданному имени и получить результат её работы. - -В Python существует особый синтаксис определения именованных функций: - -1. в начале — ключевое слово `def`; -2. название функции - - существуют правила и рекомендации по именованию функций: - - - **правила**: - - - название не может начинаться с числа; - - можно использовать нижнее подчеркивание `_`, цифры и буквы; - - - **рекомендации**: - - - `snake_case`: в названии только буквы нижнего регистра, слова разделяются `_`; - - название функции должно быть уникальным; - -3. круглые скобки и, опционально, параметры внутри (о них ниже); -4. двоеточие, переход на новую строку; -5. тело функции, выделенное отступом — набор инструкций, который «выполняет работу». - -Код в Python организован в блоки и именно отступы дают понять, где у блоков начало и конец. Блоки могут быть вложенными. Все тело функции должно располагаться минимум в одном отступе от начала строк. - -```python linenums="1" -def название_функции(позиционные, *доп_позиционные, именованные, **доп_именованные_параметры): - инструкция 0 - инструкция 1 - .... - инструкция N -``` - -Напишем простейшую функцию, которая будет печатать две фразы: - -```python linenums="1" -# Первым делом — def -# далее — имя функции "print_theme" -# после — круглые скобки, сейчас пустые. Потом : и переход на новую строку -def print_theme(): - - # Тело функции из двух вызовов print(), оба с одинаковым отступом - print("Лекция про функции!") - print("Тело кончилось") -``` - -### Вызов - -После определения функции появляется возможность к ней обращаться (вызывать). Делается это просто: указывается имя функции, круглые скобки и, опционально, аргументы в них. - -```python linenums="1" -# Выше была определена print_theme, ее и вызовем. -print_theme() -``` -```bash -Лекция про функции! -Тело кончилось -``` - -### Возвращаемое значение - -Все функции в Python имеют одно и только одно возвращаемое значение. Если в теле функции отсутствует ключевое слово `return`, возвращаемое значение всегда будет `None`. - -```python linenums="1" -# Определим функцию, которая принимает на вход x -def add_two(x): - - # Переменная result — сумма x и 2 - result = x + 2 - - # «Наружу» возвращается полученное значение - return result -``` - -!!! question "Возможно ли вернуть несколько значений?" - - Это возможно, если упаковать несколько значений в одно значение-контейнер. В Python контейнеры могут быть следующих типов: - - - список (например, `[1, 2, 3]`) - - кортеж (`(1, 2, 3)`) - - словарь (`{"key_one": 1, "key_two": 2, "key_three": 3}`) - - объект класса (см. раздел [объекты и классы](./object_class_method.md)) - - Таким образом, возвращается одно значение, а содержать в себе оно может несколько других. - -Возвращение значения означает, что его можно использовать вне функции, например, присвоить полученное значение переменной. Давайте посмотрим, что возвращает `print_theme()` и `add_two()`: - -```python linenums="1" -# Присвоим результат выполнения функции переменной и посмотрим, что в ней -from_print_theme = print_theme() -print(from_print_theme is None) -``` -```bash -Лекция про функции! -Тело кончилось -True -``` - -Как видите, несмотря на отсутствие `return` в коде функции, она действительно возвращает `None`. - -Теперь посмотрим на `add_two()`, где возвращаемое значение задано нами: - -```python linenums="1" -# add_two при вызове ожидает получить число: сложим 2 и 2 -from_add_two = add_two(2) -print(from_add_two) -``` -```bash -4 -``` - -### Множественные `return`-ы - -В теле функции можно указать `return` несколько раз. Выражения в Python вычисляются по очереди, и возвращаемое значение функции определяется первым вычисленным выражением, содержащем `return` (а если `return` отсутствует в теле функции, возвращается `None`). - -Покажем это на примере функции, умножающей нечетные числа на 2 и делящей четные числа пополам. - -```python linenums="1" -def change_num(num): - if num % 2 == 0: - return num / 2 - - return num * 2 - -print(change_num(4)) -print(change_num(5)) -``` -```bash -2 -10 -``` - -Выражение в строке 3 будет выполнено в случае, если выполняется условие из строки 2. При этом происходит выход из функции, и следующие выражения в ее теле уже не исполнятся при этом вызове. Поэтому нет необходимости писать `else`: - -```python linenums="1" -def change_num_2(num): - if num % 2 == 0: - return num / 2 - else: # Это избыточно - return num * 2 # Появляется лишний уровень вложенности -``` - -Функция `change_num_2` эквивалентна `change_num`, но содержит лишний уровень вложенности. Знание о том, что после первого `return` происходит выход из функции, позволяет избежать лишней вложенности. - -## Пространства имен и области видимости - -Чуть выше была определена `add_two()`, внутри которой инициализировалась переменная `result`. Значение этой переменной нельзя получить, обратившись к ней вне функции. - -```python linenums="1" -# Ошибочка! -# Конструкция try-except перехватывает исключение NameError -# и не дает программе перестать работать из-за возникновения этой ошибки -try: - print(result) -except NameError as ne: - print(ne) -``` -```bash -name 'result' is not defined -``` - -Потому что функции обладают своим пространством имен: переменные, которые определены внутри, не видны извне. Однако, функция может получать доступ к переменным, которые определены снаружи. Давайте опишем чуть более формально. - -В Python объектам можно давать имя и обращаться к ним по нему. Эти имена организованы в пространства имен или namespace. Инициализация переменной добавляет в namespace название объекта. Namespace — набор имен определенных на текущий момент объектов. Представьте себе `dict`, где ключом является строка, а значением — ссылка на объект. Область видимости определяет, переменные из каких пространств имен сейчас доступны. Разберем, как и где Python ищет объекты, к которым обращаются (этот процесс называется name resolution). - -Namespace и области видимости можно разделить на несколько типов: - -- локальные (Local) — локальные переменные функции, данная область существует до тех пор, пока функция не завершит работу после вызова; -- локальные пространства могут быть вложены друг в друга, в таком случае область уровня $N$ (Enclosing) содержит «более глубокую» $N + 1$. Поиск имени, вызванного на уровне $N$, начинается с локального namespace этого уровня и продвигается «наружу», то есть на уровни выше; -- глобальные (Global) — все объекты, определенные на уровне скрипта; -- встроенные (Built-in) — namespace содержит все встроенные объекты (функции, исключения и т. д.), поиск в нем осуществляется последним. - -![](./_static/legb.png){ width="400" } - -Если имя не было найдено даже на уровне Built-in, будет выброшено исключение `NameError`. - -```python linenums="1" -z = "name" - -def foo(): - - # В foo не определена своя z, но она найдется в глобальной области - print(z) - - a = 10 - b = -5 - - def bar(): - - # bar успешно напечатает a, при этом значение будет найдено в namespace foo - # Как думаете, где находится print? - # В built-in, то есть самой "внешней" области - print(a) - - # Создадим переменную b внутри bar - b = 20 - - # Будет напечатано 20, так как поиск увенчается успехом в локальном namespace - print(b) - - c = 30 - - bar() - - # Если раскомментировать следующую строку, будет ошибка - # print(c) - # Потому что foo не знает ничего про внутренности bar - - # Что будет напечатано, если раскомментировать следующую строку? - # print(b) - -foo() -``` -```bash -name -10 -20 -``` - -!!! tip "Совет" - - Хотим заметить, что нужно быть аккуратными при использовании вложенных функций и следить за тем, где и какие переменные определены. В рамках курса не советуем так делать, чтобы не запутаться. Единственное исключение — декораторы, описанные ниже. - -### Замыкания - -[Замыкание](https://ru.wikipedia.org/wiki/Замыкание_(программирование)) ([Closure](https://en.wikipedia.org/wiki/Closure_(computer_programming))) — это функция, объявленная в теле внешней функции, и использующая значения из области видимости внешней функции. - -Замыкания удобно использовать для динамического создания функций. - -```python linenums="1" -def make_adder(arg1): - def _adder(arg2): - return arg1 + arg2 - - return _adder - -add_three = make_adder(3) -print(add_three(2)) -``` -```bash -5 -``` - -### Каррирование - -[Каррирование](https://ru.wikipedia.org/wiki/Каррирование) ([Currying](https://en.wikipedia.org/wiki/Currying)) — это превращение функции от нескольких аргументов в последовательность функций от одного аргумента. - -В Python реализован менее строгий аналог каррирования. С помощью функции [`partial`](https://docs.python.org/3/library/functools.html#functools.partial) можно получить функцию от меньшего числа аргументов, но не обязательно одного. Рассмотрим пример. - -```python linenums="1" -from functools import partial - -def adder(arg1, arg2): - return arg1 + arg2 - -add_three = partial(adder, 3) -print(add_three(2)) -``` -```bash -5 -``` - -Первым аргументом в `partial` передается функция. А далее через запятую можно передать от $0$ до $N$ аргументов, которые требуется зафиксировать, где $N$ — это число аргументов исходной функции. Возвращаемое значение `partial` — это функция от $N - x$ аргументов, где $x$ — это число аргументов, переданных в `partial` (и таким образом зафиксированных). -Передавать в `partial` только функцию и $0$ аргументов можно, но не имеет смысла (получится функция от $N$ аргументов, которая и была изначально). Если же зафиксировать все $N$ аргументов, то на выходе получится функция от нуля аргументов (если это была чистая функция, результат будет эквивалентен константе). - -Важно заметить, что `partial` сохраняет порядок аргументов. Поэтому при определении функции лучше в начале ставить аргументы, значения которых реже будут меняться. - -!!! tip "Совет" - - Легко увидеть аналогию с примером замыкания, и действительно, в некоторых случаях использование `partial` дает тот же результат, но проще и потому предпочтительнее. - -### Чистые функции - -[Чистой функцией](https://ru.wikipedia.org/wiki/Чистота_функции) ([pure function](https://en.wikipedia.org/wiki/Pure_function)) называют функцию, одновременно обладающую следующими свойствами: - -- является детерминированной; -- не имеет побочных эффектов. - -Детерминированность означает, что возвращаемое значение всегда одинаково для одних и тех же значений аргументов. - -Отсутствие побочных эффектов означает, что вызов функции не изменит ничего за пределами своей локальной области видимости. Сохранение возвращаемого функцией значения в переменную происходит за рамками функции, поэтому не нарушает ее чистоты. - -```python linenums="1" -external_dict = {"arg": 2} - -def fn1(arg): - return arg * external_dict["arg"] - -def fn2(arg): - external_dict["arg"] = 3 - return arg * 2 - -def fn3(arg1, arg2): - return arg1 * arg2 - -print(fn1(2)) # (1) -print(fn2(2)) # (2) -print(fn1(2)) # (3) -print(fn3(2, 2)) # (4) -``` - -1. 4 -2. 4 -3. 6 -4. 4 - -??? question "Какие из вызванных выше функций являются чистыми?" - - Функция `fn1` не имеет побочных эффектов, но она не детерминирована потому что зависит от `external_dict`. Поэтому она не чистая. - - Функция `fn2` детерминирована, но она имеет побочный эффект — изменяет содержимое `external_dict`. Поэтому она не чистая. - - Функция `fn3` детерминирована и не имеет побочных эффектов, поэтому она чистая. - - Функция `print` тоже была вызвана. Является ли она чистой? Вывод на печать — это побочный эффект, поэтому нет. - - Вызов `fn2` изменил содержимое `external_dict`, поэтому второй вызов `fn1` дал результат, отличный от первого вызова. - - -??? question "Подумайте, какие значения будут напечатаны?" - - Ответ можно посмотреть нажав на `+` справа возле `print` - - -Чистые функции гораздо проще понять при чтении кода и гораздо проще отлаживать, поэтому по возможности стоит все функции делать чистыми. - -## Параметры - -Наша функция `add_two()` или, например, `type()` ожидают, что на вход будут переданы какие-то аргументы для успешной работы, а вот `print()` можно вызвать и с ними, и с пустыми скобками. В начале лекции был представлен скелет функции, сейчас разберем, что же находится в скобках. - -Для начала немного формализма: - -- при определении функции в скобках пишутся параметры, которые функция может принять; -- при вызове функции в скобках указываются аргументы, которые задают значения параметров внутри функции. - -То есть происходит отображение: аргументы, с которыми вызывается функция $\Rightarrow$ значения параметров. - -Переменные с названиями параметров могут быть использованы внутри тела функции, как будто их значения известны. - -### Позиционные параметры - -Позиционные параметры выглядят как перечисленные внутри скобок названия переменных, используемых внутри функции: - -```python linenums="1" -# В данном случае заданы два позиционных параметра -def foo(arg1, arg2): - print(arg1, arg2) -``` - -Данный тип параметров характеризуется следующим: - -- идут первыми после открытых скобок, все именованные строго после них; -- важен порядок: отображение аргументов в параметры будет последовательным; -- при вызове функции все аргументы, которые ожидает функция, должны быть переданы (иначе откуда Python возьмет значения? вот именно!) - -Разберем пример, который суммирует два числа: - -```python linenums="1" -# В данном случае заданы два позиционных параметра -def two_var_sum(var1, var2): - - # Функция возвращает вычисленное значение суммы - return abs(var1) + var2 - -# Порядок важен! -print(two_var_sum(-1, 2), two_var_sum(2, -1)) - -# Можно явно задавать переменные при вызове, в таком случае порядок не играет роли -# Указывается название параметра и значение после = -print(two_var_sum(var2=2, var1=-1)) -``` -```bash -3 1 -3 -``` - -А что, если количество входных переменных очень большое или вы заранее не знаете, сколько аргументов будет передано при вызове? Например, вам нужно сложить не 2 числа, а 102? В Python есть специальный синтаксис со звездочками. После позиционных аргументов можно указать `list`, элементами которого станут неограниченное количество переданных позиционных аргументов. - -Синтаксис: `имя_функции([поз_0, ..., поз_N,] [*поз_список]): ...`; `[]` в данном случае обозначают необязательность. - -```python linenums="1" -# В этом примере сразу используется синтаксис со *: список, куда попадут все переданные позиционные аргументы, тут называется args, а других позиционных параметров нет совсем -def many_arg_sum(*args): - - # Функция возвращает вычисленное значение суммы - return sum(args) - -many_arg_sum(1, 2, 3, 4, 5, 6) -``` -```bash -21 -``` - -!!! tip "Совет" - - Лучше передавать все в списках или векторах (о которых будет позже) - -### Именованные параметры - -Данные параметры имеют значения по умолчанию. - -Синтаксис: `имя_функции([поз_0, ..., поз_N,] [*поз_список], [им_0=значение_0, ..., им_K=значение_K], [**им_словарь]): ...` - -Характеризуются следующим: - -- в определении идут строго после позиционных параметров; -- в определении дано значение по умолчанию через `=` после имени; -- при вызове необязательно указывать значения, тогда будет использовано значение по умолчанию. - -```python linenums="1" -# Тут есть один позиционный параметр name и один именованный phrase -def hello(name, phrase="Привет"): - - print(f"{phrase}, {name}") - -# Передавать значения аргументов можно, сохраняя исходный порядок -hello("Саша", "Приветствую") - -# Или указывая названия параметров (в таком случае порядок можно менять) -hello(phrase="Здарова", name="Игорь") - -# Если не указать значение именованного параметра, используется что по умолчанию -hello("Вася") -``` -```bash -Приветствую, Саша -Здорова, Игорь -Привет, Вася -``` - -Аналогично позиционным аргументам, если необходимо передать множество именованных параметров, используется синтаксис со звездочками, но в данном случае их две, а не одна. Если такой синтаксис использован, все переданные именованные аргументы, кроме определенных явно, попадут в `dict`, указанный после `**`: - -```python linenums="1" -def congrats(today, everyone=False, **names_dates_mapper): - """ - Функция может поздравляет людей - Args: - today (str): сегодняшняя дата - everyone (bool): флаг, нужно ли поздравить всех - names_dates_mapper (dict): отображение имя: дата - """ - - if everyone: - print("Happy Birthday!") - - else: - for name, date in names_dates_mapper.items(): - if date[-5:] == today[-5:]: - print(f"Happy Birthday, {name}") - - -congrats("2021-09-17", Paul="2001-03-08", Lena="1997-01-31", Mark="1997-09-17") -``` -```bash -Happy Birthday, Mark -``` - -!!! question "Что это за комментарий в тройных кавычках внутри функции?" - - Это один из общепринятых способов написания [docstring](https://www.python.org/dev/peps/pep-0257/) — документации по функции. - -### Списки как значения по умолчанию - -Рассмотрим следующую функцию: - -```python linenums="1" -def fn(ls=[1]): - ls.append(2) - return ls - -print(fn()) -print(fn()) -``` -```bash -[1, 2] -[1, 2, 2] -``` - -Второй вызов функции привел к результату, отличающемуся от первого вызова. Почему так произошло? Значение `ls` по умолчанию мы объявили равным `[1]`. Оба вызова используют значение по умолчанию. Но при втором вызове в данном случае произошло обращение к тому же списку, который был создан в качестве значения по умолчанию при первом вызове. Как это можно проверить? - -В Python определена встроенная функция [id](https://docs.python.org/3/library/functions.html#id). Она возвращает целочисленный идентификатор объекта (уникальный и постоянный, пока объект существует). Используем ее, чтобы посмотреть идентификаторы списков. - -```python linenums="1" -def fn_with_id(ls=[1]): - print(id(ls)) - ls.append(2) - return ls - -print(fn_with_id()) -print(fn_with_id()) -print(fn_with_id([3])) -print(fn_with_id()) -``` -```bash -123928376604123 -[1, 2] -123928376604123 -[1, 2, 2] -113928976643254 -[3, 2] -123928376604123 -[1, 2, 2, 2] -``` - -Значения идентификаторов могут быть другие. Важно, что в первом, втором и четвертом вызове эти значения одинаковы и отличаются от третьего вызова, у которого значения списка по умолчанию не используется. Такое поведение сохраняется и для пустого списка как значения по умолчанию, и для непустого, как в примере выше. - -Одним из решений может быть следующее: - -```python linenums="1" -def fixed_fn(ls=None): - if ls is None: - return [2] - - ls.append(2) - return ls - -print(fixed_fn()) -print(fixed_fn()) -print(fixed_fn([1])) -print(fixed_fn()) -``` -```bash -[2] -[2] -[1, 2] -[2] -``` - -Обратите внимание, что с `set`-ом ситуация другая. - -```python linenums="1" -def fn_with_set(_set=set()): - _set.add(2) - print(id(_set)) - return _set - -print(fn_with_set()) -print(fn_with_set()) -print(fn_with_set({3})) -print(fn_with_set()) -``` -```bash -140214028693696 -{2} -140214028693696 -{2} -129928985405920 -{2, 3} -140214028693696 -{2} -``` - -## Анонимные функции - -Функции, определенные при помощи `def`, имеют название, по которому их можно вызвать, но также существуют и анонимные или неименованные функции. Такие функции могут быть определены при помощи оператора `lambda`. Он позволяет задать входные и выходные данные. Самостоятельно можете почитать [документацию](https://docs.python.org/3/reference/expressions.html#grammar-token-lambda-expr). - -```python -# синтаксис анонимных функций простой -lambda [арг_0, ..., арг_N]: выражение -``` - -В определении `выражение` — это возвращаемое значение анонимной функции, например: - -```python linenums="1" -lambda x: abs(x) - -lambda num, div=2: "нет" if num % div else "да" -``` -```bash -(num, div=2)> -``` - -В примере выше `lambda`-функции были только созданы в моменте, но не вызваны. Можно сказать, что мы их определили (как с `def`), но не воспользовались и сразу потеряли к ним доступ. - -Для удобства можно присвоить объект функции переменной, и по этому имени к ней обращаться: - -```python linenums="1" -# Сохранили функцию в переменную check_div -check_div = lambda num, div=2: "нет" if num % div else "да" - -# Вызов такой же, как в случае с именованной функцией -print(check_div(3), check_div(5, 5)) - -# Возможен вызов и без сохранения в переменную -print((lambda x: abs(x))(-120)) -``` -```bash -нет да -120 -``` - -В отличии от именованной, анонимная функция может иметь только одно выражение. - -Данные функции стоит применять, когда нужна одноразовая функция или требуется отложить вычисления. Пример с одноразовой функцией: - -```python linenums="1" -list(map(lambda x: x**2, [1, 2, 3])) -``` -```bash -[1, 4, 9] -``` - -Здесь используется встроенная функция `map`. Она получает на вход функцию и список элементов, вызывает функцию для каждого элемента, результат такого вызова сохраняет в список и возвращает список результатов. В примере выше на вход подан список из трех элементов и анонимная функция, которая возводит аргумент в квадрат. - -А вот пример с отложенными вычислениями: - -```python linenums="1" -perform_computation = lambda: 2 ** 10_000_000 / 2 ** 10_000_000 -perform_computation() -``` -```bash -1.0 -``` - -В данном случае на первой строке вычисления уже определены, но еще не сделаны. И только на второй строке, где происходит вызов, вычисляется выражение из тела `lambda`-функции. Обратите внимание, что `lambda`-функция может вовсе не иметь аргументов, как и именованная. - -## Декораторы - -Функции в Python являются [объектами первого класса](https://ru.wikipedia.org/wiki/Объект_первого_класса). Кроме прочего, это значит, что их можно передавать в другие функции в качестве аргументов, и отдавать в качестве возвращаемых значений. Благодаря этому возможно создавать декораторы. Декоратор — это функция, расширяющая возможности другой функции. - -### Пример - -```python linenums="1" -import time - - -# На вход декоратор принимает параметр func — оборачиваемую функцию -def time_decorator(func): - - # Внутри определена функция, которую декоратор вернет в качестве результата своей работы - # `wrapped()` будет засекать, за сколько выполняется функция `func()` - def wrapped(*args, **kwargs): - start = time.time() - - # Все аргументы, которые примет `wrapped()`, передаются в func - result = func(*args, **kwargs) - - end = time.time() - print(f"Прошло {end - start} секунд") - - # Результат работы func, каким бы он ни был, возвращается - return result - - # Обратите внимание, что возвращаемое значение — именно объект function: после имени нет круглых скобок - # Если бы они были, возвращался бы результат выполнения `wrapped()`, так как это вызов функции - - return wrapped -``` - -Выше была определена функция `many_arg_sum()`, давайте засекать, сколько она работает: - -```python linenums="1" -# Cохраним обернутую функцию (помним, декоратор возвращает функцию) в переменную -# Обратите внимание, что на вход декоратору передается объект самой функции, а не результат ее работы. -many_arg_sum = time_decorator(many_arg_sum) - -# Поведение функции поменялось, а код вызова — нет -summed = many_arg_sum(10, 0, -120, 333) -``` -```bash -Прошло 1.9073486328125e-06 секунд -``` - -Отлично, но можно добавить так называемый ^^синтаксический сахар^^: вместо присваивания значения над определением функции можно указать специальный символ `@`, после которого указывается название декоратора: - -```python linenums="1" -@time_decorator -def primitive_exponentiation(x, power=5): - result = 1 - for p in range(power): - result *= x - return result - -powered = primitive_exponentiation(10) -``` -```bash -Прошло 4.0531158447265625e-06 секунд -``` - -Использование синтаксического сахара с `@` и указанием имени декоратора над функцией аналогично вызову - -```python linenums="1" -primitive_exponentiation = time_decorator(primitive_exponentiation) -``` - -## Генераторы - -[Генераторы в Python](https://docs.python.org/3/howto/functional.html#generators) — это особый класс функций с интересными возможностями. Они позволяют приостанавливать или продолжать работу. Обычные функции вычисляют значение и возвращают его, но генераторы возвращают итератор, который возвращает поток значений и по такому потоку можно проходить пошагово, получая доступ к одному значению с каждой из итераций. - -Вот простейший пример функции-генератора: - -```python linenums="1" -def generate_numbers(n): - for number in range(n): - yield number - -generate_numbers(4) -``` -```bash - -``` - -Любая функция, содержащая ключевое слово `yield`, является функцией-генератором, это обнаруживается компилятором байт-кода Python, который в результате специально компилирует функцию. Когда вызывается функция-генератор, она не возвращает ни одного значения, вместо этого возвращается объект генератора, который поддерживает протокол итератора. - -### Инструкция `yield` - -Инструкция `yield` является частью генератора и заменяет ключевое слово `return`. Когда программа доходит до `yield`, то функция переходит в состояние ожидания и продолжает работу с того же места при повторном вызове. - -Ниже представлены две функции (генерируют последовательность в обратном порядке), одна с оператором `return`, а другая функция-генератор с оператором `yield`. Принимают на вход некое значение `n`, в примере выше - `5`, и возвращают последовательность чисел от `4` до `0`. - -```python linenums="1" title="Функция с оператором return" -def get_subsequence(n): - result = [] - while n != 0: - result.append(n - 1) - n -= 1 - return result - -print(get_subsequence(5)) -print(get_subsequence(5)) -``` -```bash -[4, 3, 2, 1, 0] -[4, 3, 2, 1, 0] -``` - -Функция `get_subsequence` возвращает последовательность в виде списка. Такая функция хранит промежуточное состояние своей работы в виде списка. В примере выше такое состояние хранится в списке `result`, который и будет возвращён после окончания работы цикла `while` с помощью оператора `return`. Список будет возвращён в то место, откуда произошёл вызов функции, при этом важно понимать, что оператор `return` возвращает не только результат работы функции, но и управление ходом выполнения программы в то место, в котором был произведён вызов функции `get_subsequence`. При повторном вызове функции `get_subsequence` генерация чисел происходит заново. - -```python linenums="1" title="Функция-генератор с оператором yield" -def generate_subsequence(n): - while n != 0: - yield n - 1 - n -= 1 - -gen = generate_subsequence(5) - -print(next(gen)) -print(next(gen)) -print(next(gen)) -print(next(gen)) -print(next(gen)) -print(next(gen)) -``` -```bash -4 -3 -2 -1 -0 ---------------------------------------------------------------------------- -StopIteration Traceback (most recent call last) - in - 11 print(next(gen)) - 12 print(next(gen)) ----> 13 print(next(gen)) - -StopIteration: -``` - -Генератор `generate_subsequence` на первый взгляд делает тоже самое, генерирует последовательность чисел в обратном порядке, только ^^возвращает^^ он такую ^^последовательность частями^^ и происходит это благодаря оператору `yield`, который не возвращает контроль над ходом выполнения программы в то место, в котором был произведён вызов функции-генератора, а передаёт контроль на время. Для того, чтобы ^^получить^^ очередной ^^элемент^^ сгенерированный функцией-генератором необходимо использовать встроенную функцию `next`, таким образом исполнение функции на время приостанавливается, до тех пор, пока снова не будет использована функция `next`. Локальная переменная внутри генератора неявным образом сохраняет своё состояние. - -!!! danger "Обратите внимание" - - Eсли генератор вернёт все значения из сгенерированной последовательности и если будет выполнено ещё одно обращение к объекту генератора `gen` с помощью функции `next` - будет возвращено исключение `StopIteration`, как видно на 13-й строке примера выше. Генератор не смог вернуть ещё одно значение поскольку больше таких значений не осталось в сгенерированной последовательности. - -Для того, чтобы получить все значения из функции-генератора можно воспользоваться циклом (для примера с помощью спискового включения (list comprehension)), например так: - -```python linenums="1" -[element for element in generate_subsequence(5)] -``` -```bash -[4, 3, 2, 1, 0] -``` - -Главное преимущество генераторов в том, что ^^не тратятся вычислительные ресурсы на хранение ни промежуточного ни итогового результата^^. По этой причине генераторы удобно использовать при обработке больших последовательностей данных. - -## Что узнали из лекции - -- что такое функции и зачем их применять -- как определить функцию (инструкция `def`) - - ```python - def название_функции(параметры): - тело функции - - ``` - -- отличия позиционных параметров от именованных: - - порядок указания — сначала позиционные, потом именованные - - значения по умолчанию у именованных позволяют не указывать их при вызове -- синтаксис со звездочками для получения заранее неизвестного числа позиционных (`*some_list`) и именованных (`**some_dict`) аргументов - - в `*some_list` стоит одна `*`: эта конструкция для получения неограниченного количества позиционных/неименованных аргументов - - в `**some_dict` две `*`: все именованные аргументы, явно не указанные среди параметров, попадут туда -- что может возвращать функция при помощи `return` - - `return` обозначает выход из функции и передачу «наружу» результата работы - - в `return` можно перечислять несколько возвращаемых значений через запятую - - в теле функции можно указать несколько `return`, всегда сработает не больше одного -- чистые функции детерминированы и лишены побочных эффектов -- чистые функции проще понять и отлаживать, поэтому они предпочтительнее -- замыкания и каррирование позволяют создавать функции динамически, для каррирования можно использовать `partial` -- что такое декораторы и как они работают, щепотку синтаксического сахара с `@` - - использование декоратора эквивалентно сохранению результата вызова функции-декоратора с аргументом в виде оборачиваемой функции `stupid_power = time_decorator(stupid_power)` -- что такое генераторы и как они работают с использованием оператора `yield` diff --git a/docs/base/index.md b/docs/base/index.md deleted file mode 100644 index dfb5f496..00000000 --- a/docs/base/index.md +++ /dev/null @@ -1,8 +0,0 @@ -# введение - -этот раздел затрагивает базовые вещи о python 3.10+ как таковом - -- [x] описание процесса установки среды разработки -- [x] описание синтаксиса языка программирования Python -- [x] разбор типовых синтаксических конструкций при программировании на Python -- [x] примеры анализа возникающих ошибок, помогающие в дальнейшем прохождении курса diff --git a/docs/base/jupyter.md b/docs/base/jupyter.md deleted file mode 100644 index 6eaee11f..00000000 --- a/docs/base/jupyter.md +++ /dev/null @@ -1,241 +0,0 @@ -# Знакомство с инструментарием: Jupyter - -!!! info "Автор(ы)" - - - [Котенков Игорь](https://github.com/stalkermustang) - -## Введение - -Как любой мастер должен знать свой инструмент, так и любой человек, решивший пройти сию курс, должен понимать тонкости рабочей среды. Как уже могли понять по прошлому занятию, всю (или большую часть) работы будем делать в `Jupyter Notebook`. Но бояться нечего: по сути, `Jupyter` – это _продвинутый текстовый редактор_ с функцией запуска кода и получения результатов вычислений. Настолько продвинутый, что позволяет вам не только рисовать картинки и писать формулы, но даже строить целые интерактивные карты: - -
- ![](./_static/interactive_map.gif) -
- [Пример интерактивной визуализации прямо внутри рабочего файла с кодом](https://medium.com/@bartomolina/geospatial-data-visualization-in-jupyter-notebooks-ffa79e4ba7f8) -
-
- -На курсе, конечно, работы с гео-данными не будет, однако очень пригодятся вывод информации в виде _таблиц_, _создание и отрисовка простых графиков_, а главное, все это происходит в ^^браузере^^. Редактирование кода в браузере не вызывает лишних проблем со средами разработки и в то же время оно доступно максимально широкому кругу людей. В этом редакторе можно запускать `Python`-код, что очень похоже на интерактивный редактор MATLAB, если с ним знакомы. - -Благодаря удобству использования и доступности `Jupyter` в настоящее время стал крупным игроком в нише научных вычислений и быстрого прототипирования. Вдобавок он безумно удобен для обучения и передачи знаний. Почему? Давайте разбираться. - -## Типы ячеек - -В `Jupyter` существует несколько типов ^^ячеек^^, поговорим о двух основных: ^^Code^^ и ^^Markdown^^. В прошлом уроке создали пустой ^^ноутбук^^, чтобы проверить установку `Jupyter`. ^^Ноутбуком^^ это называется потому, что в переводе с английского ^^notebook^^ – это тетрадка (альтернативное название на русском языке). В тетрадке можно писать что-то осмысленное, черкаться, оставлять пометки. Сейчас должны видеть вот такой экран: - -
- ![](./_static/jupyter_ui_1.png) -
- Пример пустой только что созданной тетрадки -
-
- -Здесь верхней красной чертой выделено поле с ^^названием^^ ноутбука. Можете кликнуть по нему, переименовать во что-то осмысленное и нажать ++enter++, чтобы применить изменения. Нижней же чертой обозначен выпадающий список переключений ^^типов ячеек^^. По умолчанию создана одна ^^code^^ ячейка – в ней в будущем будем писать `Python`-код. Попробуйте кликнуть по списку и выбрать ^^Markdown^^ – визуально ячейка немного изменится. - -!!! note "Что такое [Markdown](https://ru.wikipedia.org/wiki/Markdown)?" - - Markdown (произносится маркда́ун) – облегченный язык разметки, созданный с целью обозначения ^^форматирования^^ в простом тексте с максимальным сохранением его читаемости человеком. - -Пример: ``Text attributes _italic_, **bold**, `monospace`.`` - -С помощью Markdown можно разнообразить код, вставить формулы (в том числе в [LaTeX](https://ru.wikipedia.org/wiki/LaTeX) формате, если он вам знаком), ссылки на статьи и многое другое. Попробуйте скопировать код из примера выше в Markdown-ячейку и нажать кнопку `Run`: - -
- ![](./_static/jupyter_ui_2.png) -
- Пример выполненной ячейки. Красным квадратом выделена кнопка `Run` -
-
- -Произошло следующее: ваша ячейка выполнилась и `Jupyter` отобразил ее содержимое. С помощью такого форматирования можно писать целые статьи с выкладками, формулами, графиками, то есть сопроводительной информацией. Поэтому, как уже было сказано, тетрадки очень удобны, особенно если соблюдать структуру, то есть писать сверху вниз с разделением на логические блоки. Также стоит отметить, что создалась новая Code-ячейка прямо под первой. - -
- ![](./_static/jupyter_ui_3.png) -
- Пример грамотно [оформленной Jupyter-тетрадки](https://nbviewer.jupyter.org/github/rlabbe/Kalman-and-Bayesian-Filters-in-Python/blob/master/05-Multivariate-Gaussians.ipynb). Такую можно скинуть коллегам – и всем все будет понятно -
-
- -!!! note "Замечание" - - Самая прекрасная часть тетрадок: ячейки разных типов можно смешивать по порядку, таким образом сначала описывая какую-то логику, а затем непосредственно реализовывая ее в коде и выполняя. - -Пока не так часто придется писать Markdown-заметки самостоятельно, основная причина их создания – желание и дальнейшее удобство использования ноутбука. Есть также другая причина, по которой акцентируем на них внимание. Может произойти так, что случайно изменили тип ячейки и не заметили этого. Теперь, если в Markdown-ячейку вставить `Python`-код, то ничего не произойдет или возникнет ошибка. Если заметили что-то странное при выполнении кода в тетрадке – ^^проверьте, корректен ли тип ячейки^^. Для выполнения кода нужно выставить тип ^^Code^^. - -
- ![](./_static/jupyter_ui_4.png) -
- Верхняя ячейка с `print` написана в Code-режиме и корректно выполняется, печатая строчку с приветствием. Нижняя ячейка же содержит ^^текст, а не код^^, поэтому ничего работать не будет (точнее, код отобразится как текст, но не будет выполнен) -
-
- -!!! attention "Внимание" - - Посмотрите как визуально отличаются эти две ячейки. Одна из них имеет прозрачный фон, другая – серый. У ^^Code^^ ячейки также есть странная надпись слева (про нее еще поговорим). - -Каждый раз вручную запускать код (или Markdown) через кнопку `Run` не очень-то удобно, поэтому можно запомнить две комбинации клавиш. ++ctrl+enter++ ^^выполнит^^ текущую ячейку и оставит «курсор» (указатель на ячейку) ^^на том же месте^^, не создавая лишнюю строчку в ноутбуке. ++shift+enter++ повторит функциональность кнопки `Run`: выполнит ячейку, а затем ^^перейдет на следующую^^ (или ^^создаст новую^^, если текущая ячейка является ^^последней^^). - -Первая комбинация (++ctrl+enter++) будет полезна в том случае, если что-то написали и знаете, что будете вносить изменения (например, менять цвет линии на графике в попытках добиться визуальной красоты), а значит, придется менять код в этой же ячейке. - -Вторая (++shift+enter++) пригодится тогда, когда хотите запустить много-много идущих подряд ячеек (можете представить, что коллега скинул вам свою тетрадку с 30 клетками и вы хотите ее запустить, чтобы получить данные). - -Не беспокойтесь, буквально к концу первого блока лекций выработается мышечная память и будете использовать сочетания клавиш на автомате. - -## Режимы работы - -Пришло время разобраться с цветом курсора, выделяющего ячейки. Он может быть ^^синим^^ или ^^зелёным^^. - -![](./_static/jupyter_ui_5.png) - -
- ![](./_static/jupyter_ui_6.png) -
- Пример разного цвета указателя клетки -
-
- -Никакой тайны за этим нет, это два режима: ^^режим редактирования^^ и ^^командный режим^^. Зелёный цвет сигнализирует о том, что вы работаете ^^с текстовым содержимым ячейки^^, то есть редактируете его! Можете писать код, вставлять формулы, что угодно. Но как только нажмете ++esc++ на клавиатуре, цвет сменится на синий, что означает ^^возможность редактирования всего ноутбука, а не отдельных ячеек^^ в нем. Можно передвигать ячейки, удалять их (полностью, а не только текст в них), добавлять новые. Стрелочками на клавиатуре можно выбирать ячейки (скакать вверх и вниз). Как только доберетесь до нужной (а вместо этого можно просто кликнуть по ней мышкой, что полезно в ситуации, когда клетка очень далеко, в самом низу страницы) – жмите ++enter++, чтобы вернуться к редактированию. - -!!! tip "Совет" - - Можно осуществлять переходы между режимами кликом мышки (внутри блока кода либо где-нибудь в стороне, слева или справа от ячейки, где ничего нет). - -
- ![](./_static/jupyter_ui_7.png) -
- Кнопки управления ноутбуком -
-
- -Выполнять описанные выше операции можно с помощью горячих клавиш (или горячих клавиш), либо через интерфейс. Описание выделенного блока кнопок для картинки выше (в порядке слева направо, с указанием сочетаний клавиш): - -1. _Сохранение ноутбука_ – ++ctrl+s++ – делайте его почаще, дабы не потерять результаты работы! -2. _Создание ячейки ниже текущей_ – ++b++ – потому, что создается клетка снизу, то есть `Below`. Логика для ++a++ и `Above` аналогична. -3. _Вырезать ячейку_ – ++x++ – применимо и к целому блоку ячеек (можно выделить с зажатой клавишей ++shift++). Функциональность как и в Excel/Word: убрать в одном месте, чтобы вставить в другом. -4. _Копировать ячейку_ – ++c++. -5. _Вставить ячейку из буфера_ – ++v++ – после вырезания или копирования ячейки. -6. _Переместить текущую выделенную ячейку_ – ^^вверх^^. -7. _Переместить текущую выделенную ячейку_ – ^^вниз^^. - -Описание всех доступных команд (и соответствующих им хоткеев) доступно при нажатии на кнопку с клавиатурой в правой части выделенного блока меню (вне красного прямоугольника). - -!!! example "Упражнение" - - Попробуйте потратить 5-7 минут на практику использования этих кнопок и сочетаний клавиш. - -Первое время можете пользоваться только элементами UI-интерфейса – это нормально, главное, сопоставить кнопки и стоящую за ними функциональность. - -## Оставшиеся кнопки на панели - -Про кнопку `Run` (и ++shift+enter++) уже поговорили, а что с остальными? - -
- ![](./_static/jupyter_ui_8.png) -
- Кнопки управления ^^ЯДРОМ^^ ноутбука -
-
- -Для того, чтобы можно было запускать код `Python`, запускается так называемое ^^«ядро»^^ (или kernel), то есть приложение, которое непосредственно выполняет (запускает) код и передает результаты обратно в `Jupyter`-ноутбук. За это отвечает как раз `Run`. - -Справа от нее расположен `Stop`, который прерывает выполнение программы; может быть полезен в случаях, когда запустили расчеты на час, но заметили ошибку – и поэтому нужно и код переписать, и ячейку с кодом снова запустить. в этой ситуации сначала ^^останавливаете^^ выполнение, редактируете код, затем жмете `Run` – и всё готово! - -Но случается беда и код не останавливается, потому что ядро `Python` зависает. В таких случаях нужно перезапустить ядро – и кнопка с закругленной стрелочкой `Restart` поможет осуществить задуманное. Будьте аккуратны – все несохраненные данные будут потеряны (значения переменных, результаты расчетов, данные для построения графиков). Сама тетрадка останется без изменений, то есть написанное сохранится. Концепция «ядра» и запуска кода станет более понятна, когда перейдем к практике. - -!!! tip "Совет" - - Пока стоит держаться правила: «Накосячил? Попробуй остановить (`Stop`) ядро. Не получается? Тогда перезапускай (`Restart`) его!» - -Нужно понимать, что ядро «помнит» все предыдущие выполненные ячейки (пока не будет перезагружено или выключено), а значит, можете позже в коде переиспользовать те части, которые были описаны ранее (например, переменные или физические константы). Иными словами, состояние ядра сохраняется во времени и между ячейками – оно относится к документу в целом, а не к отдельным ячейкам. - -Последняя кнопка из выделенного блока имеет говорящее название: `Re-start and run all`. Ядро будет перезапущено (все переменные и данные удалятся), а затем каждая ячейка будет выполнена в порядке сверху вниз. Поэтому рекомендуется соблюдать структуру, чтобы запускать код с нуля (после возвращения к ноутбуку на следующий день, но с новым ядром, так как компьютер был выключен) – и он отрабатывал. - -## Что это за `In [*]`? - -Та самая надпись слева от запущенной Code-ячейки. Это вспомогательная информация о том, что происходит с ^^кодовой^^ ячейкой (`In` означает ^^Input^^, то есть ввод кода). Возможно несколько вариантов заполнения. - -
- ![](./_static/jupyter_ui_9.png) -
- Пример трех видов информации о статусе ячейки -
-
- -В первом случае в квадратных скобках ничего нет – это значит, что ячейка еще не была запущена. Возможно, вы забыли, а быть может, она просто ждет своего часа. - -Во втором случае ячейка была запущена шестой по счету (да-да, ячейки выполняются по порядку, который задаете сами!) и она успешно отработала и завершилась. - -В последней строчке умышленно был сделан бесконечный цикл. Это означает, что код никогда не сможет выполниться и будет висеть до тех пор, пока не остановите (кнопка `Stop`) ядро. Поэтому там выведен индикатор выполнения ячейки – в скобках указана звездочка `*`. Обратите внимание: это не всегда плохой сигнал. Если код должен выполняться 2-3 минуты, то все это время будет выводиться `[*]`. Когда код отработает и результат будет получен, отрисуется цифра (например, `[7]` ). - -## Самая полезная клавиша - -Пришло время программировать! Скопируйте себе в ячейку ноутбука кусок кода ниже и попробуйте его запустить. Не переживайте, он может показаться сложным и непонятным, но сейчас не требуется понимание всех деталей. - -```python linenums="1" -import numpy as np -import mat.pyplot as plt -%matplotlib inline - -# Fixing random state for reproducibility -np.random.seed(19680801) - -# Compute pie slices -N = 20 -θ = np.linspace(0.0, 2 * np.pi, N, endpoint=False) -radii = 10 * np.random.rand(N) -width = np.pi / 4 * np.random.rand(N) -colors = plt.cm.viridis(radii / 10.) - -ax = plt.subplot(111, projection="polar") -ax.bar(θ, radii, width=width, bottom=0.0, color=colors, alpha=0.5) -plt.show(); -``` -```bash -ModuleNotFoundError Traceback (most recent call last) - in - 1 import numpy as np -----> 2 import mat.pyplot as plt - 3 get_ipython().run_line_magic('matplotlib', 'inline') - 4 - 5 # Fixing random state for reproducibility - -ModuleNotFoundError: No module named 'mat' -``` - -Ошибка. По сообщению видно (стрелочка в левой части указывает на проблемное место), что во второй строчке используется слово `mat`, при этом `Python` жалуется на отсутствие такого модуля. Всё дело в том, что в коде выше производится попытка рисования графика и для этого используется библиотека `matplotlib`. Но в одной из строк написано только `mat`. Это не дело, давайте исправлять. Однако всех библиотек не запомнишь – и это не нужно. Попробуйте поставить курсор после буквы `t` (и перед точкой) и нажать ++tab++; должны увидеть ^^список подсказок^^ и из него выбрать нужный вариант. Этот список не только сокращает время написания кода (за счет автоматического дополнения), но и позволяет избежать ошибок в написании. Обязательно пользуйтесь этим инструментом. - -Если все сделали правильно, воспользовавшись подсказкой, то после очередного запуска (`Run`) кода появится рисунок. - -
- ![](./_static/jupyter_ui_10.png) -
- Другой пример удачного использования: есть несколько переменных со сложным, но очень похожим названием. Не стоит их перепечатывать – достаточно нажать ++tab++ -
-
- -Что ж, большое количество новой информации позади, давайте подведем итоги! - -## Что узнали из лекции - -- Существует два основных типа ячеек, один предназначен для программирования (написания кода), другой – для описания (формул, определений). -- Существует два режима работы: `edit` – редактирование конкретной ячейки и `control` – работа со всей структурой тетрадки/ноутбука. -- Режимы работы можно различить по цвету рамки вокруг активной ячейки, а тип ячейки – по прозрачности фона и наличию надписи `In[ ]` слева. -- Между режимами можно переключаться с помощью ++esc++ и ++enter++. -- Чтобы запустить ячейку (с кодом или текстом), нужно нажать на кнопку `Run` сверху, либо воспользоваться сочетаниями клавиш: ++shift+enter++, ++ctrl+enter++. -- Нужно не забывать сохранять ноутбук (++ctrl+s++), а быстро добавить ячейку кода можно с помощью плюсика слева сверху (или клавиши ++b++). -- Клавиши ++c++ / ++v++ позволяют копировать и вставлять ячейки в `control`-режиме. -- `In[3]` указывает на порядок выполнения ячеек с кодом, `In[*]` – на процесс выполнения. -- Если долго ждете выполнения Code-блока, можно остановить (кнопка `Stop`) ядро, если не помогает – `Restart`. -- Ядро – это процесс, выполняющий код, и после перезагрузки оно не сохраняет переменные. -- ++tab++ – ваш друг, позволяющий избегать опечаток, а также реже пользоваться документацией. - -## Бонус-материал - -- [Полная официальная документация по Jupyter](https://jupyter-notebook.readthedocs.io/en/stable/notebook.html). -- Если захочется узнать больше о трюках в ноутбуках, о недостатках и преимуществах по сравнению с альтернативами, предлагаем посмотреть выступление Joel Grus: - -

- -- [Основной синтаксис написания и форматирования Markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) -- [Markdown cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) -- [Список LaTeX символов](https://latex-programming.fandom.com/wiki/List_of_LaTeX_symbols) diff --git a/docs/base/list_loop.md b/docs/base/list_loop.md deleted file mode 100644 index 061f64d8..00000000 --- a/docs/base/list_loop.md +++ /dev/null @@ -1,394 +0,0 @@ -# Списки и циклы - -!!! info "Автор(ы)" - - - [Котенков Игорь](https://github.com/stalkermustang) - - [Baushenko Mark](https://github.com/e0xextazy) - -## Введение в списки объектов - -В предыдущих лекциях операции были с малым количеством переменных. Для каждого блока логики или примера кода вводилось 3-5 объектов, над которыми осуществлялись некоторые операции. Но что делать, если объектов куда больше? Скажем, необходимо хранить информацию об учащихся класса – пусть это будет рост, оценка по математике или что-либо другое. Крайне неудобно будет создавать и хранить 30 отдельных переменных. А если ещё и нужно посчитать среднюю оценку в классе! - -```python linenums="1" -average_grade = petrov_math + kosareva_math + zinchenko_math + kotenkov_math # + ... -average_grade = average_grade / 30 -``` - -Такой код к тому же получается крайне негибким: если количество студентов, как и их состав, изменится, то нужно и формулу переписать, так ещё и делитель – в нашем случае 30 – изменять. - -Часто в программах приходится работать с большим количеством однотипных переменных. Специально для этого придуманы ^^массивы^^ (по-английски array). В Python их ещё называют ^^списками^^ (list). В некоторых языках программирования эти понятия отличаются, но не в Python. Список может хранить переменные ^^разного^^ типа. Также списки называют [«контейнерами»](https://ru.wikipedia.org/wiki/Контейнер_(программирование)), так как они хранят какой-то набор данных. Для создания простого списка необходимо указать квадратные скобки или вызвать конструктор типа (`list` – это отдельный тип, фактически такой же, как `int` или `str`), а затем перечислить ^^объекты через запятую^^: - -```python linenums="1" -# разные способы объявления списков -first_list = [] -second_list = list() -third_list = list([1,2, "stroka", 3.14]) -fourth_lust = [15, 2.2, ["another_list", False]] - -print(type(second_list), type(fourth_lust)) -print(first_list, fourth_lust) -``` -```bash - -[] [15, 2.2, ['another_list', False]] -``` - -!!! info "Между тем" - - Хоть список и хранит переменные разного типа, но так делать без особой необходимости не рекомендуется – можно запутаться и ошибиться в обработке объектов списка. В большинстве других языков программирования массив может хранить только объекты одного типа. - - Для хранения сложных структур (скажем, описание студента – это не только оценка по математике, но и фамилия, имя, адрес, рост и так далее) лучше использовать классы – с ними познакомимся в будущем. А ещё могут пригодиться [^^кортежи^^](./list_loop.md#tuple), или `tuple`. - -Теперь можно один раз создать список и работать с ним как с единым целым. Да, по-прежнему для заведения оценок студентов придётся разово их зафиксировать, но потом куда проще исправлять и добавлять! Рассмотрим пример нахождения средней оценки группы, в которой всего 3 учащихся, но к ним присоединили ещё 2, а затем – целых 5: - -```python linenums="1" -# базовый журнал с тремя оценками -math_journal = [3, 3, 5] - -# добавим новопришедших студентов -math_journal.append(4) -math_journal.append(5) - -# и сразу большую группу новых студентов -math_journal.extend([2,3,4,5,5]) - -print(f"{math_journal = }") - -# найдём среднюю оценку как сумму всех оценок, делённую на их количество -avg_grade = sum(math_journal) / len(math_journal) -print(f"{avg_grade = }") -``` -```bash -math_journal = [3, 3, 5, 4, 5, 2, 3, 4, 5, 5] -avg_grade = 3.9 -``` - -В коде выше продемонстрировано сразу несколько важных аспектов: - -1. добавлять по одному объекту в конец списка можно с помощью метода списка `append()`. -2. метод `append()` принимает в качестве аргумента один объект. -3. слияние нескольких списков (конкатенация, прямо как при работе со строками) осуществляется командой `extend()` (расширить в переводе с английского). -4. для списков определена функция `len()`, которая возвращает целое число `int` – количество объектов в списке. -5. функция `sum()` может применяться к спискам для суммирования всех объектов (если позволяет тип – то есть для `float`, `int` и `bool`; попробуйте разобраться самостоятельно, как функция работает с последним указанным типом). -6. для методов `append()` и `extend()` не нужно приравнивать результат выполнения какой-то переменной – изменится сам объект, у которого был вызван метод (в данном случае это `math_journal()`); -7. списки в Python ^^упорядочены^^, то есть объекты сами по себе места не меняют, и помнят, в каком порядке были добавлены в массив. - -!!! info "О методе" - - В тексте выше встречается термин ^^метод^^, который, быть может, не знаком. По сути метод есть такая же ^^функция^^, о которых говорили ранее, но она принадлежит какому-то объекту с определенным типом. Не переживайте, если что-то непонятно – про функции и методы поговорим подробно в ближайших лекциях! - - `print()`, `sum()` – функции, они существуют сами по себе; - `append()`, `extend()` – методы объектов класса `list`, не могут использоваться без них. - -## Индексация списков - -Теперь, когда стало понятно, с чем предстоит иметь дело, попробуем усложнить пример. Как узнать, какая оценка у третьего студента? Всё просто – нужно воспользоваться ^^индексацией^^ списка: - -```python linenums="1" -# базовый журнал с пятью оценками -math_journal = [1, 2, 3, 4, 5] - -third_student_grade = math_journal[3] -print(third_student_grade) -``` -```bash -4 -``` - -И снова непонятный пример! Давайте разбираться: - -- для обращения к `i`-тому объекту нужно в квадратных скобках указать его индекс; -- ^^индекс^^ в Python начинается ==c нуля== – это самое важное и неочевидное, здесь чаще всего случаются ошибки; -- поэтому `[3]` обозначает взятие 4-й оценки (и потому выводится `4`, а не `3`); -- всего оценок 5, но так как индексация начинается с нуля, то строчка `math_journal[5]` выведет ошибку – доступны лишь индексы `[0, 1, 2, 3, 4]` для взятия (так называется процедура обращения к элементу списка по индексу – взятие по индексу). - -
- ![](./_static/list_indexing_1.png) -
- Пример списка из трёх объектов. Сверху показаны их индексы, включая отрицательные -
-
- -Также в `Python` существуют отрицательные индексы (-1, -2 ...). Они отсчитывают объекты списка, начиная с конца. Так как нуль уже занят (под первый объект), то он не используется. - -```python linenums="1" -# базовый журнал с пятью оценками -math_journal = [1, 2, 3, 4, 5] - -# возьмём последнюю оценку -last_grade = math_journal[-1] -print(f"Последняя оценка: {last_grade}") - -# а теперь – предпоследнюю -prev = math_journal[-2] -print(f"Предпоследняя оценка: {prev}") - -# конечно, взятие по индексам можно использовать в ранее разобранном синтаксисе - -if math_journal[-1] < math_journal[-2]: - math_journal[-1] += 1 - print("Последняя оценка меньше предпоследней. Натянем студенту?") -else: - math_journal[-2] = 2 - print("Последний студент сдал очень хорошо, на его фоне предпоследний просто двоечник!") -``` -```bash -Последняя оценка: 5 -Предпоследняя оценка: 4 -Последний студент сдал очень хорошо, на его фоне предпоследний просто двоечник! -``` - -Всё это важно не только для грамотного оперирования конкретными объектами, но и следующей темы. - -## Срезы - -Срезы, или slices – это механизм обращения сразу к нескольким объектам списка. Для создания среза нужно в квадратных скобках указать двоеточие, слева от него – индекс начала среза (по умолчанию `0`, можно не выставлять) ^^включительно^^, справа – границу среза ^^не включительно^^ (пустота означает «до конца списка»). Может показаться нелогичной такая разнородность указания границ, но на самом деле она безумно удобна – особенно вместе с тем, что индексация начинается с нуля. Быстрее объяснить на примере: - -```python linenums="1" -# базовый журнал с пятью оценками -math_journal = [1, 2, 3, 4, 5] - -# как взять первые 3 оценки? -first_3_grades = math_journal[:3] -print(f"{first_3_grades = }") - -# как взять последние две оценки? -last_2_grades = math_journal[-2:] -print(f"{last_2_grades = }") - -# сделаем срез на 4 оценки, начиная со второй (с индексом 1) -start_index = 1 -some_slice = math_journal[start_index : start_index + 4] -print(f"{some_slice = }") - -# возьмём столько объектов из начала, сколько объектов в some_slice -yet_another_slice = math_journal[:len(some_slice)] - -# а вот так можно проверить, попадает ли объект в список -print(f"Верно ли, что единица входит в some_slice? {1 in some_slice}") -print(f"Верно ли, что единица входит в yet_another_slice? {1 in yet_another_slice}") -``` -```bash -first_3_grades = [1, 2, 3] -last_2_grades = [4, 5] -some_slice = [2, 3, 4, 5] -Верно ли, что единица входит в some_slice? False -Верно ли, что единица входит в yet_another_slice? True -``` - -!!! info "Между тем" - - Можно сделать пустой срез, и тогда Python вернет пустой список без объектов. Можете проверить сами: - `["1", "2", "3"][10:20]` - -Давайте проговорим основные моменты, которые ^^крайне важно понять^^: - -- так как индексация начинается с нуля (значение по умолчанию) и правая граница не включается в срез, то берутся объекты с индексами `[0, 1, 2]`, что в точности равняется трём первым объектам; -- срез `[-2:]` указывает на то, что нужно взять все объекты до конца, начиная с предпоследнего; -- значения в срезе могут быть ^^вычислимы^^ (и задаваться сколь угодно сложной формулой), но должны оставаться ^^целочисленными^^; -- если нужно взять `k` объектов, начиная с `i`-го индекса, то достаточно в качестве конца среза указать `k+i`; -- для проверки вхождения какого-либо объекта в список нужно использовать конструкцию `x_obj in some_list`, которая вернет `True`, если массив содержит `x_obj`, и `False` в ином случае; -- самый простой способ сделать копию списка - это сделать срез по всему объекту: `my_list[:]`. Однако будьте внимательны – в одних случаях копирование происходит полностью (по значению), а в некоторых сохраняются ссылки (то есть изменив один объект в скопированном списке вы измените объект в исходном). Связано это с типом объектов (mutable/immutable), подробнее об этом будет рассказано в следующей лекции. В общем, если работаете с простыми типами (`int`/`str`), то срез вернёт копию, и её изменение не затронет исходный список. Однако для хранения новых данных нужна память, поэтому при копировании десятков миллионов объектов можно получить ошибку, связанную с нехваткой памяти. - -## Кортеж (tuple) - -Выше уже упоминалось о таком понятии как кортеж. Можете спросить: зачем нужны кортежи, если они так сильно похожи на списки? Чтобы больше не возникало подобных вопросов давайте сравним их! - -- Главным отличием является то, что кортежи это ^^неизменяемый тип данных^^. То есть в процессе выполнения программы можно быть уверенным, что значения внутри кортежа останутся ^^неизменными^^. И из этого свойства вытекает множество других. -- Кортеж имеет ^^меньше размер^^, чем список. Это связано с тем, что список – изменяемый объект и ему нужно хранить дополнительную информацию о выделенной памяти. - - ```python linenums="1" - a = (1, 2, 3, 4, 5, 6) - print(a.__sizeof__()) - - b = [1, 2, 3, 4, 5, 6] - print(b.__sizeof__()) - ``` - ```bash - 36 - 44 - ``` - -- Возможность использовать кортежи в качестве ключей словаря: - - ```python linenums="1" - d = {(1, 1, 1) : 1} - print(d) - ``` - ```bash - {(1, 1, 1): 1} - ``` - - ```python linenums="1" - d = {[1, 1, 1] : 1} - print(d) - ``` - ```bash - Traceback (most recent call last): - File "", line 1, in - d = {[1, 1, 1] : 1} - TypeError: unhashable type: 'list' - ``` - -Чтобы создать пустой кортеж, можно воспользоваться двумя конструкциями: - -```python linenums="1" -a = tuple() # С помощью встроенной функции tuple() -a = () # С помощью литерала кортежа -``` - -Давайте для примера создадим кортеж с 1 элементом: - -```python linenums="1" -a = ("s") -print(a) -``` -```bash -'s' -``` - -Получилась строка. Но как же так? Давайте попробуем по-другому: - -```python linenums="1" -a = ("s", ) -print(a) -``` -```bash -('s',) -``` - -Оказывается все дело в запятой. Сами по себе ^^скобки ничего не значат^^, точнее значат то, что внутри них находится одна инструкция, которая может быть отделена пробелами, переносом строк и т.д. - -Можно подумать что у кортежей одни только плюсы, но это не так. ^^Количество операций^^, которые можно применять над кортежами ^^меньше, чем у списков.^^ Это опять же связано с тем, что они неизменяемые. Получается что над кортежами можно ^^применять все операции над списками, которые не изменяют список^^: сложение, умножение на число, методы `index()`, `count()` и некоторые другие операции. - -## Циклы - -До сих пор в примерах хоть и обращались к разным объектам, добавляли и меняли их, всё ещё не было рассмотрено взаимодействие сразу с несколькими. Попробуем посчитать, сколько студентов получили оценку от 4 и выше. Для этого интуитивно кажется что нужно ^^пройтись по всем оценкам от первой до последней^^, сравнить каждую с четверкой. Для прохода по списку, или ^^итерации^^, используются ^^циклы^^. -Общий синтаксис таков: - -```python linenums="1" -example_list = list(...) -for item in example_list: - <> блок кода внутри цикла (аналогично блоку в if) - ... что-то сделать с item - <> -``` - -Здесь `example_list` – это некоторый итерируемый объект. Помимо списка в Python существуют и другие итерируемые объекты, но пока будем говорить о массивах. - -Этот цикл работает так: указанной ^^переменной `item` присваивается первое значение из списка^^, и выполняется ^^блок кода^^ внутри цикла (этот блок, напомним, определяется отступом. Он выполняется весь от начала отступа и до конца, как и было объяснено в пятой лекции). Этот блок ещё иногда называют ^^телом цикла^^. Потом переменной `item` присваивается следующее значение (второе), и так далее. Переменную, кстати, можно называть как угодно, необязательно `item`. - -^^Итерацией^^ называется каждый ^^отдельный проход^^ по телу цикла. Цикл всегда повторяет команды из тела цикла несколько раз. Два примера кода ниже аналогичны: - -```python linenums="1" -math_journal = [3, 4, 5] -counter = 0 - -for cur_grade in math_journal: - if cur_grade >= 4: - counter += 1 - -print(f"Всего хорошистов и отличников по математике {counter} человека") -``` -```bash -Всего хорошистов и отличников по математике 2 человека -``` - -```python linenums="1" -math_journal = [3, 4, 5] -counter = 0 - -cur_grade = math_journal[0] -if cur_grade >= 4: - counter += 1 - -# не забываем менять индекс с 0 на 1, так как каждый раз берётся следующий элемент -cur_grade = math_journal[1] -if cur_grade >= 4: - counter += 1 - -# и с единицы на двойку -cur_grade = math_journal[2] -if cur_grade >= 4: - counter += 1 - -print(f"Всего хорошистов и отличников по математике {counter} человека") -``` -```bash -Всего хорошистов и отличников по математике 2 человека -``` - -Понятно, что первый кусок кода обобщается на любой случай – хоть оценок десять, хоть тысяча. Второе решение не масштабируется, появляется ^^много одинакового кода, в котором легко ошибиться^^ (не поменять индекс, к примеру). - -Движемся дальше. Так как каждый элемент списка закреплен за конкретным индексом, то в практике часто возникают задачи, логика которых завязана на индексах. Это привело к тому, что появилась альтернатива для итерации по списку. Функция `range` принимает аргументы, аналогичные срезу в списке, и возвращает итерируемый объект, в котором содержатся целые числа (индексы). Так как аргументы являются аргументами функции, а не среза, то они соединяются запятой (как `print(a, b)` нескольких объектов). Если подан всего один аргумент, то нижняя граница приравнивается к нулю. Посмотрим на практике, как сохранить номера (индексы) всех хорошо учащихся студентов: - -```python linenums="1" -math_journal = [4, 3, 4, 5, 5, 2, 3, 4] -good_student_indexes = [] - -for student_index in range(len(math_journal)): - curent_student_grade = math_journal[student_index] - if curent_student_grade >= 4: - good_student_indexes.append(student_index) - -print(f"Преуспевающие по математике студенты находятся на позициях: {good_student_indexes}") -``` -```bash -Преуспевающие по математике студенты находятся на позициях: [0, 2, 3, 4, 7] -``` - -В примере `student_index` принимает последовательно все значения от `0` до `7` включительно. `len(math_journal)` равняется `8`, а значит, восьмёрка сама не будет включена в набор индексов для перебора. На каждой итерации `curent_student_grade` меняет своё значение, после чего происходит проверка. Если бы была необходимость пробежаться только по студентам, начиная с третьего, то нужно было бы указать `range(2, len(math_journal))` (двойка вместо тройки потому, что индексация с нуля, ведь мы перебираем индексы массива). - -Давайте немного модифицируем предыдущий пример: - -```python linenums="1" -math_journal = [4, 3, 4, 5, 5, 2, 3, 4] -good_student_indexes = [] - -for student_index, student_grade in enumerate(math_journal): - if student_grade >= 4: - good_student_indexes.append(student_index) - -print(f"Преуспевающие по математике студенты находятся на позициях: {good_student_indexes}") -``` -```bash -Преуспевающие по математике студенты находятся на позициях: [0, 2, 3, 4, 7] -``` - -В данном случае итерации происходят по объекту `enumerate(math_journal)`. Метод `enumerate()` возвращает итератор состоящий из `tuple`, где каждый `tuple` содержит пару состоящую из ^^индекса элемента^^ и ^^самого элемента^^. В отличии от предыдущего примера, здесь не нужно получать оценку студента по его индексу (строчка номер 5), а можно ^^напрямую^^ ее использовать из цикла `for`. Если предполагается работать одновременно и с индексами списка, и с его элементами, то метод `enumerate()` – ^^отличный способ сделать код чище^^! - -Выше описаны основные концепции обращения со списками. Их крайне важно понять и хорошо усвоить, без этого писать любой код будет безумно сложно. Скопируйте примеры к себе в тетрадку, поиграйтесь, поменяйте параметры цикла и проанализируйте изменения. - -## List comprehensions - -Некоторые циклы настолько просты, что занимают 2 или 3 строчки. Помимо прочего ещё и быстрее исполняются. Как пример – привести список чисел к списку строк: - -```python linenums="1" -# грубый вариант -inp_list = [1,4,6,8] -out_list = [] - -for item in inp_list: - out_list.append(str(item)) - -# list comprehension -out_list = [str(item) for item in inp_list] -print(out_list) -``` -```bash -['1', '4', '6', '8'] -``` - -Две части кода идентичны за вычетом того, что нижняя – с непонятной конструкцией в скобках – короче. Python позволяет в рамках одной строки произвести какие-либо простые преобразования (помним, что `str()` – это вызов функции!). Фактически самый частый пример использования – это паттерн «применение функции к каждому объекту списка». - -## Что узнали из лекции - -- `list` – это ^^объект-контейнер, который хранит другие объекты разных типов^^; запись происходит упорядочено и последовательно, а каждому объекту присвоен ^^целочисленный номер, начиная с нуля^^; -- для добавления одного объекта в `list` нужно использовать метод объекта `list` – `append()`, а для расширения списка сразу на несколько позиций пригодится `extend()`; -- проверить, входит ли объект в список, можно с помощью конструкции `obj in some_list`; -- индексы ^^могут быть отрицательными^^: `-1`, `-2` ... В таком случае нумерация начинается от последнего объекта; -- можно получить часть списка, сделав ^^срез^^ с помощью конструкции `list[start_index : end_index]`, при этом объект на позиции `end_idnex` не будет включён в возвращаемый список (т.е. ^^срез работает не включительно по правую границу^^); -- В зависимости от задачи – иногда удобнее и правильнее использовать `tuple` вместо `list`; -- часто со списками используют ^^циклы, которые позволяют итерироваться по объектам массива^^ и выполнять произвольную логику в рамках отделенного отступом блока кода; -- для итерации по индексам можно использовать `range()`, а для итерации по элементам с индексами – `enumerate()`; -- простые циклы можно свернуть в ^^list comprehension^^, и самый частый паттерн для такого преобразования – это ^^применение некоторой функции к каждому объекту^^ списка (если `x` это функция, то синтаксис будет таков: `[x(item) for item in list])`). diff --git a/docs/base/object_class_method.md b/docs/base/object_class_method.md deleted file mode 100644 index f1e4f179..00000000 --- a/docs/base/object_class_method.md +++ /dev/null @@ -1,245 +0,0 @@ -# Объекты, классы и методы - -!!! info "Автор(ы)" - - - [Котенков Игорь](https://github.com/stalkermustang) - -## ООП: Объектно-Ориентированное Программирование - -Что же такое объектно-ориентированное программирование? Судя по названию, ключевую роль здесь играют объекты, на которые ориентируется дальнейший процесс программирования. Если взглянем на реальный мир, то для нас он предстанет в виде множества объектов, обладающих определенными свойствами, взаимодействующих между собой и вследствие этого изменяющимися. Эта привычная для взгляда человека картина мира была перенесена в программирование. Python - это объектно-ориентированный язык программирования, и ^^всё в нем является объектами^^. - -^^Объект^^ - это набор данных и инструкций в памяти компьютера, в том числе: - -- тип объекта -- данные, формирующие объект (контент внутри него) -- методы - -
- ![](./_static/class_and_obj1.png){ width="250" align=left } -
- Так можно проиллюстрировать соотношение «класс - объекты». Сверху указаны общие прототипы (прямоугольник, звезда, треугольник), снизу - уникальные экземпляры, со своим цветом и деталями -
-
- -Как определить тип уже знаем. И с объектами на самом деле знакомы с самого начала - ведь даже целочисленная переменная `5`, имеющая `type(5) = int`, представляет собой объект. - -!!! info "Напомним" - - Методы - это те же функции, только существующие не сами по себе, а являющиеся частью класса. - -```python linenums="1" -example_list = list(["что-то", "с"]) -print(f"Метод append имеет тип {example_list.append}") - -# вот так можно вызвать метод, изменяя сам экземпляр класса -example_list.append("чем-то") - -# а вот так можно обратиться к атрибуту конкретного объекта -attr_value = example_list.__doc__ -print(f"Значение атрибута: {attr_value}") -``` -```bash -Метод append имеет тип -Значение атрибута: Built-in mutable sequence. - -If no argument is given, the constructor creates a new empty list. -The argument must be an iterable if specified. -``` - -`list` - это класс, и в первой строчке кода выше создается ^^объект, или экземпляр класса^^ `example_list`. Он хранит свой набор данных (контент). Метод `append` общий для всех списков, однако меняет только конкретный экземпляр. Обратим внимание: этот метод ничего не возвращает, он меняет сам объект и его контент. Не все методы работают схожим образом, и придется запоминать принцип работы самых распространенных методов. К примеру, сложение чисел или строк внутри Python также осуществляется с помощью методов, однако это не меняет саму переменную, как было рассказано в более ранних лекциях: - -```python linenums="1" -# создадим два объекта класса int -a = 3 -b = int(4) - -# неявно вызовем метод сложения -a + b -# проверим, что содержимое объектов не изменилось -print(f"{a = }, {b = }") -``` -```bash -a = 3, b = 4 -``` - -Конкретно в данном случае логика работы обусловлена свойствами `mutable`/`immutable` объектов, о чём также упоминалось в одной из предшествующих лекций. `int` неизменяем, и потому при вызове метода сложения возвращает новый объект - ведь самого себя изменить не получится. `list` же может меняться, и `append` меняет содержимое `inplace`. - -
- ![](./_static/class_and_obj_house.png){ width="450" } -
- Другой житейский пример - по одному чертежу (классу) можно построить разные (но похожие!) дома, в которых разные семьи, убранство, разные обои -
-
- -## Определение классов - -Давайте попробуем создать свой первый класс: - -```python linenums="1" -# определим классы -class List: - def __init__(self, initial_content = None): - # указывать в виде значения по умолчанию mutable-объекты неправильно - if initial_content is None: - initial_content = [] - self.content = initial_content - - def append(self, new_element): - # изменение производится inplace, с заменой собственного контента - self.content = self.content + [new_element] - -class Int: - def __init__(self, value): - self.value = value - - def add(self, second_value): - # изменение не производится, создается новый объект и он же возвращается - return Int(self.value + second_value.value) - -# воспроизведем примеры кода выше для List -example_list = List(["что-то", "с"]) -print(f"{example_list.content = }") - -example_list.append("чем-то") -print(f"{example_list.content = }") -print(f"{type(example_list) = }") - -# и для Int -a = Int(3) -b = Int(4) - -a.add(b) -print(f"После простого сложения: {a.value = }, {b.value = }") - -c = a.add(b) -print(f"После записи в переменную результата: {c.value = }") -``` -```bash -example_list.content = ['что-то', 'с'] -example_list.content = ['что-то', 'с', 'чем-то'] -type(example_list) = -После простого сложения: a.value = 3, b.value = 4 -После записи в переменную результата: c.value = 7 -``` - -Что важно заметить и отметить в этом примере: - -1. Как объявить класс? С помощью ключевого слова `class`, указания названия класса (таким образом создается новый тип данных) и перечисления методов: - - ```python - class ИмяКласса: - <код_тела_класса> - ``` - -2. Обязательно определить метод `__init__`. Это метод, вызываемый при создании нового объекта класса и отвечающий за определение его контента. В нем через запятую, как и в обычной функции, перечислить необходимые переменные и, по возможности, их значения по умолчанию. -3. Каждый метод должен первым аргументом принимать ^^экземпляр объекта^^ (по соглашению он называется `self`). При этом при вызове метода Python автоматически подставит сам объект, делать это руками не нужно. По сути под капотом происходит следующее: - - ```python linenums="1" - # вызываем метод класса - не объекта! - и передаем первым аргументом объект, - # который при обычных обстоятельствах будет записан в self - result = Int.add(Int(3), Int(4)) - print(f"{result.value}") - ``` - ```bash - 7 - ``` - -4. Атрибутом называется переменная, хранящаяся в экземпляре класса. -5. В рамках методов атрибуты объекта доступны с использованием ключевого слова `self`. К примеру, `self.data`. -6. Вне методов атрибуты доступны у экземпляров через точку: `some_object.attr_name`. -7. Для создания объекта класса нужно указать имя класса (типа) и передать аргументы: `Int(3)` - как раз оно. -8. Методы как могут возвращать что-либо (в том числе новый объект того же класса), так и ничего не возвращать. - -В заключение еще одна картинка, иллюстрирующая суть класса, экземпляра, атрибутов и методов: - -
- ![](./_static/class_and_obj_pika.png){ width="450" } -
- Что это за покемон? -
-
- -## Пример использования для хранения состояние - -Допустим, есть некоторая среда, заданная состоянием, и есть объекты, существующие в этой среде, как-то взаимодействующие между собой (и со средой). Есть набор функций, который осуществляет эти взаимодействия. Тогда удобно ввести некоторый объект `system` класса `System`, который хранит эту информацию, и передавать его как параметр в методы расчета чего-либо (никакой конкретной логики тут не заложено, не пытайтесь понять, за что отвечает `alpha` и прочие переменные - пример абстрактный): - -```python linenums="1" -# класс системы, с ее параметрами и состоянием -class System: - def __init__(self, param_vector, alpha, gamma, multiplier = 2.0, energy = 0.0): - self.param_vector = param_vector - self.alpha = alpha - self.gamma = gamma - self.multiplier = multiplier - self.energy = energy - - # начальное состояние - self.system_state = [ - (alpha - gamma) * multiplier * param - for param - in self.param_vector - ] - - def first_action(self, object): - # взаимодействие с одним объектом: увеличение энергии, изменение состояния системы - self.gamma -= object.energy - self.energy += object.energy - self.system_state = [param - self.alpha * self.energy for param in self.system_state] - - def second_action(self, list_of_object): - # взаимодействие с несколькими объектами - увеличение их энергии - for obj in list_of_object: - obj.energy += self.gamma * self.multiplier - -class Object: - def __init__(self, energy = 10.0): - # объект хранит только один атрибут - self.energy = energy - -# симуляция одного цикла в системе -def one_system_cycle(system: System, objects = None): - if objects is not None: - system.second_action(objects) - # убираем один последний объект - objects = objects[:-1] - else: - objects = [Object(val) for val in range(5)] - for obj in objects: - system.first_action(obj) - return objects - -params = [1.0, 3.0, 4.15, 0.0] -alpha = 5 -gamma = 0.18 -system = System(params, alpha, gamma, energy = 10) - -# изначально объектов нет, они появятся после первого цикла -objects = None - -for cycle_num in range(1, 4): - print(f"Состояние системы на итерации {cycle_num}: {system.system_state}.", end="\t") - objects = one_system_cycle(system, objects) - print(f"Всего объектов: {len(objects)}", end="\t") - - total_object_energy = sum([obj.energy for obj in objects]) - print(f"Суммарная энергия объектов: {total_object_energy}") -``` -```bash -Состояние системы на итерации 1: [9.64, 28.92, 40.00600000000001, 0.0]. Всего объектов: 5 Суммарная энергия объектов: 10 -Состояние системы на итерации 2: [-340.36, -321.08, -309.994, -350.0]. Всего объектов: 4 Суммарная энергия объектов: -72.56 -Состояние системы на итерации 3: [-340.36, -321.08, -309.994, -350.0]. Всего объектов: 3 Суммарная энергия объектов: -114.84 -``` - -Обратите внимание на то, что функция `one_system_cycle` не возвращает `system` - ведь прямо во время итераций меняем ее состояние, и в последующие моменты времени эти изменения сохраняются, то есть состояние остается. Таким образом, эту систему (среду) - а именно объект, экземпляр класса `System` - как параметр ^^можно передавать в десятки функций, и каждая из них будет видеть актуальное состояние^^. - -## Что узнали из лекции - -- объекты одного класса отличаются между собой атрибутами, которые придают уникальности; -- методы классов позволяют описывать логику взаимодействия, обновлять состояние; -- для объявления класса нужно определить как минимум один метод `__init__`; -- классы без методов можно использовать как удобное хранилище разнородной информации о схожих объектах (описать разных студентов и их оценки). - -Это далеко не все, что можно написать по теме классов и объектов, однако это тот необходимый минимум, что потребуется для ознакомления. Больше примеров и деталей можно найти, например, по ссылкам: - -- [пример с несколькими взаимодействующими объектами](https://younglinux.info/oopython/ooprogramm) -- [что такое наследование и зачем оно нужно](https://younglinux.info/oopython/inheritance) diff --git a/docs/base/syntactic_sugar.md b/docs/base/syntactic_sugar.md deleted file mode 100644 index 827c75dd..00000000 --- a/docs/base/syntactic_sugar.md +++ /dev/null @@ -1,639 +0,0 @@ -# Синтаксический сахар - -!!! info "Автор(ы)" - - - [Kosarevsky Dmitry](https://github.com/dKosarevsky) - -## Введение - -^^Синтаксический сахар^^ — это синтаксис, который позволяет разработчикам писать код проще, «сладким» способом. Следовательно, такой способ даёт роскошь не знать, как работает система под капотом. Синтаксический сахар связан не только с Python, подробнее по [ссылке](https://ru.wikipedia.org/wiki/Синтаксический_сахар). - -Раннее уже были изучены некоторые способы использования синтаксического сахара в Python, такие как: - -- [декораторы](./functions.md#_17) -- [генераторы](./functions.md#_19) -- [контекстные менеджеры](./conditional_comparison.md#_5) -- [f-строки (f-strings)](./variable_types_output.md#_4) -- [списковое включение или генератор списков (list comprehensions)](./list_loop.md#list-comprehensions) - -Важно понимать и другие варианты применения такого функционала изучаемого языка. - -## Магические методы (Magic Methods) - -^^Магические методы^^ (иногда их ещё называют специальными методами) — это методы с предопределенными именами, характеризующимися двойным подчеркиванием в начале и в конце - `__init__` как пример. Они являются «магическими», потому что - -- эти методы вызываются косвенно -- не нужно вызывать напрямую -- все делается за кулисами - -Например, когда создаётся экземпляр класса `x = MyClass()`, Python выполнит необходимые вызовы `__new__` и `__init__`. - -### Пример - -```python linenums="1" -greet = "Hello, Python ODS!" - -print(greet) -``` -```bash -Hello, Python ODS! -``` - -```python linenums="1" -greet.__repr__() -``` -```bash -"'Hello, Python ODS!'" -``` - -Как видно из примера, метод `__repr__()` тесно связан с известной функцией `print()`. Вот еще несколько примеров: - -```python linenums="1" -list_example = ["test", "baz", 8] - -"test" in list_example -len(list_example) -print(list_example) -list_example == [] -list_example[2] -``` -```bash -True -3 -['test', 'baz', 8] -False -8 -``` - -```python linenums="1" -list_example.__contains__("test") -list_example.__len__() -list_example.__repr__() -list_example.__eq__([]) -list_example.__getitem__(2) -``` -```bash -True -3 -"['test', 'baz', 8]" -False -8 -``` - -В этом разделе не будут подробно рассматриваться магические методы, если есть желание узнать больше о них - можно заглянуть в [документацию](https://docs.python.org/3.11/reference/datamodel.html) (как пример для Python версии 3.11). - -??? question "Являются ли магические методы синтаксическим сахаром?" - - Да! - -## Генератор словарей (dict-comprehension) - -```python linenums="1" -d = {n: n+2 for n in range(10)} - -print(d) -``` -```bash -{0: 2, 1: 3, 2: 4, 3: 5, 4: 6, 5: 7, 6: 8, 7: 9, 8: 10, 9: 11} -``` - -## Операторы присваивания - -```python linenums="1" -a += 1 -# эквивалент кода: a = a + 1 -``` - -## Операторы сравнения - -```python linenums="1" -1 < x < 10 -# эквивалент кода: 1 < x and x < 10 -``` - -## Тернарный оператор - -```python linenums="1" -x = something if condition else otherthing -``` - -## Большие числа - -Для удобства чтения большие числа можно записывать с использованием символа нижнего подчёркивания. - -```python linenums="1" -number = 1_000_000_000_000 -number2 = 1000000000000 - -print(number == number2) -``` -```bash -True -``` - -## Многоточие (Ellipsis) - -Python имеет специальный встроенный одноэлементный объект под названием `Ellipsis`. Если вывести три точки или слово `Ellipsis` в интерактивной оболочке Python, результаты будут следующими: - -```python linenums="1" -... -``` -```bash -Ellipsis -``` - -```python linenums="1" -Ellipsis -``` -```bash -Ellipsis -``` - -Этот простой предмет кажется незаметным, но если правильно его использовать, он может облегчить нашу жизнь. Рассмотрим три общих сценария, в которых можно использовать `Ellipsis`. - -### `Ellipsis` — это заполнитель для ненаписанного кода - -При разработке нового модуля обычно определяются некоторые функции или классы, но не реализуются сразу. Потому что хочется только определить, что нужно написать в будущем, и не слишком заботимся о деталях реализации на раннем этапе. В таком сценарии `Ellipsis` — наш лучший друг: - -```python linenums="1" -def create_lecture(): - ... - -class Lecture: - pass -``` - -Можно просто использовать `Ellipsis` в качестве заполнителя для функции или класса использую тождественный `...` `pass`. - -Вообще говоря, хорошей практикой программирования является то, что сначала проектируются необходимые функции или классы, а потом реализуются. Поэтому такой способ может помочь нашему уму ясно видеть всю структуру и не зацикливаться сразу на деталях. - -### Использование `Ellipsis` в `NumPy`, чтобы опустить размеры - -`NumPy` — важная библиотека Python для Data Science. `Ellipsis` полезно при работе с многомерными массивами в `NumPy`. - -Например, если есть трёхмерная матрица и необходимо разделить её, то есть как минимум три способа как сделать это: - -```python linenums="1" -import numpy as np - -A = np.random.rand(2, 3, 2) - -print(A) -``` -```bash -[[[0.992417 0.9530508 ] - [0.56965073 0.30738159] - [0.7711779 0.11873405]] - - [[0.95767839 0.82798645] - [0.31408532 0.22584154] - [0.22445472 0.62915576]]] -``` - -```python linenums="1" -print(A[:, :, 1]) -``` -```bash -[[0.9530508 0.30738159 0.11873405] - [0.82798645 0.22584154 0.62915576]] -``` - -```python linenums="1" -print(A[..., 1]) -``` -```bash -[[0.9530508 0.30738159 0.11873405] - [0.82798645 0.22584154 0.62915576]] -``` - -```python linenums="1" -print(A[Ellipsis, 1]) -``` -```bash -[[0.9530508 0.30738159 0.11873405] - [0.82798645 0.22584154 0.62915576]] -``` - -Использование `Ellipsis` (трёх точек) является наиболее экономичным способом разделения многомерной матрицы. Потому что это требует наименьшего набора текста. Время программистов — деньги, не так ли? - -### Использование `Ellipsis` для подсказки типа - -Подсказки типов были новым функционалом Python версии 3.5. На основе [PEP 484](https://www.python.org/dev/peps/pep-0484/) `Ellipsis` имеет особое значение для этого функционала. - -С одной стороны однородные кортежи произвольной длины могут быть выражены с помощью одного типа и `Ellipsis`, например, `Tuple[int, ...]`. - -С другой стороны можно объявить возвращаемый тип вызываемого объекта без указания сигнатуры вызова, заменив `Ellipsis` (три точки) на список аргументов: - -```python linenums="1" -def partial(func: Callable[..., str], *args) -> Callable[..., str]: - # тело функции -``` - -`Ellipsis` — интересный синтаксический сахар в Python. Его удобно использовать в некоторых сценариях. - -## Морж-оператор (walrus-operator) - -Каждая новая версия Python добавляет в язык новые функции. Для Python 3.8 самым большим изменением было добавление выражений присваивания. В частности, оператор `:=` дает новый синтаксис для присваивания переменных в середине выражений. Такой оператор в просторечии известен как морж-оператор. - -Уже было [упоминали ранее](./conditional_comparison.md#_5) о существовании оператора `:=`, полезно погрузиться в дополнительные возможности такого оператора. - -Поговорим о том, как: - -- определить морж-оператора и понять его значение -- понимать варианты использования морж-оператора -- избегать повторяющегося кода с помощью морж-оператора -- конвертировать код, использующий морж-оператора, в код, использующий другие методы присваивания и наоборот -- понимать влияния на обратную совместимость при использовании морж-оператора -- использовать соответствующий стиль в выражениях присваивания - -!!! note "Замечание" - - Для корректной работы морж-оператора требуется Python 3.8 или более поздней версии. - -### Основы морж-оператора - -![](./_static/walrus.png){ width="250" align=right} - -Оператор `:=` официально известен как оператор выражения присваивания. Во время ранних дискуссий его назвали оператором моржа, потому что синтаксис `:=` напоминает глаза и бивни лежащего на боку моржа. Также иногда можно увидеть, что оператор `:=` называют «оператор двоеточие равно» (colon equals operator). Еще одним термином, используемым для выражений присваивания, являются именованные выражения. - -Чтобы получить первое представление о том, что такое выражения присваивания, можно поэкспериментировать со следующим кодом: - -```python linenums="1" -walrus = False - -print(walrus) -``` -```bash -False -``` - -В примере выше показан традиционный оператор присваивания, в котором переменной `walrus` присваивается значение `False`. - -```python linenums="1" - -print(walrus := True) -``` -```bash -True -``` - -Затем, используется выражение присваивания, чтобы присвоить значение `True` для `walrus`. В обоих случаях можно ссылаться на присвоенные значения, используя имя переменной `walrus`. - -Между двумя типами присваиваний, рассмотренными выше с переменной `walrus`, есть тонкая, но важная разница. Выражение присваивания возвращает значение, а традиционное присваивание — нет. - -В этих примерах можно увидеть еще один важный аспект операторов моржа. Оператор `:=` не делает ничего такого, что было бы невозможно без него. С помощью оператора моржа можно лишь делать определенные конструкции более удобными и иногда можно более четко передать цель кода. - -Общее представление о том, что такое оператор `:=` и что он может делать получено. Это оператор, используемый в выражениях присваивания, который может возвращать присваиваемое значение, в отличие от традиционных операторов присваивания. - -!!! warning "Внимание" - - Один из принципов разработки, лежащий в основе оператора walrus, заключается в том, что не существует идентичных контекстов кода, в которых были бы допустимы как оператор присваивания, использующий оператор `=`, так и выражение присваивания, использующее оператор `:=`. Например, невозможно выполнить простое присваивание с помощью оператора walrus: - - ```python linenums="1" - walrus := True - ``` - ```bash - File "", line 1 - walrus := True - ^ - SyntaxError: invalid syntax - ``` - - В большинстве случаев можно добавить круглые скобки `()` вокруг выражения присваивания, чтобы сделать код валидным: - - ```python linenums="1" - (walrus := True) - ``` - - Однако такая конструкция не имеет большого смысла, т.к. удобнее воспользоваться оператором `=`. При этом запись традиционного оператора присваивания `=` внутри таких скобок не допускается. - -### Варианты использования морж-оператора - -Рассмотрим несколько примеров, где морж-оператора может упростить код. Общая тема всех этих примеров заключается в том, чтобы избегать различных видов повторения: - -- повторные вызовы функций могут сделать код медленнее -- повторяющиеся операторы могут затруднить сопровождение кода -- повторяющиеся вызовы итераторов могут сделать код чрезмерно сложным -- увидим, как морж-оператор может помочь в каждой из этих ситуаций - -#### Отладка - -Возможно, один из лучших вариантов использования морж-оператора — отладка сложных выражений. Допустим, стоит задача найти расстояние между двумя точками на земной поверхности. Один из способов сделать это — использовать [формулу `гаверсинуса`](https://ru.frwiki.wiki/wiki/Formule_de_haversine): - -$$ -d = 2r \arcsin ( \sqrt{ hav(\varphi_2 - \varphi_1) + \cos(\varphi_1) \cos(\varphi_2) hav(\lambda_2 - \lambda_1) } ) -$$ - -$$ -= 2r \arcsin ( \sqrt{ \sin^2(\frac{\varphi_2 - \varphi_1}{2}) + \cos(\varphi_1) \cos(\varphi_2) \sin^2(\frac{\lambda_2 - \lambda_1}{2}) } ) \ , -$$ - -где $\varphi$ представляет широту, а $\lambda$ - долготу каждого местоположения. - -Чтобы продемонстрировать эту формулу, можно рассчитать расстояние между Москвой (55,45° с. ш., 37,36° в. д.) и Ванкувером (51,3° с. ш., 0,7° з. д.) следующим образом: - -```python linenums="1" -from math import asin, cos, radians, sin, sqrt - -rad = 6371 # приблизительный радиус Земли в километрах - -# Расположение Москвы и Лондона -ϕ1, λ1 = radians(55.45), radians(37.36) -ϕ2, λ2 = radians(51.3), radians(-0.7) - -# Расстояние между Москвой и Лондоном -dist = 2 * rad * asin( - sqrt( - sin((ϕ2 - ϕ1) / 2) ** 2 - + cos(ϕ1) * cos(ϕ2) * sin((λ2 - λ1) / 2) ** 2 - ) -) -print(dist) -``` -```bash -2533.3259714914857 -``` - -Как можно увидеть, расстояние от Москвы до Лондона составляет чуть более 2500 километров. - -Теперь предположим, что нужно перепроверить реализацию и посмотреть, насколько члены `гаверсинуса` влияют на конечный результат. Можно скопировать и вставить часть из основного кода, чтобы оценить его отдельно. Однако также можно использовать оператор `:=`, чтобы дать имя интересующему подвыражению: - -```python linenums="1" -dist = 2 * rad * asin( - sqrt( - (ϕ_hav := sin((ϕ2 - ϕ1) / 2) ** 2) - + cos(ϕ1) * cos(ϕ2) * sin((λ2 - λ1) / 2) ** 2 - ) -) -print(ϕ_hav) -``` -```bash -0.0013109950744640937 -``` - -Преимущество использования морж-оператора здесь заключается в том, что одновременно можно вычислять значение итогового значения и отслеживаете значение `ϕ_hav`. Это позволяет подтвердить, что не было допущено никаких ошибок во время отладки. - -#### Списки и словари - -Списки — это мощные структуры данных в Python, которые часто представляют собой ряд связанных атрибутов. Точно так же словари используются во всем Python и отлично подходят для структурирования информации. - -Иногда при настройке таких структур данных приходится выполнять одну и ту же операцию несколько раз. В качестве первого примера вычислим некоторую базовую описательную статистику списка чисел и сохраним их в словаре: - -```python linenums="1" -numbers = [12, 0, 18, 3, 2, 7, 3, 1] - -data_structure = { - "длина": len(numbers), - "сумма": sum(numbers), - "среднее": sum(numbers) / len(numbers), -} - -print(data_structure) -``` -```bash -{'длина': 8, 'сумма': 46, 'среднее': 5.75} -``` - -Важно обратить внимание, что и сумма, и длина списка чисел вычисляются дважды. В этом простом примере последствия не так уж плохи, но если бы список был больше или вычисления были бы более сложными, вероятно захотелось бы оптимизировать такой код. Для этого можно сначала переместить вызовы функций из определения словаря: - -```python linenums="1" -numbers = [12, 0, 18, 3, 2, 7, 3, 1] - -num_length = len(numbers) -num_sum = sum(numbers) - -data_structure = { - "длина": num_length, - "сумма": num_sum, - "среднее": num_sum / num_length, -} - -print(data_structure) -``` -```bash -{'длина': 8, 'сумма': 46, 'среднее': 5.75} -``` - -Переменные `num_length` и `num_sum` используются только для оптимизации вычислений внутри словаря. Используя морж-оператор, эту роль можно сделать более понятной: - -```python linenums="1" -numbers = [12, 0, 18, 3, 2, 7, 3, 1] - -data_structure = { - "длина": (num_length := len(numbers)), - "сумма": (num_sum := sum(numbers)), - "среднее": num_sum / num_length, -} - -print(data_structure) -``` -```bash -{'длина': 8, 'сумма': 46, 'среднее': 5.75} -``` - -`num_length` и `num_sum` теперь определены внутри определения описания. Это явный намёк на то, что эти переменные используются только для оптимизации этих вычислений и больше не используются позже. - -!!! note "Замечание" - - Область видимости переменных `num_length` и `num_sum` одинакова в примере с морж-оператором и в примере без него. Это означает, что в обоих примерах переменные доступны после определения описания. - - Несмотря на то, что оба примера функционально очень похожи, преимущество использования выражений присваивания заключается в том, что оператор `:=` сообщает о назначении этих переменных как одноразовые оптимизации. - -## f-строки (f-strings) - -О f-строках [говорили ранее](./variable_types_output.md#_4), полезно погрузиться в дополнительные возможности этого удобного и в последнее время наиболее часто используемого функционала для форматирования строк. - -В большинстве случаев синтаксис аналогичен старому `%`-форматированию с добавлением `{}` и `:` вместо `%`. Например, `%03.2f` можно перевести как `{:03.2f}`. - -### Спецификаторы формата - -Спецификаторы в f-строках можно использовать таким образом: - -```python linenums="1" -x = 12.3456789 - -print(f"{x:.3f}") -``` -```bash -12.346 -``` - -Спецификаторы формата могут содержать оцениваемые выражения. Это позволяет использовать следующий код: - -```python linenums="1" -width = 12 -precision = 4 -value = 12.3456789 -res = f"result: {value:{width}.{precision}}" - -print(res) -``` -```bash -result: 12.35 -``` - -После оценки выражений в спецификаторе формата (при необходимости) спецификаторы формата не интерпретируются оценщиком f-строки. Как и в str.format(), они просто передаются в метод __format__() форматируемого объекта. - -### Переменные со значениями - -Версия Python 3.8 не обошла стороной и f-строки, дополнив их возможностями по выводу имён переменных вместе со значениями. - -Как это работало до версии 3.8: - -```python linenums="1" -x = 1 -y = 8 - -print(f"x = {x}, y = {y}") -``` -```bash -x = 1, y = 8 -``` - -И как это стало работать начиная с версии Python 3.8: - -```python linenums="1" -x = 1 -y = 8 -z = 12.3456789 - -print(f"{x = }, {y = }") -print(f"{z = :.3f}") -``` -```bash -x = 1, y = 8 -z = 12.346 -``` - -### Мини-язык спецификаций форматирования - -[Format Specification Mini-Language](https://docs.python.org/3/library/string.html#formatspec) Python, поддерживаемый f-строками, позволяет реализовать множество операций форматирования данных. - -#### Заполнение и центрирование текста - -Предположим у нас есть следующая строка - -```python linenums="1" -text = "ODS" - -print(f"{text}") -``` -```bash -ODS -``` - -Если добавить в неё: - -- двоеточие, -- символ-заполнитель, -- указать требуемую длину строки с помощью `<` - -```python linenums="1" -text = "ODS" - -print(f"{text:-<15}") -``` - -То не занятый текстом остаток строки будет заполнен выбранным символом-заполнителем: - -```bash -ODS------------ -``` - -Если указать длину строки через `>`, то можно заполнить строку с левой стороны: - -```python linenums="1" -text = "ODS" - -print(f"{text:->15}") -``` -```bash -------------ODS -``` - -??? question "Как заполнить строку с обеих сторон, чтобы получилось `------ODS------`?" - - ```python linenums="1" - text = "ODS" - - print(f"{text:-^15}") - ``` -#### Замена `%x` и `%o` и преобразование значения в разные базы - -Формат поддерживает двоичные числа - -```python linenums="1" -print(f"int: {42:d}; hex: {42:x}; oct: {42:o}; bin: {42:b}") -``` -```bash -int: 42; hex: 2a; oct: 52; bin: 101010 -``` - -с префиксом `0x`, `0o`, или `0b`: - -```python linenums="1" -print(f"int: {42:d}; hex: {42:#x}; oct: {42:#o}; bin: {42:#b}") -``` -```bash -int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010 -``` - -#### Разделитель групп разрядов - -```python linenums="1" -n = 1234567890 - -print(f"{n:,}") -print(f"{n:_}") -``` -```bash -1,234,567,890 -1_234_567_890 -``` - -#### Выражение процента - -```python linenums="1" -points = 19 -total = 22 - -print(f"{points} от {total} составляет {points/total:.2%}") -``` -```bash -19 от 22 составляет 86.36% -``` - -#### Форматирование даты и времени - -```python linenums="1" -from datetime import datetime - -today = datetime.today() -now = datetime.utcnow() - -print(f"{today:%d.%m.%Y}") # вывод даты в заданном формате -print(f"{today:%Y}") # вывод года из даты -print(f"{now:%T}") # вывод времени -print(f"{now:%x}") # вывод даты -``` -```bash -04.11.2022 -2022 -13:25:45 -11/04/22 -``` - -#### Добавление начальных нулей - -```python linenums="1" -n = 321 - -print(f"{n:08}") -``` -```bash -00000321 -``` - -## Заключение - -Как видно, синтаксический сахар облегчает жизнь программистам, и часто они даже не замечают или даже не знают, что используем его, но в любом случае всегда полезно знать, как он работает в деталях, потому что рано или поздно придётся глубже понять как работает та или иная вещь, чтобы успешно решать сложные задачи. diff --git a/docs/base/tools_install.md b/docs/base/tools_install.md deleted file mode 100644 index 71b174d9..00000000 --- a/docs/base/tools_install.md +++ /dev/null @@ -1,336 +0,0 @@ -# Установка необходимых инструментов и настройка среды - -!!! info "Автор(ы)" - - - [Котенков Игорь](https://github.com/stalkermustang) - - [vvssttkk](https://github.com/vvssttkk) - -## Установка Python - -Быстрее всего (как минимум в символах и сразу для всех платформ) рассказать как установить Python, потребуется - -- [x] зайти на [официальный сайт Python](https://www.python.org/) -- [x] во вкладке «Downloads» выбрать нужную платформу (Linux, macOS, Windows) -- [x] скачать релиз (для начала советуем использовать стабильную версию, к примеру, `3.10.6` на момент когда эта лекция пишется) - -!!! attention "Между тем" - - Python для Linux и macOS предустановлен, но он довольно старый, ещё 2 версия, которая уже как не поддерживается. - -## Установка виртуального окружения [^1] - -При разработке Python-приложений или использовании решений на Python, созданных другими разработчиками, может возникнуть ряд проблем, связанных с использованием библиотек различных версий, к примеру: - -1. различные приложения могут использовать одну и туже библиотеку, но при этом требуемые версии могут отличаться -2. может возникнуть необходимость в том, чтобы запретить вносить изменения в приложение на уровне библиотек, к примеру, установили приложение и хотите, чтобы оно работало независимо от того обновляются библиотеки или нет. Как понимаете, если оно будет использовать библиотеки из глобального хранилища (`/usr/lib/python3/site-packages/`), то, со временем, могут возникнуть проблемы -3. просто может не быть доступа к директории `/usr/lib/python3/site-packages/` - -Для решения данных вопросов используется подход, основанный на построении виртуальных окружений – своего рода песочниц, в рамках которых запускается приложение со своими библиотеками, обновление и изменение которых не затронет другие приложение, использующие те же библиотеки. - -### ПО позволяющее создавать виртуальное окружение - -Программное обеспечение, которое позволяет создавать виртуальные окружения в Python можно разделить на те, что входят в стандартную библиотеку Python и не входят в неё. Сделаем краткий обзор доступных инструментов (хороший пост на эту тем есть на [stackoverflow](https://stackoverflow.com/questions/41573587/what-is-the-difference-between-venv-pyvenv-pyenv-virtualenv-virtualenvwrappe)). - -Начнем с инструментов, которые входят в `PyPI` – Python Package Index – репозиторий пакетов Python, доступный для любого разработчика и пользователя Python. - -`virtualenv` - -: Это, наверное, одни из самых популярных инструментов, позволяющих создавать виртуальные окружения. Он прост в установке и использовании. В сети довольно много руководств по virtualenv. Этот инструмент нужно обязательно освоить, как минимум, потому что описание развертывания и использования многих систем, созданных с использованием Python, включает в себя процесс создания виртуального окружения с помощью virtualenv. - -`pyenv` - -: Инструмент для изоляции версий Python. Чаще всего применяется, когда на одной машине вам нужно иметь несколько версий интерпретатора. - -`virtualenvwrapper` - -: Это обертка для `virtualenv` позволяющая хранить все изолированные окружения в одном месте, создавать их, копировать и удалять. Предоставляет удобный способ переключения между окружениями и возможность расширять функционал за счет плагинов. Существуют ещё инструменты и плагины, выполняющие работу по изоляции частей системы Python. - -`venv` - -: Этот модуль появился в Python3 и не может быть использован для решения задачи изоляции в Python2. По своему функционалу очень похож на `virtualenv`. Если вы работаете с третьим Python, то можете смело использовать данный инструмент. - -`poetry`, `pipenv`, `pipx` .. - -: И это ещё не все, которые также отвечают за виртуальное окружение, с которыми предлагаем ознакомится самим. - -### `virtualenv` как пример - -#### Установка - -`virtualenv` можно установить с использованием менеджера `pip`, либо скачать исходные коды проекта и установить приложение вручную. - -Установка с помощью `pip` через командную строку - -```bash -pip install virtualenv -``` - -#### Создание виртуального окружения - -Происходит следующей командой - -```bash -virtualenv -p python3.10 env_py310 -``` - -- `-p python3.10` – с помощью флага `-p` указываем версию Python окружения (3.10) -- `env_py310` – имя окружения - -!!! info "Другие флаги" - - Для просмотра доступных флагов нужно к команде добавить `--help`; для `virtualenv` это - - ```bash - virtualenv --help - ``` - -После выполнения данной команды, в текущей директории будет создана новая директория с именем `env_py310`, где - -- [x] `env_py310/bin/` – содержит скрипты для активации/деактивации окружения, интерпретатор Python, используемый в рамках данного окружения, менеджер `pip` и ещё несколько инструментов, обеспечивающих работу с пакетами Python. В Windows, это директория `env_py310\Scripts\` -- [x] `env_py310/include/` и `env_py310/lib/` – директории, содержащие библиотечные файлы окружения. Новые пакеты будут установлены в директорию `env_py310/lib/python3.10/site-packages/` - -#### Активация виртуального окружения - -Для активации виртуального окружения воспользуйтесь командой (для Linux и macOS): - -=== "общий" - - ``` - source env_py310/bin/activate - ``` - -=== "простой" - - ``` - . env_py310/bin/activate - ``` - -=== "для windows" - - ``` - env_py310\Scripts\activate.bat - ``` - -!!! info "Что делает `source`" - - Команда `source` выполняет `bash`-скрипт без запуска второго `bash`-процесса. - -Если команда выполнилась успешно, то перед приглашением в командной строке появилась дополнительная надпись, совпадающая с именем виртуального окружения. - -``` -(env_py310) user@name_machine$ -``` - -При этом в переменную окружения `PATH`, в самое начало, будет добавлен путь до директории `bin`, созданного `env_py310/` (символом `/` обозначают что это директория). - -!!! info "`--system-site-packages`" - - При создании виртуального окружения с флагом - - ```bash - virtualenv --system-site-packages env_py310 - ``` - - то в рамках окружения `env_py310` будете иметь доступ к глобальному хранилищу пакетов: - - - `/usr/lib/python3.10/site-packages/` (Linux, macOS) - - `\Python3.10\Lib\site-packages\` (Windows) - -#### Деактивация виртуального окружения - -Для выхода из виртуального окружения, введите команду - -=== "Linux, macOS" - - ``` - deactivate - ``` - -=== "для windows" - - ``` - deactivate.bat - ``` - -## Установка Jupyter - -Для установки классического Jupyter Notebook выполнить - - -```bash -pip install notebook -``` - -Для запуска - -```bash -jupyter notebook -``` - -
- ![](./_static/jupyter_console.png) -
- Примерно так будет выглядеть терминал со ссылками -
-
- -Перейдите по одной из ссылок (если не перекинула само), в которых есть слово `token` – они начинаются с `http://localhost` или `http://127.0.0.1`. В браузере откроется страница с обзором директории, из которой был запущен `Jupyter Notebook`. Если в дальнейшем хотите хранить все свои результаты в другом месте, то перед запуском команды с помощью уже указанной инструкции в терминале `cd <путь/до/директории>` перейдите к ней. - -Для создания нового файла – блокнота, как его еще называют («почему?», – узнаете в следующей лекции) – кликните по кнопке `New` в правом верхнем углу, а затем – по `Python 3` (возможно будет какая-нить приставка, это штатно). - -
- ![](./_static/jupyter_create.png) -
- Таким образом можно создать новый файл с кодом -
-
- -Для завершения проверки скопируйте код ниже в тетрадку в браузере, а затем нажмите ++ctrl+enter++ (++command+return++ для macOS) (это заставит код выполниться, подробнее дальше в курсе). Если увидите график - то все в полном порядке! - -```python linenums="1" -import numpy as np -import matplotlib.pyplot as plt -%matplotlib inline - -# Fixing random state for reproducibility -np.random.seed(19680801) - -# Compute pie slices -N = 20 -θ = np.linspace(0.0, 2 * np.pi, N, endpoint=False) -radii = 10 * np.random.rand(N) -width = np.pi / 4 * np.random.rand(N) -colors = plt.cm.viridis(radii / 10.) - -ax = plt.subplot(111, projection="polar") -ax.bar(θ, radii, width=width, bottom=0.0, color=colors, alpha=0.5) - -plt.show() -``` -![](./_static/jupyter_test_code_run.png) - -Не переживайте, этот код не нужно разбирать сейчас – просто убеждаемся, что все работает согласно задумке. Если что-то не так, пересмотрите все ли сделали согласно инструкции; если да и не воспроизводится, то задавайте вопрос в [канале курса](https://opendatascience.slack.com/archives/CEH3VJCRJ) - -### jupyterlab - -Модернизированная версия Jupyter Notebook смахивающая в какой-то мере на полноценную среду разработки (с тёмной темой), где одновременно можно работать с несколькими файлами, а не в отдельных вкладках как в классическом. - -Для установки - -```bash -pip install jupyterlab -``` - -Запустить - -```bash -jupyter-lab -``` - -Горячо рекомендуем использовать его, ну или привыкать работать с IDE JetBrains PyCharm, VSCode и т.д. - -### colab - -[Collaboratory](https://colab.research.google.com) или Colab от Google Research – размещенный Jupyter – который используется для написания и запуска преимущественно Python из браузера, то есть вычисления происходят целиком и полностью в облаке, требуется лишь наличие стабильного интернета. Также имеются бесплатные GPU и TPU, но c ограничениями как и сами аппаратные ресурсы: не сможете создавать проекты, требующие большого объема вычислений. Также можно делиться созданными блокнотами (Jupyter Notebooks) по необходимости. - -Более детально советуем ознакомиться с [Google Colab – Краткое руководство](https://isolution.pro/ru/t/google-colab/google-colab-quick-guide/google-colab-kratkoe-rukovodstvo). - -## Установка git - -[`Git`](https://github.com/git-guides) – система контроля версий. Этот инструмент часто используется для совместной разработки программ (и не только!) группой людей, каждый из которых работает над своей отдельной проблемой. Так, например, этот курс был создан с помощью `git`, и каждый автор работал с отдельной копией, создавая набор лекций. А затем все копии собрались в одну книгу, которую читаете. Пара учебных материалов по работе с git: - -- [погружение в git](https://gitimmersion.com/) -- [наиболее часто используемые советы и рекомендации по git](https://github.com/git-tips/tips) -- [git-scm](https://git-scm.com/docs/gittutorial) - -### Инструкция для Linux - -#### Fedora - -Или другой похожий дистрибутив, такой как RHEL или CentOS, можно воспользоваться dnf: - -```bash -sudo dnf install git-all -``` - -#### Debian - -Например, Ubuntu, попробуйте apt: - -```bash -sudo apt install git -``` - -Чтобы воспользоваться дополнительными возможностями, посмотрите инструкцию по установке для нескольких различных разновидностей Unix на сайте [git-scm.com/download/linux](https://git-scm.com/download/linux). - -### Инструкция для macOS - -#### Xcode CLI - -Самый простой способ – установить Xcode Command Line Tools. Нужно выполнить - -```bash -git --version -``` - -и если git не установлен, будет предложено это произвести. - -#### brew - -Тут необходимо установить менеджер пакетов - `brew`. [По ссылке](https://brew.sh/index_ru) найдете инструкцию и более детальное описание, чем он является. Необходимо выполнить в терминале команду: - -```bash -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -``` - -!!! attention "Внимание" - - Скорее всего, для выполнения этой команды, нужно задействовать команду `sudo`, это вполне нормальная история. - -Для установки самого git выполнить - -```bash -brew install git -``` - -### Инструкция для Windows - -#### Официальная сборка - -Официальная сборка доступна на [сайте git](https://git-scm.com/download/win) – отдельный проект, называемый git для Windows. Для дополнительной информации перейдите на [gitforwindows.org](https://gitforwindows.org/) - -#### chocolatey - -Для автоматической установки можете использовать [пакет git chocolatey](https://community.chocolatey.org/packages/git) (учтите, он поддерживается сообществом). - -### Проверка установки - -Выполните - -```bash -git --version -``` - -К примеру, если получите что-то вида `git version 2.36.2` -- всё прошло успешно. - -### Копирование репозитория курса - -Для примера, дабы скопировать репозиторий этой книги, нужно зайти на его страницу в [GitHub](https://github.com/) (имеются и другие подобные системы) курса. - -[Перейти в репозиторий курса](https://github.com/open-data-science/pycourse){ .md-button .md-button--primary } - -Затем найдите кнопку с текстом `< > Code` и кликните по ней. В открывшемся окне убедитесь, что выбрана вкладка `HTTPS`, а не `SSH` или `GitHub CLI`. Скопируйте предложенную ссылку (это такое же, если скопировать ссылку вкладки браузера). После зайдите в терминал в нужную директорию и выполните - -``` bash -git clone https://github.com/open-data-science/pycourse.git -``` - -После чего появится директория `pycourse/`. Это можно увидеть через команду `ls` (только для Linux и macOS). - -Для того, чтобы зайти в директорию, потребуется выполнить команду (change directory, сменить директорию) - -```bash -cd pycourse/ -``` - -[^1]: «Виртуальные окружения. Подробная инструкция на Python.», серия «Python.Уроки» от UPROGER. [https://uproger.com/virtualnye-okruzheniya-podrobnaya-instrukcziya-na-python/](https://uproger.com/virtualnye-okruzheniya-podrobnaya-instrukcziya-na-python/) diff --git a/docs/base/variable_types_output.md b/docs/base/variable_types_output.md deleted file mode 100644 index 89159de3..00000000 --- a/docs/base/variable_types_output.md +++ /dev/null @@ -1,299 +0,0 @@ -# Переменные и вывод информации - -!!! info "Автор(ы)" - - - [Котенков Игорь](https://github.com/stalkermustang) - -## Суть переменных в `Python` - -Настало время приступить к изучению непосредственно Python, ведь по прошествии пары лекций об языке программирования и не говорили вовсе! Начнем со [знакомой всем по школьным карандашам формулы](https://ru.wikipedia.org/wiki/Эквивалентность_массы_и_энергии) $E=mc^2$. По ней можно вычислить полную энергию физического объекта $E$ с помощью известной массы объекта $m$ и константы $c$. Эта постоянная, указывающая на скорость света в вакууме, используется настолько часто, что для нее выделили отдельное обозначение в виде буквы латинского алфавита, как и для многих других аналогичных величин. Если в формуле встречается $c$ (в известном контексте), то вы всегда уверены, что именно нужно подставить при расчетах. - -Этот пример полностью описывает концепцию ^^переменных^^ в языках программирования, и Python не исключение. Запись $x = 3$ означает, что везде по тексту далее под иксом подразумевается именно тройка, и ничего другого (пока не будет введено новое определение). Этой же логике подчиняется Python. Сначала указывается имя переменной, а затем – ассоциируемое с ней значение. - -```python linenums="1" -c = 299_792_458 # запишем константу, м/с -m = 0.5 # масса некоторого абстрактного объекта, кг -E = m * (c ** 2) # вычисляем энергию, Дж - -some_variable_1 = 10.2 # какая-то другая переменная -m = 12 -``` - -Пример кода выше иллюстрирует сразу несколько базовых концепций, которые нужно запомнить: - -1. В объявлении переменной нет ничего сложного. Синтаксис и правила интуитивно понятны: это можно делать как в физике/математике, как в учебниках и статьях. -2. `#` означает комментарий, то есть произвольный текст, который не воспринимается Python (все ^^до конца строки^^ кода полностью игнорируется). Служит исключительно для создания подсказок в коде, объяснения происходящего, то есть для удобства. -3. Числа могут быть ^^целыми и вещественными^^. Разряды в целых числах для удобства визуального восприятия можно разделять нижней чертой. -4. ^^Значение переменной может быть вычислимым^^, то есть являться производной от других переменных (как $E$, ведь это результат перемножения). На самом деле значение вычисляется в момент объявления переменной (при сложной формуле расчета процесс может занимать некоторое время). -5. Операция возведения в степень реализуется с помощью `**`. -6. В качестве названия переменных можно использовать ^^буквы^^ и ^^цифры^^, а также некоторые символы. Однако ^^имя переменной не может начинаться с цифры^^. -7. Переменные можно переопределять (и даже менять тип). Однако ^^старое значение в этом случае будет безвозвратно утрачено^^. В данном примере после выполнения последней строчки нельзя установить, чему было равно $m$ до того, как переменной было присвоено значение дюжины. - -Если говорить менее строго и более абстрактно, то ^^переменная – это контейнер^^ (или коробка), в котором что-то лежит, и на самой коробке на приклеенном листочке бумаги указано содержимое. Чем понятнее надпись, тем легче найти и использовать объект (поэтому переменные с названием из одной буквы воспринимаются плохо, особенно если таких переменных очень много). - -
- ![](./_static/box_with_a_name.png) -
- [Объявить переменную -- значит положить объект в коробку с подписью](https://stevenpcurtis.medium.com/what-is-a-variable-3447ac1331b9) -
-
- -## Типы переменных - -В листинге кода выше важно заметить, что существует разница между двумя типами численных переменных: ^^целые^^ и ^^вещественные^^. При сугубо математических расчетах и арифметических операциях тип переменной не имеет значения. Однако для некоторого функционала нужно быть аккуратным. Поговорим подробно об этом в следующих лекциях, а пока стоит запомнить, что вещи, которые необходимо посчитать – в том числе и ^^длину^^ чего-то _счетного_ – должны быть целочисленными (как и в жизни: первый, второй, третий ...). - -!!! warning "Внимание" - - Целочисленный тип называется ^^int^^ (от `Integer`), вещественный – ^^float^^. Эти типы можно переводить из одного в другой. При переводе вещественного числа в целое теряется часть информации. - -^^Тип переменной^^ – и это относится не только к числам, но и к ^^любому^^ объекту – можно узнать с помощью функции `type`. Для вывода информации используется функция `print`. Что именно представляет собой функция рассмотрим в более поздних лекциях, пока стоит думать об этом как о некотором объекте, который зависит (рассчитывается) от других объектов и выдает некоторый результат. Для передачи аргументов используются круглые скобки (аналогично математике: $y = F(x)$). Давайте скомбинируем эти знания и рассмотрим пример: - -```python linenums="1" -first_variable = 10 -second_variable = 10.0 - -# запишем в переменные значения типов данных -type_of_first_variable = type(first_variable) -type_of_second_variable = type(second_variable) - -# и распечатаем сами типы, чтобы посмотреть глазами и сравнить -print(type_of_first_variable) -print(type_of_second_variable) - -# перезапишем переменные -first_variable = 12.9 -second_variable = int(first_variable) -third_variable = float(second_variable) - -# в print() можно передавать несколько переменных -print(first_variable, second_variable, third_variable) -``` -```bash - - -12.9 12 12.0 -``` - -!!! example "Упражнение" - - Внимательно проанализируйте код выше – в нем продемонстрирован базовый синтаксис ^^преобразования типов^^ и ^^вывода информации^^. - -Легко увидеть подтверждение высказанных ранее тезисов: `second_variable` действительно потеряла часть информации (дробную часть числа), которую нельзя вернуть, если преобразовать переменную обратно во `float`. Преобразование типов в языках программирования называется ^^приведением^^ (типов, то есть привести одно к другому, а не из-за страшилок про духов). - -## Арифметические операции с числами - -Математика `Python` максимально близка к естественной: `+`, `-`, `*` и `**` (рассмотренное ранее возведение в степень) работают в точности как ожидается. С делением `/` есть нюанс: ^^возвращаемое значение всегда вещественное^^. - -```python linenums="1" -a = 3 -b = 12.1 - -c = a + b - -# можно объединять вызовы функций print и type -# без создания лишней переменной -print(type(c)) - -# и даже трех функций, включая приведение типа -print(type(int(c))) - -# деление числа на само себя дает единицу, но.. -print(a / a) -print(b / b) -print(c / c) -print(12 / 4) -``` -```bash - - -1.0 -1.0 -1.0 -3.0 -``` - -!!! note "Замечание" - - Обратите внимание, что операции не изменяют переменную саму по себе (то есть операция `a + b` не меняет ни `a`, ни `b`). Чтобы сохранить получаемое значение, нужно присвоить его некоторой переменной (в примере выше это `c`). Если хотите изменить непосредственно саму переменную, то можно переприсвоить ей значение на основе расчета: `a = a + b` или `c = c + 12`. - -Даже несмотря на то, что пример с делением числа на само себя очевиден (всегда получается единица, кроме деления на нуль), будет выведено вещественное значение. Сами же вещественные значения можно складывать, вычитать, умножать и возводить в степень как с целыми, так и с вещественными числами (и наоборот). Если в таком выражении используется хотя бы одна `float`-переменная, то и результат будет не целочисленным. Однако: - -```python linenums="1" -a = 3 -b = 2 - -print(a + b, type(a + b)) -print(a * b, type(a * b)) -print(a ** b, type(a ** b)) -``` -```bash -5 -6 -9 -``` - -Это _практически_ все тонкости, которые необходимо знать, чтобы не совершать базовые ошибки. - -!!! note "Примечание" - - Скорее всего, появился вопрос относительно расстановки пробелов в коде. Обязательно ли соблюдать такой синтаксис? Нужно ли ставить пробелы до и после знаков операций? На самом деле нет: это делается исключительно для удобства чтения кода и ^^настоятельно рекомендуется не удаляться от стандартов языка^^. Код ниже выполнится без ошибок, однако ухудшается читаемость: - - ```python linenums="1" - a= 3 - b =2 - - print(a +b, type(a+ b)) - print(a * b, type(a *b)) - print(a**b, type(a ** b)) - ``` - ```bash - 5 - 6 - 9 - ``` - -## Строковые переменные - -Разобрались в том, как описывать и хранить числа, как производить арифметические расчеты. Базовый математический язык освоен, но хочется общаться словами! Конечно, `Python` позволяет это делать. Благодаря ^^строковым переменным^^ можно хранить и соединять текстовую информацию: - -```python linenums="1" -text_variable = 'тут что-то написано' -another_text_variable = "Вася, впиши сюда что-нибудь перед публикацией курса!" - -long_text = -''' -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut -labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris -nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit -esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt -in culpa qui officia deserunt mollit anim id est laborum. -''' - -print(another_text_variable) -``` -```bash -Вася, впиши сюда что-нибудь перед публикацией курса! -``` - -В примере рассмотрено три способа создания текстовых переменных. Первые два не отличаются между собой с точки зрения `Python`, то есть неважно, используются одинарные кавычки `'` или двойные `"`. Однако стоит понимать, что если строка содержит в себе такой символ, то кавычка должна быть изменена: - -```python linenums="1" -error_string = 'Chillin' kid' -another_error_string = "И тут он мне говорит: "у тебя нет ног!"" - -print(error_string) -print(another_error_string) -``` -```bash - File "", line 1 - error_string = 'Chillin' kid' - ^ -SyntaxError: invalid syntax -``` - -Механизм ошибки таков, что `Python` неясно: строчка намеренно закончена и дальше идет какая-то команда, или же строчка продолжается. В обоих случаях ^^нужно сменить способ создания строки^^ – и тогда все будет хорошо: - -```python linenums="1" -error_string = "Chillin' kid" -another_error_string = 'И тут он мне говорит: "у тебя нет ног!"' - -print(error_string) -print(another_error_string) -``` -```bash -Chillin' kid -И тут он мне говорит: "у тебя нет ног!" -``` - -Если необходимо сохранить какой-либо объемный текст или сообщение, можно воспользоваться мультистрочным объявлением переменной, как в первом примере блока. - -Строки можно объединять для удобства вывода информации. Склеивание строк называется ^^конкатенацией^^. - -```python linenums="1" -first_string = 'Результат вычислений: ' -second_string = ". Это не так много!" - -a = 12 -b = 2 -result = a * b - -# два способа вывода: -print(first_string, result, second_string) - -# либо через склейку строк вручную -# обратите внимание на приведение типа int к str -result_string = first_string + str(result) + second_string -print(result_string) -``` -```bash -Результат вычислений: 24 . Это не так много! -Результат вычислений: 24. Это не так много! # (1) -``` - -1. Обратите внимание на пробел между числом и точкой в первом случае. Они добавлены автоматически функцией `print` – это сделано для того, чтобы разные объекты при последовательном выводе не «склеивались» друг с другом. Во втором случае этого не происходит, так как напрямую склеиваются строки и только затем передается результат конкатенации на печать в `print`. - -!!! warning "Внимание" - - Будьте аккуратны со сложением строк. Объединение строк `"3"` и `"5"` даст результат `"35"`, а не `8` – и тип результирующего значения ^^будет строковый^^. ^^Сложить строку и число нельзя^^: получите ошибку и никакого приведения типов не произойдет. Здесь возникнет двусмысленность – нужно привести число к строке и затем сконкатенировать или же строку к числу (а вдруг это невозможно?), после чего сложить. - - -!!! example "Упражнение" - - Попробуйте в объединить строковые, целочисленные и вещественные переменные в разных комбинациях. Разберитесь, что означает ошибка, которая будет выведена в случае, если не делать приведение типов (то есть без `str` в `str(result)`). - -Но на практике это не совсем удобно, поэтому в `Python` придумали `f`-строки. Их суть в том, что переменная из кода напрямую подставляется (с автоматическим приведением типа к строке) в саму строку! Вот: - -```python linenums="1" -a = 12 -b = 2 -result = a * b - -result_string = f"Результат вычислений: {result}. Это не так много!" - -# и без f -wrong_result_string = "Результат вычислений: {result}. Это не так много!" - -print(result_string) -print(wrong_result_string) -``` -```bash -Результат вычислений: 24. Это не так много! -Результат вычислений: {result}. Это не так много! -``` - -Для объявления `f`-строки нужно - -- [x] использовать одинаковые кавычки на концах текста -- [x] указать литеру `f` перед самой строкой -- [x] обрамить название конкретной переменной (`result` в данном случае) в фигурные скобки. - -Когда переменная одна, а также нет текста после её использования, то выгода `F`-строк не так очевидна (относительно простого `print(some_string, some_variable)`). Однако представьте, что нужно вывести координаты точки в трехмерном пространстве, значение времени, параметры системы и значение некоторой функции от всех переменных выше! - -```python linenums="1" -# так тоже можно! -x, y, z = 12.1, 0, 13 -# скобки, как и в математике, задают порядок выполнения вычислений -func_val = (x * y) ** z - -current_time = 30.113412 - -# а вот так можно писать длинные f-строки (но работает и для обычных) -out_string = (f"В точке с координатами X={x}, Y={y}, Z={z} значение функции " - f"равно {func_val}. Состояние системы указано на момент " - "времени t=" + str(current_time)) - -print(out_string) -``` -```bash -В точке с координатами X=12.1, Y=0, Z=13 значение функции равно 0.0. Состояние системы указано на момент времени t=30.113412 -``` - -## Что узнали из лекции - -- Переменные – это «контейнеры», в которые можно что-то положить и дать название. -- Математика в `Python` не имеет сложных правил, процесс вычислений максимально интуитивен. -- Арифметические операции могут менять тип результирующей переменной. -- `type()`, `print()` – базовые функции, с помощью которых можно делать самопроверки по ходу написания кода. -- Сменить тип переменной можно вызовом функций `int()`, `float()`, `str()`. -- Строки могут обрамляться как `'`, так и `"` (но этих символов не должно быть внутри текста). -- `f`-строки облегчают комплексный вывод, содержащий как текст, так и переменные `Python` (и автоматически приводит типы). diff --git a/docs/community.md b/docs/community.md deleted file mode 100644 index 135c007b..00000000 --- a/docs/community.md +++ /dev/null @@ -1,18 +0,0 @@ -# сообщество - -* [ods.ai](https://ods.ai/) - - сайт со всеми программами, курсами, соревнованиями, конференциями, событиям, хабами, проектами и т.п. + самом сообществе - -* присоединиться к площадке общения [ods в [matrix]](https://ods.ai/tracks/odsmatrix101) -* [хабр](https://habr.com/ru/company/ods/blog/) -* telegram (основные) - * [opendatascience ru](https://t.me/ods_ru) - * [data fest](https://t.me/datafest) - * [data science by ods.ai](https://t.me/opendatascience) - * [ods lab](https://t.me/odslab) - * [ods pet projects](https://t.me/ods_pet_projects) - * [reliable ml](https://t.me/reliable_ml) - * [mlpps и data engineering](https://t.me/MLopsProduction) - * [code mining](https://t.me/codemining) -* [twitter](https://twitter.com/ods_ai) diff --git a/docs/index.md b/docs/index.md index a9536fa4..7f34839f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,205 +1,3 @@ # главная -[Python](https://www.python.org/) есть такой язык программирования, который позволяет сообщить компьютеру о том, что нужно сделать, дабы достичь некоего результата. За последнее десятилетие он получил быстрое распространение и сейчас является одним из самых популярных языков программирования в мире. Входной порог для его использования достаточно низок: можно использовать Python для решения своих задач даже если никогда не имели дела с программированием. - -!!! danger "зачем?" - - В этом чудесном месте планируется затронуть основные моменты Python (с упором на машинное обучение): база, как работать с основными библиотеками, что есть правильный код, асинхронность, тесты и т.д. и т.п. Кто-то без умолку уронит замечание, дескать, этого всего сполна, но тут упор делаем на примеры в той самой промышленности. Будем рады любой помощи в составлении материалов, практики и иного доброго словца – [contributing.md](https://github.com/open-data-science/pycourse/blob/master/contributing.md). - - Проект находится в стадии разработки «основы python». Подискутировать о курсе можно [тут](https://github.com/open-data-science/pycourse/discussions). - - [Посмотреть прогресс курса](https://github.com/orgs/open-data-science/projects/1/views/1){ .md-button .md-button--primary } - -## Что такое Python? - -Python – это язык программирования ^^общего назначения^^, используемый для различных задач, например: - -- [x] анализ данных ([Pandas](https://pandas.pydata.org/)) -- [x] построение визуализаций на основе данных ([Matplotlib](https://matplotlib.org/), [seaborn](https://seaborn.pydata.org/), [Plotly](https://plotly.com/python/)) -- [x] научные и математические вычисления ([SciPy](https://scipy.org/), [NumPy](https://numpy.org/), [SymPy](https://www.sympy.org/)) -- [x] квантовое вычисление ([Cirq](https://github.com/quantumlib/cirq), [Qiskit](https://github.com/Qiskit/qiskit), [PennyLane](https://github.com/PennyLaneAI/pennylane)) -- [x] статистические исследования ([statsmodels](https://www.statsmodels.org/)) -- [x] машинное обучение ([scikit-learn](https://scikit-learn.org/)) -- [x] продвинутая аналитика данных, в том числе с использованием нейронных сетей ([PyTorch](https://pytorch.org/), [TensorFlow](https://www.tensorflow.org/)) -- [x] компьютерная графика ([blender](https://www.blender.org/)) -- [x] геофизика ([pyGIMLi](https://www.pygimli.org/), [SimPEG](https://simpeg.xyz/)) -- [x] химия ([awesome-python-chemistry](https://github.com/lmmentel/awesome-python-chemistry)) -- [x] теория графов ([NetworkX](https://networkx.org/)) -- [x] медицина ([PyQtGraph](https://www.pyqtgraph.org/)) -- [x] психология ([PsychoPy](https://www.psychopy.org/)) -- [x] разработка веб-приложений ([Django](https://www.djangoproject.com/), [Flask](https://flask.palletsprojects.com/)) -- [x] разработка мобильных приложений ([Kivy](https://kivy.org/)) -- [x] работа с текстовыми файлами, изображениями, аудио и видео файлами ([PyMedia](http://pymedia.org/)) -- [x] создание игр ([Pygame](https://www.pygame.org/)) -- [x] реализация графических интерфейсов ([PyQT](https://riverbankcomputing.com/software/pyqt/), [PyGObject](https://pygobject.readthedocs.io/)) -- [x] и т.д. и т.п. - -
- ![](./assets/blackhole.png) -
- [Рассчитанная в Python симуляция преломлений света черной дырой](https://github.com/Python-simulation/Black-hole-simulation-using-python) -
-
- -## Чем примечателен Python? - -В основе разностороннего применения и популярности лежит ^^простота изучения^^: всё чаще люди начинают свой путь в программировании с Python, поскольку он очень ^^дружелюбен к новичкам^^ и позволяет максимально быстро перейти к решению целевой задачи. - -Сюда же можно отнести ^^многообразие библиотек^^ (или _расширений функциональности_, то есть кода, написанного другими людьми, который можно переиспользовать). Хотите изучить физику небесных тел и симулировать их взаимодействия? Можно найти и скачать библиотеку, позволяющую за один вечер провести вычисления, о которых в прошлом веке можно было лишь мечтать. Хотите создать прототип мобильного приложения? И на этот случай есть библиотека. Вам нравится квантовая физика и хотите использовать её вместе с умными компьютерными алгоритмами? Что ж, тогда снова по адресу. - -
- ![](./assets/aero_python.png) -
- [Пример моделирования аэродинамики в Python с помощью библиотеки AeroPython](https://lorenabarba.com/blog/announcing-aeropython/) -
-
- -Python – это ^^высокоуровневый язык для быстрой разработки и/или прототипирования^^, на нем очень удобно проверять гипотезы и идеи. «_Высокоуровневый_» означает, что не нужно вникать в устройство компьютера и тонкости взаимодействия с ним, чтобы перейти к задаче. Многое «сделано за нас»: работаем с простыми _абстракциями_ (или удобными представлениями), а не боремся с компьютером из-за непонимания сложностей его устройства. - -Еще один плюс в копилку популярности языка – это ^^элегантность и краткость синтаксиса^^ (принципов написания кода, как будто это абзацы в тексте или колонки в газете). Вместе с вышеупомянутым обилием библиотек можно буквально за 5 минут и 10 строк кода – а это меньше половины листа А4 – воспроизвести научную статью, в которую вложено несколько человеко-лет. А еще такой синтаксис делает ^^код легким для чтения, запоминания и понимания^^. - -Стоит отметить, что Python – это ^^интерпретируемый^^ язык, а значит, компьютер каждый раз перед выполнением программы читает код строчку за строчкой и определяет (интерпретирует), что нужно сделать дальше, не проводя никаких оптимизаций и предварительных расчетов. Это негативно влияет на общую скорость работы: Python является ^^одним из самых медленных языков^^. Тем не менее он отлично подходит для академических целей, например, исследовательской работы или других задач, где скорость работы не является критически важной. Настоящая сила Python заключается в том, что это ^^«язык-клей»^^: он обеспечивает удобный доступ к различным библиотекам, написанным на высокоэффективных языках, например, на C/C++, Fortran, CUDA C и других. - -## И в чем подвох? - -В простоте языка и его доступности для быстрого старта таится одна из проблем: _можно не понимать, что происходит внутри_, поэтому иногда бывает сложно разобраться в причинах ошибок и неточностей, возникающих по ходу работы над задачей. В целом к Python применим следующий принцип: «легко научиться, трудно овладеть». Возвращаясь к примеру элегантности кода, когда 10 строк кода выполняют всю работу: важно понимать, что за ними стоят еще _сотни_ или даже _тысячи строк кода_, а это может приводить к ситуациям, когда поиск ошибки в минимальном наборе команд растягивается на несколько дней. - -## Опросы Stack Overflow - -Ежегодные [опросы Stack Overflow в мае 2022](https://survey.stackoverflow.co/2022/) года определили, что JavaScript десятый год подряд становится наиболее часто используемым языком программирования. (65,36%, в предыдущем году - 64,9%, большинство участников Stack Overflow web-разработчики). - -![](./assets/why_py_stackoverflow_1.png) - -Но для тех, кто учится программировать, картина другая. HTML/CSS, Javascript и Python почти связаны как самые популярные языки для людей, изучающих программирование. Люди, изучающие программирование, чаще, чем профессиональные разработчики, сообщают об использовании Python (58% против 44%), C++ (35% против 20%) и C (32% против 17%). - -![](./assets/why_py_stackoverflow_2.png) - -Пять лет подряд Python определялся участниками опросов как наиболее востребованная технология, однако в 2022 Rust незначительно опередил Python: - -![](./assets/why_py_stackoverflow_3.png) - -## Рейтинг языков программирования - -
- ![](./assets/why_py_tiobe_rating.png) -
- Рейтинг популярности языков программирования по данным индекса TIOBE на октябрь 2022 года. -
-
- -Рейтинг [TIOBE](https://www.tiobe.com/tiobe-index/) составляется из всех актуальных языков программирования (около 100). Как видно из рейтинга, Python возглавляет рейтинг. Такой успех можно объяснить возможностью выполнения широкого спектра задач и удобством языка. Удобство заключается в том, что Python - высокоуровневый язык. Это означает, что сложные описания структур машинного кода выполнены в удобно читаемом для человека виде. Стоит отметить, что при изучении языка необходимо уделять больше времени пониманию того, как работают стандартные функции, поскольку это позволит быстрее прокачивать свой навык программирования. - -## Минусы Python - -Python — отличный выбор для практически любого проекта. Но если он выбран, важно понимать и о последствиях такого выбора. -Ограничения Python по сравнению с другими языками: - -- ^^ограничения скорости^^ - поскольку Python интерпретируется, это часто приводит к медленному выполнению, однако, это не проблема, если скорость не является ключевым фактором для жизнедеятельности проекта -- ^^слаб в мобильных вычислениях и браузерах^^ - хотя Python служит отличным серверным языком, он редко встречается на стороне клиента -- ^^ограничения дизайна^^ - Python имеет динамическую типизацию. Это означает, что не нужно объявлять тип переменной при написании кода. Хотя это очень удобно для разработчиков при написании кода, но это может привести к ошибкам при исполнении и чтении кода -- ^^недостаточно развитые уровни доступа к базе данных^^ - по сравнению с более широко используемыми технологиями, такими как JDBC (Java DataBase Connectivity) и ODBC (Open DataBase Connectivity), уровни доступа к базе данных Python немного недоработаны; следовательно, он реже применяется на крупных предприятиях - -Несмотря на некоторые проблемы со скоростью, безопасностью и временем выполнения, Python — ^^отличный язык для изучения^^. - -Его популярность говорит сама за себя и это объясняется тем, что он простой, интерпретируемый, объектно-ориентированный, расширяемый, встраиваемый, переносимый и читабельный. - -## Почему Python востребован в Data Science? - -Бизнес во многих отраслях осознаёт важность получения как можно большего количества информации из своих данных, что создаёт высокий спрос на Python. Такой спрос на Python в Data Science возник из-за универсальности языка программирования, который позволяет ускорить процессы обработки данных и эффективно удовлетворить потребности бизнеса. - -Популярность Python для специалистов по данным возросла, потому что легко обучить, изучить и просто использовать. Python идеально подходит как для новичков в области работы с данными, так и для опытных программистов, которые хотят сменить карьеру на индустрию данных. - -### Бизнес предпочитают Python другим технологиям для выполнения ежедневных задач с данными - -Python можно классифицировать как универсальный язык программирования, который позволяет специалистам по данным быстро выполнять основные ежедневные задачи с данными, что делает Python настолько привлекательным для бизнеса в различных отраслях, которые ищут специалистов по данным. Навыки программирования на Python стали визитной карточкой настоящего специалиста по данным для специалистов по найму и работодателей. - -Вот 3 основные причины, по которым компании предпочитают Python другим технологиям, таким как Matlab, R, Java или C, для выполнения повседневных задач по обработке данных: - -- **универсальность** - Python позволяет специалистам по данным быстро и легко выполнять задачи по обработке данных, статистике, математике, машинному обучению и визуализации в одной среде разработки -- **open-source** - Python имеет открытый исходный код, а его стандартные библиотеки позволяют пользователям экономить, столь ценное для бизнеса, время при разработке решений и тестировании продуктов с использованием структур данных Python, инструментов анализа и изменяемого исходного кода -- **удобный для пользователя** - Python считается одним из самых удобных для пользователя и объектно-ориентированных языков для изучения начинающими программистами и людьми, меняющими профессию, из-за его простоты использования и поддержки онлайн-сообщества. Например, в интерфейсе Python используется простой для понимания код со встроенными типами данных и динамической типизацией для ускоренной разработки, тестирования и внедрения прототипов. - -Сравнение, как выглядит одна и та же функция (расчёт факториала), написанная на Java и на Python: - -```Java linenums="1" title="Java" -class Factorial -{ - static int factorial(int n) - { - if (n == 0) - return 1; - return n*factorial(n-1); - } - - public static void main(String[] args) - { - System.out.println(factorial(5)); - } -} -``` - -```python linenums="1" title="Python" -def factorial(n): - return 1 if (n==1 or n==0) else n * factorial(n - 1) - -print(factorial(5)) -``` - -### Как Python используется в Data Science и машинном обучении? - -Когда дело доходит до выбора языка программирования в Data Science, он всегда определяется типом проекта, над которым была проделана работа. - -В настоящее время Python чаще всего используется в индустрии при разработке, тестировании и реализации проектов и процессов автоматизированного машинного обучения. - -Исследователь данных или инженер по машинному обучению будет использовать Python при выполнении проектов искусственного интеллекта и машинного обучения, включающих анализ настроений, обработку естественного языка или предиктивную аналитику, чтобы получать информацию о полезных тенденциях и закономерностях из структурированных и неструктурированных наборов данных. - -Это стало возможным благодаря развивающимся и бесплатным для всех пакетам библиотек Python, предназначенным для упрощения разработки, тестирования и выполнения проектов машинного обучения для специалистов по данным. - -Конкретные примеры ниже иллюстрируют, как некоторые из этих библиотек Python используются в индустрии для ключевых задач в операциях, связанных с Data Science, для каждого бизнеса, включая обработку данных, анализ, манипулирование, автоматизацию и машинное обучение: - -- **NumPy** - числового анализа данных, изображений и текста -- **SciPy** - научных вычислений -- **Pandas** - расширенной обработки данных -- **Scikit-learn** - машинного обучения, визуализации данных, обработки изображений/текстовых данных -- **Matplotlib** - визуализации данных - -### Применение Python в ведущих компаниях, ориентированных на данные, и будущее Python в Data Science - -Индустрия данных стала доверять Python как многоцелевому языку программирования. - -Уверенность и рост среди пользователей Python развивались по мере того, как Python доказывал свою способность адаптироваться к ежедневным требованиям компаний к данным, ориентированных на пользователей. Python позволил этим компаниям быстро и эффективно выполнять необходимые задачи по анализу данных, визуализации, автоматизации и машинному обучению. - -Python используют практически все крупные компании, о которых слышим каждый день: Сбер, Авито, Лента, VK, МТС, МегаФон, Miro, Лаборатория Касперского, ЦФТ, ВТБ.. список можно продолжать почти что бесконечно. - -Вот лишь некоторые из способов, которыми ведущие компании планеты, работающие с данными, используют Python: - -- **Yandex** - Python [используется в Яндекс](https://habr.com/ru/company/yandex/blog/509352/) уже более 15 лет и за это время было как переписано многое с различных языков программирования, например с Perl так и написано много с нуля. Python используют практически в каждом сервисе в том или ином виде. Активно используют фреймворк Django для создания web-сервисов, таких как Афишу, Погоду, Телепрограмму и другие. Примерно 15 лет назад практически весь backend был написан на C++ и переход на Python позволил сильно ускорить разработку сервисов. Активно используют почти все современные фреймворки, такие как Flask, [Celery](https://docs.celeryq.dev/), [Falcon](https://falcon.readthedocs.io/), которые как и Django написаны на Python. Для написания асинхронного кода используют такие фреймворки как [Tornado](https://www.tornadoweb.org/en/stable/), [Twisted](https://twisted.org/) и модуль стандартной библиотеки [asyncio](https://docs.python.org/3/library/asyncio.html). Что касается Data Science, то и тут Python не обошли стороной: был разработан известный в кругах специалистов по машинному обучению фреймворк [CatBoost](https://catboost.ai/), и хотя для написания такого фреймворка [использовались и другие языки](https://github.com/catboost/catboost), тем не менее вклад Python примерно в 25% общего кода имеет достаточно большой вклад в проект. -- **VK** - Python всё чаще используется социальной сетью ВКонтакте для проектирования, управления инфраструктурой и операционной автоматизации. Чтобы удовлетворить свои критические потребности пользователей в обновлениях в реальном времени, удобстве использования и подключении, ВКонтакте использует фреймворки, написанные на Python, которые быстро обрабатывает обширный веб-трафик, предоставляя пользователям эффективную работу в режиме реального времени каждый раз, когда они входят в систему. Также [используют Python](https://github.com/topics/vk-api) для своего API. -- **Netflix** - Python повсеместно используется службой создания контента и потоковой передачи ее группами по Data Science и инженерами для анализа данных на стороне сервера, визуализации и тестирования, прогнозной аналитики данных, автоматизации оповещений и безопасности, а также мониторинга данных в реальном времени и разработки внутренних операционных процессов. Например, персонализированные плейлисты _«Вы должны посмотреть это следующим, потому что вы смотрели…»_ используют алгоритмы глубокого обучения и прогнозной аналитики, чтобы дать конкретные рекомендации, основанные на индивидуальной аналитике поведенческих данных. -- **Google** - Python используется в максимально возможной степени - включая анализ данных, тестирование и мониторинг, автоматизацию и прогнозную аналитику, веб-приложения и разработку и т.д. Также использовал Python для создания фреймворка глубокого обучения TensorFlow, который используется для проектов машинного обучения компаний по всему миру. - -!!! quote "Личное мнение" - - Ожидается, что в будущем Python и Data Science сохранят прочное партнерство благодаря приверженности Python разработке и регулярному выпуску обновлений, отвечающих требованиям индустрии данных и новых технологий. Если среда программирования Python продолжит расширять свои возможности и универсальность, она по-прежнему будет предпочтительным языком для компаний, проектов и специалистов по работе с данными. - -### Изучите Python, чтобы подготовиться к успешной карьере в Data Science! - -Если есть заинтересованность в карьере связанной с индустрией данных, можно подготовиться к успеху, пройдя этот настоящий курс о языке программирования Python. - -Изучение использования Python для Data Science даст конкурентное преимущество при поиске первой работы или при смене карьеры связанной с индустрией данных. - -!!! info "Совет" - - Рекомендуется в процессе изучения заглядывать в официальную документацию и в частности [The Python Tutorial](https://docs.python.org/3/tutorial/). - -## Интересные факты про Python - -- Разработчик языка Гвидо ван Россум назвал его в честь популярного британского комедийного телешоу 1970-х «Летающий цирк Монти Пайтона» -- Актуальной версией Python считаются версии `3.6` и выше (`3.7`, `3.8.12`..). Долгое время (до 2020) года существовал `Python2`, который ныне не поддерживается и не обновляется. Если видите кусок кода на `Python2` и вам предстоит работать с ним, возможно, сначала придется его переписать, хотя большая часть кода имеет совместимость и работает корректно. Естественно тут не будем изучать `Python2` -- Довольно огромное сообщество: большинство проблем, с которыми можете столкнуться, уже было озвучено и даже решено. Это означает, что используя поисковик, можете решить практически все проблемы в течение 10-30 минут. Главное – научиться правильно формулировать свои вопросы -- При работе с Python следует придерживаться принципа «должен существовать один и, желательно, только один очевидный способ сделать это». Другие принципы (`Дзен Питона`) на русском языке – [по ссылке](https://tyapk.ru/blog/post/the-zen-of-python) -- Python – это ^^открытый проект^^, в который каждый может внести изменения (но они должны быть предварительно одобрены), например, [тут](https://mail.python.org/archives/list/python-ideas@python.org/) -- Есть целый набор рекомендаций и предложений по улучшению кода (`PEP`, [Python Enhancement Proposals](https://www.python.org/dev/peps/)). Они содержат указания на то, как следует писать код и чего стоит избегать, а также дискуссии о будущих изменениях в языке -- Язык постоянно развивается, в нем появляются новые возможности, улучшается производительность (скорость выполнения) -- Сборник всех существующих в открытом доступе библиотек находится по адресу [pypi.org](https://pypi.org/) -- Если столкнетесь с багом (системной ошибкой, вызванной внутренним механизмом языка), то сообщить об этом можно [на специальном сайте](https://bugs.python.org/) +тест diff --git a/docs/javascripts/mathjax.js b/docs/javascripts/mathjax.js deleted file mode 100644 index 85528390..00000000 --- a/docs/javascripts/mathjax.js +++ /dev/null @@ -1,16 +0,0 @@ -window.MathJax = { - tex: { - inlineMath: [["\\(", "\\)"]], - displayMath: [["\\[", "\\]"]], - processEscapes: true, - processEnvironments: true - }, - options: { - ignoreHtmlClass: ".*|", - processHtmlClass: "arithmatex" - } - }; - - document$.subscribe(() => { - MathJax.typesetPromise() - }) diff --git a/docs/overrides/main.html b/docs/overrides/main.html deleted file mode 100644 index 2d8a1a20..00000000 --- a/docs/overrides/main.html +++ /dev/null @@ -1,5 +0,0 @@ -{% extends "base.html" %} - -{% block announce %} - желаете помочь курсу, переходите к инструкции -{% endblock %} diff --git a/license b/license deleted file mode 100644 index f288702d..00000000 --- a/license +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/mkdocs.yml b/mkdocs.yml deleted file mode 100644 index 8e265b0f..00000000 --- a/mkdocs.yml +++ /dev/null @@ -1,146 +0,0 @@ -site_name: python от ods.ai -site_url: https://open-data-science.github.io/pycourse/ -copyright: © 2022-2023 ods.ai - -repo_name: open-data-science/pycourse -repo_url: https://github.com/open-data-science/pycourse -edit_uri: edit/master/docs/ - -theme: - name: material - custom_dir: docs/overrides - - static_templates: - - 404.html - - font: - text: Golos Text - code: JetBrains Mono - - favicon: assets/logo.png - logo: assets/logo.png - - language: ru - features: - - announce.dismiss - - - content.code.annotate - - content.code.copy - - content.action.edit - - content.tabs.link - - # - header.autohide - - - navigation.expand - - navigation.footer - - navigation.indexes - - navigation.instant - - navigation.sections - - navigation.tabs - - navigation.tabs.sticky - - navigation.top - - navigation.tracking - - - search.highlight - - search.share - - search.suggest - - palette: - scheme: slate - primary: black - accent: red - -plugins: - - search: - lang: - - en - - ru - - minify: - minify_html: true - # - git-revision-date-localized: - # enable_creation_date: true - # fallback_to_build_date: true - # type: date - - glightbox - - -extra: - generator: false - analytics: - provider: google - property: !ENV GOOGLE_ANALYTICS_KEY - social: - - icon: fontawesome/brands/github - link: https://github.com/open-data-science/pycourse - # - icon: fontawesome/brands/matrix - # link: .. - - icon: fontawesome/brands/twitter - link: https://twitter.com/ods_ai - -markdown_extensions: - - # Python Markdown - - abbr - - admonition - - attr_list - - def_list - - footnotes - - md_in_html - - tables - - toc: - permalink: true - - # Python Markdown Extensions - - pymdownx.arithmatex: - generic: true - - pymdownx.betterem: - smart_enable: all - - pymdownx.caret - - pymdownx.critic - - pymdownx.details - - pymdownx.emoji: - emoji_generator: !!python/name:materialx.emoji.to_svg - emoji_index: !!python/name:materialx.emoji.twemoji - - pymdownx.highlight: - anchor_linenums: true - - pymdownx.inlinehilite - - pymdownx.keys - - pymdownx.mark - - pymdownx.snippets - - pymdownx.smartsymbols - - pymdownx.superfences: - custom_fences: - - name: mermaid - class: mermaid - format: !!python/name:pymdownx.superfences.fence_code_format - - pymdownx.tabbed: - alternate_style: true - - pymdownx.tasklist: - custom_checkbox: true - clickable_checkbox: true - - pymdownx.tilde - -extra_javascript: - - javascripts/mathjax.js - - https://polyfill.io/v3/polyfill.min.js?features=es6 - - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js - -nav: - - главная: - - index.md - - authors.md - - community.md - - содействие: https://github.com/open-data-science/pycourse/blob/master/contributing.md - - лицензия: https://github.com/open-data-science/pycourse/blob/master/license - - основы python: - - base/index.md - - установка инструментов: base/tools_install.md - - ориентация в jupyter: base/jupyter.md - - переменные, типы и вывод: base/variable_types_output.md - - условия и сравнения: base/conditional_comparison.md - - списки и циклы: base/list_loop.md - - словари: base/dictionary.md - - функции: base/functions.md - - объекты, классы и методы: base/object_class_method.md - - синтаксический сахар: base/syntactic_sugar.md - - финальная лекция: base/final.md diff --git a/readme.md b/readme.md index e66f5e25..d0e8ff14 100644 --- a/readme.md +++ b/readme.md @@ -1,49 +1,19 @@ - -``` - __ ___ __ __ ___ __ __ __ -|__) \_/ | |__| / \ |\ | / \ | / \ | \ (_ /\ | -| | | | | \__/ | \| \__/ | \__/ |__/ __) . /--\ | -``` +# docs.jethub.pro -

- - badge_ci - - - badge_cd_prod - - - badge_dependency_review - - - badge_codeql - -

+## окружение/среда -# О чём это всё +разработано на движке [mkdocs](https://github.com/squidfunk/mkdocs-material) -В этом чудесном месте планируется затронуть основные моменты Python (с упором на машинное обучение) +- установить нужные библиотеки (лучше в отдельном виртуальном окружении) -- база -- как работать с основными библиотеками -- что есть правильный код -- асинхронность -- тесты -- .. + ```bash + pip install -r requirements.txt + ``` -Кто-то без умолку уронит замечание, дескать, этого всего сполна, но тут упор делаем на примеры в той самой промышленности. +- запустить -Проект находится в стадии разработки «основы python». + ```bash + mkdocs serve --dirtyreload + ``` -# Содействие - -Будем рады любой помощи в составлении материалов, практики и иного доброго словца – [contributing.md](https://github.com/open-data-science/pycourse/blob/master/contributing.md). - -# Дискуссии - -Их можно обсуждать в следующих местах - -- [задачах](https://github.com/open-data-science/pycourse/issues) -- [обсуждениях](https://github.com/open-data-science/pycourse/discussions) - -[Дорожная карта](https://github.com/orgs/open-data-science/projects/1/views/2) +- перейти по предложенной внутренней ссылке, дабы открыть книгу