Repository: trekhleb/learn-python Branch: master Commit: 7d36c78b5f8f Files: 79 Total size: 189.6 KB Directory structure: gitextract_6lyybz2h/ ├── .flake8 ├── .gitignore ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.es-ES.md ├── README.md ├── README.pt-BR.md ├── README.zh-TW.md ├── _config.yml ├── pylintrc ├── requirements.txt └── src/ ├── additions/ │ ├── test_generators.py │ └── test_pass.py ├── classes/ │ ├── test_class_and_instance_variables.py │ ├── test_class_definition.py │ ├── test_class_objects.py │ ├── test_inheritance.py │ ├── test_instance_objects.py │ ├── test_method_objects.py │ └── test_multiple_inheritance.py ├── control_flow/ │ ├── test_break.py │ ├── test_continue.py │ ├── test_for.py │ ├── test_if.py │ ├── test_try.py │ └── test_while.py ├── data_types/ │ ├── test_dictionaries.py │ ├── test_lists.py │ ├── test_numbers.py │ ├── test_sets.py │ ├── test_strings.py │ ├── test_tuples.py │ └── test_type_casting.py ├── exceptions/ │ ├── test_handle_exceptions.py │ └── test_raise_exceptions.py ├── files/ │ ├── binary_file │ ├── multi_line_file.txt │ ├── test_file_methods.py │ └── test_file_reading.py ├── functions/ │ ├── test_function_annotations.py │ ├── test_function_arbitrary_arguments.py │ ├── test_function_decorators.py │ ├── test_function_default_arguments.py │ ├── test_function_definition.py │ ├── test_function_documentation_string.py │ ├── test_function_keyword_arguments.py │ ├── test_function_scopes.py │ ├── test_function_unpacking_arguments.py │ └── test_lambda_expressions.py ├── getting_started/ │ ├── python_syntax.md │ ├── test_variables.py │ └── what_is_python.md ├── modules/ │ ├── fibonacci_module.py │ ├── sound_package/ │ │ ├── __init__.py │ │ ├── effects/ │ │ │ ├── __init__.py │ │ │ ├── echo.py │ │ │ └── reverse.py │ │ └── formats/ │ │ ├── __init__.py │ │ ├── aif.py │ │ └── wav.py │ ├── test_modules.py │ └── test_packages.py ├── operators/ │ ├── test_arithmetic.py │ ├── test_assigment.py │ ├── test_bitwise.py │ ├── test_comparison.py │ ├── test_identity.py │ ├── test_logical.py │ └── test_membership.py ├── standard_libraries/ │ ├── glob_files/ │ │ ├── first_file.txt │ │ └── second_file.txt │ ├── test_datetime.py │ ├── test_glob.py │ ├── test_json.py │ ├── test_math.py │ ├── test_re.py │ └── test_zlib.py └── user_input/ └── test_input.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .flake8 ================================================ [flake8] max-line-length = 100 ================================================ FILE: .gitignore ================================================ .idea .pytest_cache venv **/*.pyc env __pycache__ .vscode ================================================ FILE: .travis.yml ================================================ language: python python: - "3.6" # Install dependencies. install: - pip install -r requirements.txt # Run linting and tests. script: - pylint ./src - flake8 ./src --statistics --count - pytest # Turn email notifications off. notifications: email: false ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2018 Oleksii Trekhleb Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.es-ES.md ================================================ # Playground y Cheatsheet para aprender Python [![Build Status](https://travis-ci.org/trekhleb/learn-python.svg?branch=master)](https://travis-ci.org/trekhleb/learn-python) > Esta es una colección de scripts de Python divididos en [categorías](#contenido) que contienen ejemplos de código con sus explicaciones, diferentes usos y links a recursos adicionales. > _Lee esto en:_ [_Inglés_](README.md), [_Portugués_](README.pt-BR.md), _Traditional Chinese_](README.zh-TW.md). Es un **playground** ya que puedes cambiar o añadir cosas al código para ver cómo funciona y [probarlo](#probando-el-código) usando aserciones. También puedes [revisar el código](#revisando-el-código) que has escrito y averiguar si está acorde con la guía de estilos de Python. Todo esto, en conjunto, puede hacer que tu proceso de aprendizaje sea más interactivo y puede ayudarte a mantener la calidad del código muy alta desde el principio. Es un **cheatsheet** porque puedes regresar y revisar los ejemplos de código para fortalecer tus conocimientos sobre las [sentencias y contrucciones estándar de Python](#contenido). Además, ya que el código tiene muchas aserciones, podrás ver el resultado de las funciones/sentencias en el mismo código sin la necesidad de ejecutarlos. > _También puede interesarte 🤖 [Interactive Machine Learning Experiments](https://github.com/trekhleb/machine-learning-experiments)_ ## Cómo usar este repositorio Cada script de Python en este repositorio sigue la estructura: ```python """Lists <--- Nombre del tema # @see: https://www.learnpython.org/en/Lists <-- Link a recurso adicional Aquí puede haber una explicación detallada del tema en concreto (ej: información general sobre listas). """ def test_list_type(): """Explicación del sub-tema. Cada archivo contiene funciones de prueba que muestran sub-temas (ej: tipos de listas, métodos en listas). """ # Este es un ejemplo de cómo construir una lista. <-- Estos comentarios explican el procedimiento squares = [1, 4, 9, 16, 25] # Las listas pueden ser indexadas y cortadas. # Al indexar devuelve el item. assert squares[0] == 1 # <-- Estas aserciones muestran el resultado. # Al cortar devuelve una nueva lista. assert squares[-3:] == [9, 16, 25] # <-- Estas aserciones muestran el resultado. ``` Normalmente, querrás hacer lo siguiente: - [Encontrar el tema](#contenido) que quieres aprender o revisar. - Leer los comentarios y/o la documentación que está escrita en cada docstring del script (toma como ejemplo el script de arriba). - Ver los ejemplos de código y las aserciones para conocer diferentes maneras de usar el código y entender el resultado previsto. - Cambiar el código o añadir nuevas aserciones para ver cómo funcionan las cosas. - [Probar](#probando-el-código) y [revisar](#revisando-el-código) el código para ver si funciona y si está escrito correctamente. ## Contenido 1. **Empezando** - [¿Qué es Python?](src/getting_started/what_is_python.md) - [Sintaxis de Python](src/getting_started/python_syntax.md) - [Variables](src/getting_started/test_variables.py) 2. **Operadores** - [Operadores aritméticos](src/operators/test_arithmetic.py) (`+`, `-`, `*`, `/`, `//`, `%`, `**`) - [Operadores Bitwise](src/operators/test_bitwise.py) (`&`, `|`, `^`, `>>`, `<<`, `~`) - [Operadores de atribución](src/operators/test_assigment.py) (`=`, `+=`, `-=`, `/=`, `//=` etc.) - [Operadores de comparación](src/operators/test_comparison.py) (`==`, `!=`, `>`, `<`, `>=`, `<=`) - [Operadores lógicos](src/operators/test_logical.py) (`and`, `or`, `not`) - [Operadores de identidad](src/operators/test_identity.py) (`is`, `is not`) - [Operadores de asociación](src/operators/test_membership.py) (`in`, `not in`) 3. **Tipos de datos** - [Números](src/data_types/test_numbers.py) (incluyendo booleans) - [Strings](src/data_types/test_strings.py) y sus métodos - [Listas](src/data_types/test_lists.py) y sus métodos (incluyendo comprensión de listas) - [Tuples](src/data_types/test_tuples.py) - [Sets](src/data_types/test_sets.py) y sus métodos - [Diccionarios](src/data_types/test_dictionaries.py) - [Tipo de casting](src/data_types/test_type_casting.py) 4. **Control de flujo** - [La sentencia `if`](src/control_flow/test_if.py) - [La sentencia `for`](src/control_flow/test_for.py) (y la función `range()`) - [La sentencia `while`](src/control_flow/test_while.py) - [La sentencia `try`](src/control_flow/test_try.py) - [La sentencia `break`](src/control_flow/test_break.py) - [La sentencia `continue`](src/control_flow/test_continue.py) 5. **Funciones** - [Definición de función](src/functions/test_function_definition.py) (sentencias `def` y `return`) - [Ámbito de variables dentro de funciones](src/functions/test_function_scopes.py) (sentencias `global` y `nonlocal`) - [Valores de argumento predeterminados](src/functions/test_function_default_arguments.py) - [Argumentos de palabras clave](src/functions/test_function_keyword_arguments.py) - [Listas de argumento arbitrario](src/functions/test_function_arbitrary_arguments.py) - [Listas de argumentos en funciones](src/functions/test_function_unpacking_arguments.py) (sentencias `*` y `**`) - [Expresiones Lambda](src/functions/test_lambda_expressions.py) (sentencia `lambda`) - [Strings de documentación](src/functions/test_function_documentation_string.py) - [Anotaciones en funciones](src/functions/test_function_annotations.py) - [Decoradores de funciones](src/functions/test_function_decorators.py) 6. **Clases** - [Definición de clase](src/classes/test_class_definition.py) (sentencia `class`) - [Objetos de clase](src/classes/test_class_objects.py) - [Objetos de instancia](src/classes/test_instance_objects.py) - [Métodos de objetos](src/classes/test_method_objects.py) - [Variables de clase y de instancia](src/classes/test_class_and_instance_variables.py) - [Herencia](src/classes/test_inheritance.py) - [Herencia múltiple](src/classes/test_multiple_inheritance.py) 7. **Módulos** - [Módulos](src/modules/test_modules.py) (sentencia `import`) - [Paquetes](src/modules/test_packages.py) 8. **Errores y excepciones** - [Controlando excepciones](src/exceptions/test_handle_exceptions.py) (sentencia `try`) - [Generando excepciones](src/exceptions/test_raise_exceptions.py) (sentencia `raise`) 9. **Archivos** - [Leyendo y escribiendo](src/files/test_file_reading.py) (sentencia `with`) - [Métodos de objetos de archivo](src/files/test_file_methods.py) 10. **Adicionales** - [La sentencia `pass`](src/additions/test_pass.py) - [Generadores](src/additions/test_generators.py) (sentencia `yield`) 11. **Pequeño tour de las librerías estándar** - [Serialización](src/standard_libraries/test_json.py) (librería `json`) - [Parámetros en archivos](src/standard_libraries/test_glob.py) (librería `glob`) - [Expresiones regulares](src/standard_libraries/test_re.py) (librearía `re`) - [Matemática](src/standard_libraries/test_math.py) (librerías `math`, `random` y `statistics`) - [Fechas y horas](src/standard_libraries/test_datetime.py) (librería `datetime`) - [Compresión de datos](src/standard_libraries/test_zlib.py) (librearía `zlib`) ## Pre-requisitos **Instalando Python** Asegúrate de que tienes [Python3 instalado](https://realpython.com/installing-python/) en tu sistema. Podrías utilizar la librería estándar [venv](https://docs.python.org/es/3/library/venv.html) para crear entornos virtuales y tener Python, pip y todos los paquetes instalados en el directorio de tu proyecto local para evitar cometer errores con paquetes del sistema y sus versiones. Dependiendo de la instalación, tendrás acceso a Python3 ejecutando `python` o `python3`. Lo mismo aplica para el administrador de paquetes pip - puedes tener acceso a él ejecutando `pip` o `pip3`. Puedes ver tu versión actual de Python ejecutando: ```bash python --version ``` Ten en cuenta que cuando leas `python` en este repositorio, se asume que es Python **3**. **Instalando dependencias** Instala todas las depencias requeridas para el proyecto ejecutando: ```bash pip install -r requirements.txt ``` ## Probando el código Las pruebas son hechas usando el framework [pytest](https://docs.pytest.org/en/latest/). Puedes añadir más pruebas por ti mismo añadiendo archivos y funciones con el prefijo `test_` (ej: `test_topic.py` con la función `def test_sub_topic()` adentro). Para ejecutar todas las pruebas, por favor escribe el siguiente comando desde el directorio raíz del proyecto: ```bash pytest ``` Para ejecutar diferentes pruebas escribe: ```bash pytest ./path/to/the/test_file.py ``` ## Revisando el código La revisión del código está hecha usando las librerías [pylint](http://pylint.pycqa.org/) y [flake8](http://flake8.pycqa.org/en/latest/). ### PyLint Para revisar si el código sigue la guía de estilos [PEP 8](https://www.python.org/dev/peps/pep-0008/), por favor ejecuta: ```bash pylint ./src/ ``` En caso de que linter detecte un error (ej: `missing-docstring`), te recomiendo leer más sobre el error concreto ejecutando: ```bash pylint --help-msg=missing-docstring ``` [Más sobre PyLint](http://pylint.pycqa.org/) ### Flake8 Para revisar si el código sigue la guía de estilos [PEP 8](https://www.python.org/dev/peps/pep-0008/), por favor ejecuta: ```bash flake8 ./src ``` O, si quieres ver un output más detallado, ejecuta: ```bash flake8 ./src --statistics --show-source --count ``` [Más sobre Flake8](http://flake8.pycqa.org/en/latest/) ## Apoya al proyecto Puedes apoyar al proyecto a través de ❤️️ [GitHub](https://github.com/sponsors/trekhleb) o ❤️️ [Patreon](https://www.patreon.com/trekhleb). ================================================ FILE: README.md ================================================ # Playground and Cheatsheet for Learning Python > 🇺🇦 UKRAINE [IS BEING ATTACKED](https://war.ukraine.ua/) BY RUSSIAN ARMY. CIVILIANS ARE GETTING KILLED. RESIDENTIAL AREAS ARE GETTING BOMBED. > - Help Ukraine via: > - [Serhiy Prytula Charity Foundation](https://prytulafoundation.org/en/) > - [Come Back Alive Charity Foundation](https://savelife.in.ua/en/donate-en/) > - [National Bank of Ukraine](https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi) > - More info on [war.ukraine.ua](https://war.ukraine.ua/) and [MFA of Ukraine](https://twitter.com/MFA_Ukraine)
[![Build Status](https://travis-ci.org/trekhleb/learn-python.svg?branch=master)](https://travis-ci.org/trekhleb/learn-python) > This is a collection of Python scripts that are split by [topics](#table-of-contents) and contain code examples with explanations, different use cases and links to further readings. > _Read this in:_ [_Português_](README.pt-BR.md), [_Español_](README.es-ES.md), [_Traditional Chinese_](README.zh-TW.md). It is a **playground** because you may change or add the code to see how it works and [test it out](#testing-the-code) using assertions. It also allows you to [lint the code](#linting-the-code) you've wrote and check if it fits to Python code style guide. Altogether it might make your learning process to be more interactive and it might help you to keep code quality pretty high from very beginning. It is a **cheatsheet** because you may get back to these code examples once you want to recap the syntax of [standard Python statements and constructions](#table-of-contents). Also because the code is full of assertions you'll be able to see expected functions/statements output right away without launching them. > _You might also be interested in 🤖 [Interactive Machine Learning Experiments](https://github.com/trekhleb/machine-learning-experiments)_ ## How to Use This Repository Each Python script in this repository has the following structure: ```python """Lists <--- Name of the topic here # @see: https://www.learnpython.org/en/Lists <-- Link to further readings goes here Here might go more detailed explanation of the current topic (i.e. general info about Lists). """ def test_list_type(): """Explanation of sub-topic goes here. Each file contains test functions that illustrate sub-topics (i.e. lists type, lists methods). """ # Here is an example of how to build a list. <-- Comments here explain the action squares = [1, 4, 9, 16, 25] # Lists can be indexed and sliced. # Indexing returns the item. assert squares[0] == 1 # <-- Assertions here illustrate the result. # Slicing returns a new list. assert squares[-3:] == [9, 16, 25] # <-- Assertions here illustrate the result. ``` So normally you might want to do the following: - [Find the topic](#table-of-contents) you want to learn or recap. - Read comments and/or documentation that is linked in each script's docstring (as in example above). - Look at code examples and assertions to see usage examples and expected output. - Change code or add new assertions to see how things work. - [Run tests](#testing-the-code) and [lint the code](#linting-the-code) to see if it work and is written correctly. ## Table of Contents 1. **Getting Started** - [What is Python](src/getting_started/what_is_python.md) - [Python Syntax](src/getting_started/python_syntax.md) - [Variables](src/getting_started/test_variables.py) 2. **Operators** - [Arithmetic Operators](src/operators/test_arithmetic.py) (`+`, `-`, `*`, `/`, `//`, `%`, `**`) - [Bitwise Operators](src/operators/test_bitwise.py) (`&`, `|`, `^`, `>>`, `<<`, `~`) - [Assignment Operators](src/operators/test_assigment.py) (`=`, `+=`, `-=`, `/=`, `//=` etc.) - [Comparison Operator](src/operators/test_comparison.py) (`==`, `!=`, `>`, `<`, `>=`, `<=`) - [Logical Operators](src/operators/test_logical.py) (`and`, `or`, `not`) - [Identity Operators](src/operators/test_identity.py) (`is`, `is not`) - [Membership Operators](src/operators/test_membership.py) (`in`, `not in`) 3. **Data Types** - [Numbers](src/data_types/test_numbers.py) (including booleans) - [Strings](src/data_types/test_strings.py) and their methods - [Lists](src/data_types/test_lists.py) and their methods (including list comprehensions) - [Tuples](src/data_types/test_tuples.py) - [Sets](src/data_types/test_sets.py) and their methods - [Dictionaries](src/data_types/test_dictionaries.py) - [Type Casting](src/data_types/test_type_casting.py) 4. **Control Flow** - [The `if` statement](src/control_flow/test_if.py) - [The `for` statement](src/control_flow/test_for.py) (and `range()` function) - [The `while` statement](src/control_flow/test_while.py) - [The `try` statements](src/control_flow/test_try.py) - [The `break` statement](src/control_flow/test_break.py) - [The `continue` statement](src/control_flow/test_continue.py) 5. **Functions** - [Function Definition](src/functions/test_function_definition.py) (`def` and `return` statements) - [Scopes of Variables Inside Functions](src/functions/test_function_scopes.py) (`global` and `nonlocal` statements) - [Default Argument Values](src/functions/test_function_default_arguments.py) - [Keyword Arguments](src/functions/test_function_keyword_arguments.py) - [Arbitrary Argument Lists](src/functions/test_function_arbitrary_arguments.py) - [Unpacking Argument Lists](src/functions/test_function_unpacking_arguments.py) (`*` and `**` statements) - [Lambda Expressions](src/functions/test_lambda_expressions.py) (`lambda` statement) - [Documentation Strings](src/functions/test_function_documentation_string.py) - [Function Annotations](src/functions/test_function_annotations.py) - [Function Decorators](src/functions/test_function_decorators.py) 6. **Classes** - [Class Definition](src/classes/test_class_definition.py) (`class` statement) - [Class Objects](src/classes/test_class_objects.py) - [Instance Objects](src/classes/test_instance_objects.py) - [Method Objects](src/classes/test_method_objects.py) - [Class and Instance Variables](src/classes/test_class_and_instance_variables.py) - [Inheritance](src/classes/test_inheritance.py) - [Multiple Inheritance](src/classes/test_multiple_inheritance.py) 7. **Modules** - [Modules](src/modules/test_modules.py) (`import` statement) - [Packages](src/modules/test_packages.py) 8. **Errors and Exceptions** - [Handling Exceptions](src/exceptions/test_handle_exceptions.py) (`try` statement) - [Raising Exceptions](src/exceptions/test_raise_exceptions.py) (`raise` statement) 9. **Files** - [Reading and Writing](src/files/test_file_reading.py) (`with` statement) - [Methods of File Objects](src/files/test_file_methods.py) 10. **Additions** - [The `pass` statement](src/additions/test_pass.py) - [Generators](src/additions/test_generators.py) (`yield` statement) 11. **Brief Tour of the Standard Libraries** - [Serialization](src/standard_libraries/test_json.py) (`json` library) - [File Wildcards](src/standard_libraries/test_glob.py) (`glob` library) - [String Pattern Matching](src/standard_libraries/test_re.py) (`re` library) - [Mathematics](src/standard_libraries/test_math.py) (`math`, `random`, `statistics` libraries) - [Dates and Times](src/standard_libraries/test_datetime.py) (`datetime` library) - [Data Compression](src/standard_libraries/test_zlib.py) (`zlib` library) 12. **User input** - [Terminal input](src/user_input/test_input.py) (`input` statement) ## Prerequisites **Installing Python** Make sure that you have [Python3 installed](https://realpython.com/installing-python/) on your machine. You might want to use [venv](https://docs.python.org/3/library/venv.html) standard Python library to create virtual environments and have Python, pip and all dependent packages to be installed and served from the local project directory to avoid messing with system wide packages and their versions. Depending on your installation you might have access to Python3 interpreter either by running `python` or `python3`. The same goes for pip package manager - it may be accessible either by running `pip` or `pip3`. You may check your Python version by running: ```bash python --version ``` Note that in this repository whenever you see `python` it will be assumed that it is Python **3**. **Installing dependencies** Install all dependencies that are required for the project by running: ```bash pip install -r requirements.txt ``` ## Testing the Code Tests are made using [pytest](https://docs.pytest.org/en/latest/) framework. You may add new tests for yourself by adding files and functions with `test_` prefix (i.e. `test_topic.py` with `def test_sub_topic()` function inside). To run all the tests please execute the following command from the project root folder: ```bash pytest ``` To run specific tests please execute: ```bash pytest ./path/to/the/test_file.py ``` ## Linting the Code Linting is done using [pylint](http://pylint.pycqa.org/) and [flake8](http://flake8.pycqa.org/en/latest/) libraries. ### PyLint To check if the code is written with respect to [PEP 8](https://www.python.org/dev/peps/pep-0008/) style guide please run: ```bash pylint ./src/ ``` In case if linter will detect error (i.e. `missing-docstring`) you may want to read more about specific error by running: ```bash pylint --help-msg=missing-docstring ``` [More about PyLint](http://pylint.pycqa.org/) ### Flake8 To check if the code is written with respect to [PEP 8](https://www.python.org/dev/peps/pep-0008/) style guide please run: ```bash flake8 ./src ``` Or if you want to have more detailed output you may run: ```bash flake8 ./src --statistics --show-source --count ``` [More about Flake8](http://flake8.pycqa.org/en/latest/) ## Author - [@trekhleb](https://trekhleb.dev) ================================================ FILE: README.pt-BR.md ================================================ # Playground e Cheatsheet Para Aprender Python [![Build Status](https://travis-ci.org/trekhleb/learn-python.svg?branch=master)](https://travis-ci.org/trekhleb/learn-python) > Essa é uma coleção de scripts Python dividida em [tópicos](#índice) que contém exemplos de código com explicações, diferentes usos e links para outras leituras. > _Ler em:_ [_English_](README.md), [_Español_](README.es-ES.md), [_Traditional Chinese_](README.zh-TW.md). É um **playground** porque você pode fazer alterações no código para ver como ele se comporta, além de [testá-lo](#testando-o-código) usando asserções. Também é possível [revisar o código](#revisando-o-código) que você escreveu automaticamente e verificar se ele se encaixa no guia de estilo de código Python. Isso tudo pode tornar seu processo de aprendizagem mais interativo e ajudar a manter a qualidade do código bastante alta desde o início. É um **cheatsheet** porque você pode voltar a esses exemplos de código quando quiser recapitular a sintaxe das [estruturas padrão do Python](#índice). O código está cheio de asserções, então você poderá ver o retorno das funções sem precisar executá-las. > _Você pode se interessar também por 🤖 [Interactive Machine Learning Experiments](https://github.com/trekhleb/machine-learning-experiments)_ ## Como Usar Esse Repositório Nesse repositório, cada script Python possui a seguinte estrutura: ```python """Lists <--- Nome do tópico # @see: https://www.learnpython.org/en/Lists <-- Link para outras leituras. A seguir, uma explicação mais detalhada do tópico atual (ex, informações gerais sobre listas (Lists)). """ def test_list_type(): """Explicação do subtópico. Cada arquivo contém funções de teste que ilustram subtópicos (ou seja, tipo de lista, métodos de lista). """ # Here is an example of how to build a list. <-- Comentários em inglês explicam a ação. squares = [1, 4, 9, 16, 25] # Lists can be indexed and sliced. # Indexing returns the item. assert squares[0] == 1 # <-- As asserções ilustram o resultado. # Slicing returns a new list. assert squares[-3:] == [9, 16, 25] # <-- As asserções ilustram o resultado. ``` Então você pode querer fazer o seguinte: - [Encontrar o tópico](#índice) que deseja aprender ou recapitular. - Ler os comentários e/ou a documentação vinculada em cada script (como no exemplo acima). - Analisar os exemplos e asserções para ver exemplos de uso e saída esperada das funções. - Alterar o código ou adicionar novas asserções para ver o que acontece. - [Executar testes](#testando-o-código) e [revisar o código](#revisando-o-código) para ver se ele funciona e para saber se está escrito corretamente. ## Índice 1. **Começando** - [O que é Python](src/getting_started/what_is_python.md) - [Sintaxe Python](src/getting_started/python_syntax.md) - [Variáveis](src/getting_started/test_variables.py) 2. **Operadores** - [Operadores Aritméticos](src/operators/test_arithmetic.py) (`+`, `-`, `*`, `/`, `//`, `%`, `**`) - [Operadores Bitwise](src/operators/test_bitwise.py) (`&`, `|`, `^`, `>>`, `<<`, `~`) - [Operadores de Atribuição](src/operators/test_assigment.py) (`=`, `+=`, `-=`, `/=`, `//=` etc.) - [Operadores de Comparação](src/operators/test_comparison.py) (`==`, `!=`, `>`, `<`, `>=`, `<=`) - [Operadores Lógicos](src/operators/test_logical.py) (`and`, `or`, `not`) - [Operadores de Indentidade](src/operators/test_identity.py) (`is`, `is not`) - [Operadores de Associação](src/operators/test_membership.py) (`in`, `not in`) 3. **Tipos de Dados** - [Números](src/data_types/test_numbers.py) (incluindo boleanos) - [Strings](src/data_types/test_strings.py) e seus métodos - [Listas](src/data_types/test_lists.py) e seus métodos (incluindo lista de compreensões) - [Tuplas](src/data_types/test_tuples.py) - [Conjuntos](src/data_types/test_sets.py) e seus métodos - [Dicionários](src/data_types/test_dictionaries.py) - [Casting de Tipo](src/data_types/test_type_casting.py) 4. **Controles de Fluxo** - [A declaração `if`](src/control_flow/test_if.py) - [A declaração `for`](src/control_flow/test_for.py) (e a função `range()`) - [A declaração `while`](src/control_flow/test_while.py) - [A declaração `try`](src/control_flow/test_try.py) - [A declaração `break`](src/control_flow/test_break.py) - [A declaração `continue`](src/control_flow/test_continue.py) 5. **Funções** - [Definição de Função](src/functions/test_function_definition.py) (declaração `def` e `return`) - [Variáveis Dentro das Funções](src/functions/test_function_scopes.py) (declaração `global` e `nonlocal`) - [Valores Padrão de Argumentos](src/functions/test_function_default_arguments.py) - [Argumentos de palavras-chave](src/functions/test_function_keyword_arguments.py) - [Listas de Argumento Arbitrárias](src/functions/test_function_arbitrary_arguments.py) - [Desfazendo Lista de Argumentos](src/functions/test_function_unpacking_arguments.py) (declaração `*` e `**`) - [Expressões Lambda](src/functions/test_lambda_expressions.py) (declaração `lambda`) - [Documentação das Strings](src/functions/test_function_documentation_string.py) - [Função de Anotações](src/functions/test_function_annotations.py) - [Função de Decoradores](src/functions/test_function_decorators.py) 6. **Classes** - [Definição de Classe](src/classes/test_class_definition.py) (declaração `class`) - [Classes dos Objetos](src/classes/test_class_objects.py) - [Instância dos Objetos](src/classes/test_instance_objects.py) - [Métodos de Objetos](src/classes/test_method_objects.py) - [Variável de Classe e Instância](src/classes/test_class_and_instance_variables.py) - [Herança](src/classes/test_inheritance.py) - [Herança Múltipla](src/classes/test_multiple_inheritance.py) 7. **Módulos** - [Módulos](src/modules/test_modules.py) (declaração `import`) - [Pacotes](src/modules/test_packages.py) 8. **Erros e Exceções** - [Tratando Exceções](src/exceptions/test_handle_exceptions.py) (declaração `try`) - [Levantando Exceções](src/exceptions/test_raise_exceptions.py) (declaração `raise`) 9. **Arquivos** - [Lendo e Escrevendo](src/files/test_file_reading.py) (declaração `with`) - [Métodos de Objetos de Arquivos](src/files/test_file_methods.py) 10. **Adicional** - [A declaração `pass`](src/additions/test_pass.py) - [Geradores](src/additions/test_generators.py) (declaração `yield`) 11. **Algumas Bibliotecas Padrão** - [Serialization](src/standard_libraries/test_json.py) (biblioteca `json`) - [File Wildcards](src/standard_libraries/test_glob.py) (biblioteca `glob`) - [String Pattern Matching](src/standard_libraries/test_re.py) (biblioteca `re`) - [Matemática](src/standard_libraries/test_math.py) (bibliotecas `math`, `random` e `statistics`) - [Tempo e Datas](src/standard_libraries/test_datetime.py) (biblioteca `datetime`) - [Comprimindo Dados](src/standard_libraries/test_zlib.py) (biblioteca `zlib`) ## Pré-requisitos **Instalando o Python** Certifique-se de ter o [Python3 instalado](https://realpython.com/installing-python/) em sua máquina. Você pode usar a biblioteca padrão do Python [venv](https://docs.python.org/3/library/venv.html) para criar ambientes virtuais e ter o Python, pip e todos os outros pacotes a serem instalados a partir do diretório local do projeto para evitar mexer com pacotes externos ou do sistema. Dependendo da sua instalação, você pode ter acesso ao interpretador Python3 executando `python` ou `python3`. O mesmo vale para o gerenciador de pacotes pip, você pode acessá-lo executando `pip` ou `pip3`. Você pode ver a versão do seu Python executando: ```bash python --version ``` Observe que neste repositório sempre que você vê o `python`, será assumido que é o Python **3**. **Instalando dependências** Instale todas as dependências necessárias para o projeto executando: ```bash pip install -r requirements.txt ``` ## Testando o Código Testes são feitos usando o framework [pytest](https://docs.pytest.org/en/latest/). Você pode adicionar novos testes criando arquivos e funções com o prefixo `test_` (ex. `test_topic.py` com a função `def test_sub_topic()` dentro). Para executar todos os testes, execute o seguinte comando na pasta raiz do projeto: ```bash pytest ``` Para executar testes específicos, execute: ```bash pytest ./path/to/the/test_file.py ``` ## Revisando o Código A revisão é feita usando as bibliotecas [pylint](http://pylint.pycqa.org/) e [flake8](http://flake8.pycqa.org/en/latest/). ### PyLint Para verificar se o código está escrito de acordo com o guia de estilo do [PEP 8](https://www.python.org/dev/peps/pep-0008/), execute: ```bash pylint ./src/ ``` Caso o pylint detecte um erro (ex. `missing-docstring`), convém ler mais sobre erros específicos executando: ```bash pylint --help-msg=missing-docstring ``` [Saber mais sobre PyLint](http://pylint.pycqa.org/) ### Flake8 Para verificar se o código está escrito de acordo com o guia de estilo do [PEP 8](https://www.python.org/dev/peps/pep-0008/), execute: ```bash flake8 ./src ``` Ou, se você quiser uma saída mais detalhada, execute: ```bash flake8 ./src --statistics --show-source --count ``` [Saber mais sobre Flake8](http://flake8.pycqa.org/en/latest/) --- Traduzido por [vilmacio22](https://github.com/vilmacio22). ================================================ FILE: README.zh-TW.md ================================================ # 學習 Python 的練習場(Playground)和速查表(Cheatsheet) [![Build Status](https://travis-ci.org/trekhleb/learn-python.svg?branch=master)](https://travis-ci.org/trekhleb/learn-python) > 此專案依據 [目錄](#目錄) 分類收集了 Python 腳本,包含了程式碼範例及解釋、不同的使用情境以及衍伸閱讀連結。 > _閱讀英文原始版本:_ [_English_](README.md), [_Português_](README.pt-BR.md), [_Español_](README.es-ES.md). 此專案名稱之所以叫做 **練習場(Playground)**,是因為您可以修改或是新增程式碼至範例中去觀察程式執行流程並使用斷言關鍵字(assert)來 [測試程式](#測試程式)。同時,此專案也使用了業界常用的工具來 [檢查程式碼](#檢查程式碼),確保您所撰寫的程式碼符合官方建議的 Python 程式碼風格規範。 總而言之,此專案會使您的學習過程更具互動性,並幫助您從一開始學習的時候就使用高品質的程式碼。 此專案名稱之所以也包含了 **速查表(Cheatsheet)** 是因為您可以隨時透過此專案中的 [標準 Python 陳述式以及結構](#目錄) 回顧程式碼語法,也因為在此專案中的每個程式碼範例都使用了斷言來說明及教學,故您可以不用執行程式就看到函式/陳述式的預期輸出結果。 > 若對機器學習(Machine Learning)有興趣,可以參考專案原作者的另一個學習專案:🤖 [Interactive Machine Learning Experiments](https://github.com/trekhleb/machine-learning-experiments) ## 如何使用此專案儲存庫 在此專案儲存庫中的每一個 Python 腳本皆為以下結構: ```python """串列(Lists) <--- 此為主題名稱 # @詳見: https://www.learnpython.org/en/Lists <-- 此為延伸閱讀連結 此處可能會有針對此主題更多的詳細說明(例如:關於串列的基本使用方法) """ def test_list_type(): """此處為子主題解釋 每個檔案皆包含說明該子主題的測試函式(例如:串列型態、串列方法) """ # 建立串列之範例 <-- 此行是解釋下一行程式碼動作之註解 squares = [1, 4, 9, 16, 25] # 串列可以被索引(indexed)及切片(sliced) # 索引會回傳該索引位置之內容值 assert squares[0] == 1 # <-- 利用斷言來呈現結果 # 切片會回傳一個新的串列 assert squares[-3:] == [9, 16, 25] # <-- 利用斷言來呈現結果 ``` 故您可以做以下動作: - 找一個您想要學習或是回顧的 [主題](#目錄)。 - 閱讀註解及/或包含於腳本文件字串(docstring)中的延伸閱讀資料(如上述之程式碼範例)。 - 查看程式碼範例並利用斷言來展示使用範例及預期輸出。 - 修改程式碼或新增新的斷言來了解程式運作流程。 - [執行測試](#測試程式) 及 [檢查程式碼](#檢查程式碼) 來確認程式是否被正確撰寫及是否可以被正確執行。 ## 目錄 1. **入門** - [Python 是什麼](src/getting_started/what_is_python.md) - [Python 語法](src/getting_started/python_syntax.md) - [變數](src/getting_started/test_variables.py) 2. **運算子** - [數學運算子](src/operators/test_arithmetic.py) (`+`, `-`, `*`, `/`, `//`, `%`, `**`) - [位元運算子](src/operators/test_bitwise.py) (`&`, `|`, `^`, `>>`, `<<`, `~`) - [指派運算子](src/operators/test_assigment.py) (`=`, `+=`, `-=`, `/=`, `//=` 等 ...) - [比較運算子](src/operators/test_comparison.py) (`==`, `!=`, `>`, `<`, `>=`, `<=`) - [邏輯運算子](src/operators/test_logical.py) (`and`, `or`, `not`) - [恆等運算子](src/operators/test_identity.py) (`is`, `is not`) - [成員存取運算子](src/operators/test_membership.py) (`in`, `not in`) 3. **資料類型** - [數字](src/data_types/test_numbers.py)(包含布林值) - [字串](src/data_types/test_strings.py) 及相關方法 - [串列](src/data_types/test_lists.py) 及相關方法(包含列表構建) - [元組](src/data_types/test_tuples.py) - [集合](src/data_types/test_sets.py) 及相關方法 - [字典](src/data_types/test_dictionaries.py) - [類型轉換](src/data_types/test_type_casting.py) 4. **流程控制** - [`if` 陳述式](src/control_flow/test_if.py) - [`for` 陳述式](src/control_flow/test_for.py) (以及 `range()` 函式) - [`while` 陳述式](src/control_flow/test_while.py) - [`try` 陳述式](src/control_flow/test_try.py) - [`break` 陳述式](src/control_flow/test_break.py) - [`continue` 陳述式](src/control_flow/test_continue.py) 5. **函式** - [函式定義](src/functions/test_function_definition.py)(`def` 以及 `return` 陳述式) - [函式內變數作用範圍](src/functions/test_function_scopes.py)(`global` 以及 `nonlocal` 陳述式) - [預設引數](src/functions/test_function_default_arguments.py) - [關鍵字引數](src/functions/test_function_keyword_arguments.py) - [任意引數串列](src/functions/test_function_arbitrary_arguments.py) - [拆解引數串列](src/functions/test_function_unpacking_arguments.py)(`*` 以及 `**` 陳述式) - [Lambda 表達式](src/functions/test_lambda_expressions.py) (`lambda` 陳述式) - [文件字串](src/functions/test_function_documentation_string.py) - [函式註釋](src/functions/test_function_annotations.py) - [函式裝飾器](src/functions/test_function_decorators.py) 6. **類別** - [類別定義](src/classes/test_class_definition.py) (`class` 陳述式) - [類別物件](src/classes/test_class_objects.py) - [物件實體](src/classes/test_instance_objects.py) - [物件方法](src/classes/test_method_objects.py) - [類別及實體變數](src/classes/test_class_and_instance_variables.py) - [繼承](src/classes/test_inheritance.py) - [多重繼承](src/classes/test_multiple_inheritance.py) 7. **模組** - [模組](src/modules/test_modules.py) (`import` 陳述式) - [套件](src/modules/test_packages.py) 8. **錯誤和例外** - [例外處理](src/exceptions/test_handle_exceptions.py) (`try` 陳述式) - [例外引發](src/exceptions/test_raise_exceptions.py) (`raise` 陳述式) 9. **檔案** - [讀取和寫入](src/files/test_file_reading.py) (`with` 陳述式) - [檔案物件方法](src/files/test_file_methods.py) 10. **附加內容** - [`pass` 陳述式](src/additions/test_pass.py) - [生成器](src/additions/test_generators.py) (`yield` 陳述式) 11. **標準函式庫簡介** - [串列化](src/standard_libraries/test_json.py) (`json` 函式庫) - [檔案萬用字元](src/standard_libraries/test_glob.py) (`glob` 函式庫) - [字串規則比對](src/standard_libraries/test_re.py) (`re` 函式庫) - [數學運算](src/standard_libraries/test_math.py) (`math`, `random`, `statistics` 函式庫) - [日期和時間](src/standard_libraries/test_datetime.py) (`datetime` 函式庫) - [資料壓縮](src/standard_libraries/test_zlib.py) (`zlib` 函式庫) ## 使用此專案必備條件 **安裝 Python** 確認您已安裝 [Python3](https://realpython.com/installing-python/) 在您的電腦上。 您可能會想要使用標準 Python 函式庫所提供的 [虛擬環境](https://docs.python.org/3/library/venv.html) 功能在專案目錄中建立虛擬環境來佈署 Python 程式、pip 程式以及安裝所有需要的套件,藉此來避免作業系統中 Python 版本及相依性的混亂。 根據您的安裝方法,您可能可以通過以下方式執行 Python 3 直譯器:執行 `python` 或 `python3` 命令。pip 套件管理器執行方式也是如此:執行 `pip` 或 `pip3`。 您可以使用以下命令來確認 Python 版本: ```bash python --version ``` 此專案儲存庫中的所有程式碼皆是基於 Python **3**。 **安裝相依性套件** 透過以下命令安裝此專案需要的相依性套件: ```bash pip install -r requirements.txt ``` ## 測試程式 此專案使用 [pytest](https://docs.pytest.org/en/latest/) 測試框架來執行程式碼測試。 您可以新增以 `test_` 為開頭的檔案/函式來新增測試。(例如:`test_topic.py` 檔案內有 `def test_sub_topic()` 測試函式) 請從專案根目錄下使用以下命令來執行所有測試: ```bash pytest ``` 您也可以使用以下命令執行特定測試: ```bash pytest ./path/to/the/test_file.py ``` ## 檢查程式碼 此專案使用 [pylint](http://pylint.pycqa.org/) 以及 [flake8](http://flake8.pycqa.org/en/latest/) 函式庫來執行程式碼檢查。 ### PyLint 檢查撰寫之程式碼是否符合 [PEP 8](https://www.python.org/dev/peps/pep-0008/) 風格規範,請執行以下命令: ```bash pylint ./src/ ``` 若此檢查工具偵測到錯誤(例如:`missing-docstring`),您可以使用以下命令查看特定錯誤之詳細說明: ```bash pylint --help-msg=missing-docstring ``` [更多關於 PyLint](http://pylint.pycqa.org/) ### Flake8 檢查撰寫之程式碼是否符合 [PEP 8](https://www.python.org/dev/peps/pep-0008/) 風格規範,請執行以下命令: ```bash flake8 . /src ``` 若您希望得到更多詳細的輸出,您可以加上以下參數再執行此工具: ```bash flake8 . /src --statistics --show-source --count ``` [更多關於 Flake8](http://flake8.pycqa.org/en/latest/) ## 支持此專案 您可以透過 ❤️️ [GitHub](https://github.com/sponsors/trekhleb) 或 ❤️️ [Patreon](https://www.patreon.com/trekhleb) 支持原作者專案 ================================================ FILE: _config.yml ================================================ theme: jekyll-theme-minimal ================================================ FILE: pylintrc ================================================ [MASTER] # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. extension-pkg-whitelist= # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS # Add files or directories matching the regex patterns to the blacklist. The # regex matches against base names, not paths. ignore-patterns= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). # @TODO: Figure out how to AVOID HARD-CODING of sys.path in order to make pylint work with relative module imports init-hook='sys.path.append('./src/modules')' # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the # number of processors available to use. jobs=1 # Control the amount of potential inferred values when inferring a single # object. This can help the performance when dealing with large functions or # complex, nested conditions. limit-inference-results=100 # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= # Pickle collected data for later comparisons. persistent=yes # Specify a configuration file. #rcfile= # When enabled, pylint would attempt to guess common misconfiguration and emit # user-friendly hints instead of false-positive error messages. suggestion-mode=yes # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no [MESSAGES CONTROL] # Only show warnings with the listed confidence levels. Leave empty to show # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. confidence= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once). You can also use "--disable=all" to # disable everything first and then reenable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use "--disable=all --enable=classes # --disable=W". disable=print-statement, parameter-unpacking, unpacking-in-except, old-raise-syntax, backtick, long-suffix, old-ne-operator, old-octal-literal, import-star-module-level, non-ascii-bytes-literal, raw-checker-failed, bad-inline-option, locally-disabled, locally-enabled, file-ignored, suppressed-message, useless-suppression, deprecated-pragma, use-symbolic-message-instead, apply-builtin, basestring-builtin, buffer-builtin, cmp-builtin, coerce-builtin, execfile-builtin, file-builtin, long-builtin, raw_input-builtin, reduce-builtin, standarderror-builtin, unicode-builtin, xrange-builtin, coerce-method, delslice-method, getslice-method, setslice-method, no-absolute-import, old-division, dict-iter-method, dict-view-method, next-method-called, metaclass-assignment, indexing-exception, raising-string, reload-builtin, oct-method, hex-method, nonzero-method, cmp-method, input-builtin, round-builtin, intern-builtin, unichr-builtin, map-builtin-not-iterating, zip-builtin-not-iterating, range-builtin-not-iterating, filter-builtin-not-iterating, using-cmp-argument, eq-without-hash, div-method, idiv-method, rdiv-method, exception-message-attribute, invalid-str-codec, sys-max-int, bad-python3-import, deprecated-string-function, deprecated-str-translate-call, deprecated-itertools-function, deprecated-types-field, next-method-defined, dict-items-not-iterating, dict-keys-not-iterating, dict-values-not-iterating, deprecated-operator-function, deprecated-urllib-function, xreadlines-attribute, deprecated-sys-function, exception-escape, comprehension-escape # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). See also the "--disable" option for examples. enable=c-extension-no-member [REPORTS] # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details. #msg-template= # Set the output format. Available formats are text, parseable, colorized, json # and msvs (visual studio). You can also give a reporter class, e.g. # mypackage.mymodule.MyReporterClass. output-format=text # Tells whether to display a full report or only the messages. reports=no # Activate the evaluation score. score=yes [REFACTORING] # Maximum number of nested blocks for function / method body max-nested-blocks=5 # Complete name of functions that never returns. When checking for # inconsistent-return-statements if a never returning function is called then # it will be considered as an explicit return statement and no message will be # printed. never-returning-functions=sys.exit [LOGGING] # Logging modules to check that the string format arguments are in logging # function parameter format. logging-modules=logging [SPELLING] # Limits count of emitted suggestions for spelling mistakes. max-spelling-suggestions=4 # Spelling dictionary name. Available dictionaries: none. To make it working # install python-enchant package.. spelling-dict= # List of comma separated words that should not be checked. spelling-ignore-words= # A path to a file that contains private dictionary; one word per line. spelling-private-dict-file= # Tells whether to store unknown words to indicated private dictionary in # --spelling-private-dict-file option instead of raising a message. spelling-store-unknown-words=no [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME, XXX, TODO [TYPECHECK] # List of decorators that produce context managers, such as # contextlib.contextmanager. Add to this list to register other decorators that # produce valid context managers. contextmanager-decorators=contextlib.contextmanager # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. generated-members= # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # Tells whether to warn about missing members when the owner of the attribute # is inferred to be None. ignore-none=yes # This flag controls whether pylint should warn about no-member and similar # checks whenever an opaque object is returned when inferring. The inference # can return multiple potential results while evaluating a Python object, but # some branches might not be evaluated, which results in partial inference. In # that case, it might be useful to still emit no-member and other checks for # the rest of the inferred objects. ignore-on-opaque-inference=yes # List of class names for which member attributes should not be checked (useful # for classes with dynamically set attributes). This supports the use of # qualified names. ignored-classes=optparse.Values,thread._local,_thread._local # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis. It # supports qualified module names, as well as Unix pattern matching. ignored-modules= # Show a hint with possible names when a member name was not found. The aspect # of finding the hint is based on edit distance. missing-member-hint=yes # The minimum edit distance a name should have in order to be considered a # similar match for a missing member name. missing-member-hint-distance=1 # The total number of similar names that should be taken in consideration when # showing a hint for a missing member. missing-member-max-choices=1 [VARIABLES] # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins= # Tells whether unused global variables should be treated as a violation. allow-global-unused-variables=yes # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_, _cb # A regular expression matching the name of dummy variables (i.e. expected to # not be used). dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ # Argument names that match this expression will be ignored. Default to name # with leading underscore. ignored-argument-names=_.*|^ignored_|^unused_ # Tells whether we should check for unused import in __init__ files. init-import=no # List of qualified module names which can have objects that can redefine # builtins. redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io [FORMAT] # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format= # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' # Maximum number of characters on a single line. max-line-length=100 # Maximum number of lines in a module. max-module-lines=1000 # List of optional constructs for which whitespace checking is disabled. `dict- # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. # `trailing-comma` allows a space between comma and closing bracket: (a, ). # `empty-line` allows space-only lines. no-space-check=trailing-comma, dict-separator # Allow the body of a class to be on the same line as the declaration if body # contains single statement. single-line-class-stmt=no # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no [SIMILARITIES] # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no # Minimum lines number of a similarity. min-similarity-lines=4 [BASIC] # Naming style matching correct argument names. argument-naming-style=snake_case # Regular expression matching correct argument names. Overrides argument- # naming-style. #argument-rgx= # Naming style matching correct attribute names. attr-naming-style=snake_case # Regular expression matching correct attribute names. Overrides attr-naming- # style. #attr-rgx= # Bad variable names which should always be refused, separated by a comma. bad-names=foo, bar, baz, toto, tutu, tata # Naming style matching correct class attribute names. class-attribute-naming-style=any # Regular expression matching correct class attribute names. Overrides class- # attribute-naming-style. #class-attribute-rgx= # Naming style matching correct class names. class-naming-style=PascalCase # Regular expression matching correct class names. Overrides class-naming- # style. #class-rgx= # Naming style matching correct constant names. const-naming-style=UPPER_CASE # Regular expression matching correct constant names. Overrides const-naming- # style. #const-rgx= # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 # Naming style matching correct function names. function-naming-style=snake_case # Regular expression matching correct function names. Overrides function- # naming-style. #function-rgx= # Good variable names which should always be accepted, separated by a comma. good-names=i, j, k, ex, Run, _ # Include a hint for the correct naming format with invalid-name. include-naming-hint=no # Naming style matching correct inline iteration names. inlinevar-naming-style=any # Regular expression matching correct inline iteration names. Overrides # inlinevar-naming-style. #inlinevar-rgx= # Naming style matching correct method names. method-naming-style=snake_case # Regular expression matching correct method names. Overrides method-naming- # style. #method-rgx= # Naming style matching correct module names. module-naming-style=snake_case # Regular expression matching correct module names. Overrides module-naming- # style. #module-rgx= # Colon-delimited sets of names that determine each other's naming style when # the name regexes allow several styles. name-group= # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=^_ # List of decorators that produce properties, such as abc.abstractproperty. Add # to this list to register other decorators that produce valid properties. # These decorators are taken in consideration only for invalid-name. property-classes=abc.abstractproperty # Naming style matching correct variable names. variable-naming-style=snake_case # Regular expression matching correct variable names. Overrides variable- # naming-style. #variable-rgx= [IMPORTS] # Allow wildcard imports from modules that define __all__. allow-wildcard-with-all=no # Analyse import fallback blocks. This can be used to support both Python 2 and # 3 compatible code, which means that the block might have code that exists # only in one or another interpreter, leading to false positives when analysed. analyse-fallback-blocks=no # Deprecated modules which should not be used, separated by a comma. deprecated-modules=optparse,tkinter.tix # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled). ext-import-graph= # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled). import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled). int-import-graph= # Force import order to recognize a module as part of the standard # compatibility libraries. known-standard-library= # Force import order to recognize a module as part of a third party library. known-third-party=enchant [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__, __new__, setUp # List of member names, which should be excluded from the protected access # warning. exclude-protected=_asdict, _fields, _replace, _source, _make # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=cls [DESIGN] # Maximum number of arguments for function / method. max-args=5 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Maximum number of boolean expressions in an if statement. max-bool-expr=5 # Maximum number of branch for function / method body. max-branches=12 # Maximum number of locals for function / method body. max-locals=15 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of public methods for a class (see R0904). max-public-methods=20 # Maximum number of return / yield for function / method body. max-returns=6 # Maximum number of statements in function / method body. max-statements=50 # Minimum number of public methods for a class (see R0903). min-public-methods=2 [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception". overgeneral-exceptions=Exception ================================================ FILE: requirements.txt ================================================ astroid==2.0.4 atomicwrites==1.1.5 attrs==18.1.0 flake8==3.5.0 isort==4.3.4 lazy-object-proxy==1.3.1 mccabe==0.6.1 more-itertools==4.3.0 pluggy==0.7.1 py==1.5.4 pycodestyle==2.3.1 pyflakes==1.6.0 pylint==2.1.1 pytest==3.7.2 six==1.11.0 wrapt==1.10.11 ================================================ FILE: src/additions/test_generators.py ================================================ """Generators. @see: https://www.learnpython.org/en/Generators Generators are used to create iterators, but with a different approach. Generators are simple functions which return an iterable set of items, one at a time, in a special way. When an iteration over a set of item starts using the for statement, the generator is run. Once the generator's function code reaches a "yield" statement, the generator yields its execution back to the for loop, returning a new value from the set. The generator function can generate as many values (possibly infinite) as it wants, yielding each one in its turn. """ import random def lottery(): """Generator function example. Here is a simple example of a generator function which returns random integers. This function decides how to generate the random numbers on its own, and executes the yield statements one at a time, pausing in between to yield execution back to the main for loop. """ # returns first 3 random numbers between 1 and 10 # pylint: disable=unused-variable for _ in range(3): yield random.randint(1, 10) # returns a 4th number between 10 and 20 yield random.randint(10, 20) def test_generators(): """Yield statement""" for number_index, random_number in enumerate(lottery()): if number_index < 3: assert 0 <= random_number <= 10 else: assert 10 <= random_number <= 20 ================================================ FILE: src/additions/test_pass.py ================================================ """PASS statement @see: https://docs.python.org/3/tutorial/controlflow.html The pass statement does nothing. It can be used when a statement is required syntactically but the program requires no action. """ def test_pass_in_function(): """PASS statement in function "Pass" can be used as a place-holder for a function or conditional body when you are working on new code, allowing you to keep thinking at a more abstract level. The pass statement below is silently ignored but it makes current test_pass() function valid. """ pass def test_pass_in_loop(): """PASS in loops. "Pass" can be used when a statement is required syntactically but the program requires no action. For example: """ # pylint: disable=unused-variable for number in range(100): # It just don't do anything but for loop is still valid. pass # Example above is quite useless but it was given just for illustration of the idea. # The more useful example might be: # # while True: # pass # Busy-wait for keyboard interrupt (Ctrl+C) # pylint: disable=too-few-public-methods class MyEmptyClass: """PASS statement in class "Pass" is commonly used for creating minimal classes like current one. """ pass ================================================ FILE: src/classes/test_class_and_instance_variables.py ================================================ """Class and Instance Variables. @see: https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables Generally speaking, instance variables are for data unique to each instance and class variables are for attributes and methods shared by all instances of the class. """ def test_class_and_instance_variables(): """Class and Instance Variables.""" # pylint: disable=too-few-public-methods class Dog: """Dog class example""" kind = 'canine' # Class variable shared by all instances. def __init__(self, name): self.name = name # Instance variable unique to each instance. fido = Dog('Fido') buddy = Dog('Buddy') # Shared by all dogs. assert fido.kind == 'canine' assert buddy.kind == 'canine' # Unique to fido. assert fido.name == 'Fido' # Unique to buddy. assert buddy.name == 'Buddy' # Shared data can have possibly surprising effects with involving mutable objects such as lists # and dictionaries. For example, the tricks list in the following code should not be used as a # class variable because just a single list would be shared by all Dog instances. # pylint: disable=too-few-public-methods class DogWithSharedTricks: """Dog class example with wrong shared variable usage""" tricks = [] # Mistaken use of a class variable (see below) for mutable objects. def __init__(self, name): self.name = name # Instance variable unique to each instance. def add_trick(self, trick): """Add trick to the dog This function illustrate mistaken use of mutable class variable tricks (see below). """ self.tricks.append(trick) fido = DogWithSharedTricks('Fido') buddy = DogWithSharedTricks('Buddy') fido.add_trick('roll over') buddy.add_trick('play dead') assert fido.tricks == ['roll over', 'play dead'] # unexpectedly shared by all dogs assert buddy.tricks == ['roll over', 'play dead'] # unexpectedly shared by all dogs # Correct design of the class should use an instance variable instead: # pylint: disable=too-few-public-methods class DogWithTricks: """Dog class example""" def __init__(self, name): self.name = name # Instance variable unique to each instance. self.tricks = [] # creates a new empty list for each dog def add_trick(self, trick): """Add trick to the dog This function illustrate a correct use of mutable class variable tricks (see below). """ self.tricks.append(trick) fido = DogWithTricks('Fido') buddy = DogWithTricks('Buddy') fido.add_trick('roll over') buddy.add_trick('play dead') assert fido.tricks == ['roll over'] assert buddy.tricks == ['play dead'] ================================================ FILE: src/classes/test_class_definition.py ================================================ """Class Definition Syntax. @see: https://docs.python.org/3/tutorial/classes.html Python is an object oriented programming language. Almost everything in Python is an object, with its properties and methods. A Class is like an object constructor, or a "blueprint" for creating objects. """ def test_class_definition(): """Class definition.""" # Class definitions, like function definitions (def statements) must be executed before they # have any effect. (You could conceivably place a class definition in a branch of an if # statement, or inside a function.) class GreetingClass: """Example of the class definition This class contains two public methods and doesn't contain constructor. """ name = 'user' def say_hello(self): """Class method.""" # The self parameter is a reference to the class itself, and is used to access variables # that belongs to the class. It does not have to be named self , you can call it # whatever you like, but it has to be the first parameter of any function in the class. return 'Hello ' + self.name def say_goodbye(self): """Class method.""" return 'Goodbye ' + self.name # When a class definition is entered, a new namespace is created, and used as the local scope — # thus, all assignments to local variables go into this new namespace. In particular, function # definitions bind the name of the new function here. # Class instantiation uses function notation. Just pretend that the class object is a # parameterless function that returns a new instance of the class. For example the following # code will creates a new instance of the class and assigns this object to the local variable. greeter = GreetingClass() assert greeter.say_hello() == 'Hello user' assert greeter.say_goodbye() == 'Goodbye user' ================================================ FILE: src/classes/test_class_objects.py ================================================ """Class Definition Syntax. @see: https://docs.python.org/3/tutorial/classes.html#class-objects After defining the class attributes to a class, the class object can be created by assigning the object to a variable. The created object would have instance attributes associated with it. """ def test_class_objects(): """Class Objects. Class objects support two kinds of operations: - attribute references - instantiation. """ # ATTRIBUTE REFERENCES use the standard syntax used for all attribute references in # Python: obj.name. Valid attribute names are all the names that were in the class’s namespace # when the class object was created. For class MyCounter the following references are valid # attribute references: class ComplexNumber: """Example of the complex numbers class""" real = 0 imaginary = 0 def get_real(self): """Return real part of complex number.""" return self.real def get_imaginary(self): """Return imaginary part of complex number.""" return self.imaginary assert ComplexNumber.real == 0 # __doc__ is also a valid attribute, returning the docstring belonging to the class assert ComplexNumber.__doc__ == 'Example of the complex numbers class' # Class attributes can also be assigned to, so you can change the value of # ComplexNumber.counter by assignment. ComplexNumber.real = 10 assert ComplexNumber.real == 10 # CLASS INSTANTIATION uses function notation. Just pretend that the class object is a # parameterless function that returns a new instance of the class. For example # (assuming the above class): complex_number = ComplexNumber() assert complex_number.real == 10 assert complex_number.get_real() == 10 # Let's change counter default value back. ComplexNumber.real = 10 assert ComplexNumber.real == 10 # The instantiation operation (“calling” a class object) creates an empty object. Many classes # like to create objects with instances customized to a specific initial state. Therefore a # class may define a special method named __init__(), like this: class ComplexNumberWithConstructor: """Example of the class with constructor""" def __init__(self, real_part, imaginary_part): self.real = real_part self.imaginary = imaginary_part def get_real(self): """Return real part of complex number.""" return self.real def get_imaginary(self): """Return imaginary part of complex number.""" return self.imaginary complex_number = ComplexNumberWithConstructor(3.0, -4.5) assert complex_number.real, complex_number.imaginary == (3.0, -4.5) ================================================ FILE: src/classes/test_inheritance.py ================================================ """Inheritance @see: https://docs.python.org/3/tutorial/classes.html#inheritance Inheritance is one of the principles of object-oriented programming. Since classes may share a lot of the same code, inheritance allows a derived class to reuse the same code and modify accordingly """ # pylint: disable=too-few-public-methods class Person: """Example of the base class""" def __init__(self, name): self.name = name def get_name(self): """Get person name""" return self.name # The syntax for a derived class definition looks like this. # pylint: disable=too-few-public-methods class Employee(Person): """Example of the derived class The Base Class (in our case Person) must be defined in a scope containing the derived class definition. In place of a base class name, other arbitrary expressions are also allowed. Derived classes may override methods of their base classes. Because methods have no special privileges when calling other methods of the same object, a method of a base class that calls another method defined in the same base class may end up calling a method of a derived class that overrides it. An overriding method in a derived class may in fact want to extend rather than simply replace the base class method of the same name. There is a simple way to call the base class method directly: just call BaseClassName.methodname(self, arguments). This is occasionally useful to clients as well. (Note that this only works if the base class is accessible as BaseClassName in the global scope.) """ def __init__(self, name, staff_id): Person.__init__(self, name) # You may also use super() here in order to avoid explicit using of parent class name: # >>> super().__init__(name) self.staff_id = staff_id def get_full_id(self): """Get full employee id""" return self.get_name() + ', ' + self.staff_id def test_inheritance(): """Inheritance.""" # There’s nothing special about instantiation of derived classes: DerivedClassName() creates a # new instance of the class. Method references are resolved as follows: the corresponding class # attribute is searched, descending down the chain of base classes if necessary, and the method # reference is valid if this yields a function object. person = Person('Bill') employee = Employee('John', 'A23') assert person.get_name() == 'Bill' assert employee.get_name() == 'John' assert employee.get_full_id() == 'John, A23' # Python has two built-in functions that work with inheritance: # # - Use isinstance() to check an instance’s type: isinstance(obj, int) will be True only if # obj.__class__ is int or some class derived from int. # # - Use issubclass() to check class inheritance: issubclass(bool, int) is True since bool is # a subclass of int. However, issubclass(float, int) is False since float is not a subclass # of int. assert isinstance(employee, Employee) assert not isinstance(person, Employee) assert isinstance(person, Person) assert isinstance(employee, Person) assert issubclass(Employee, Person) assert not issubclass(Person, Employee) ================================================ FILE: src/classes/test_instance_objects.py ================================================ """Class Definition Syntax. @see: https://docs.python.org/3/tutorial/classes.html#instance-objects """ def test_instance_objects(): """Instance Objects. Now what can we do with instance objects? The only operations understood by instance objects are attribute references. There are two kinds of valid attribute names: - data attributes - methods. """ # DATA ATTRIBUTES need not be declared; like local variables, they spring into existence when # they are first assigned to. For example, if x is the instance of MyCounter created above, # the following piece of code will print the value 16, without leaving a trace. # pylint: disable=too-few-public-methods class DummyClass: """Dummy class""" pass dummy_instance = DummyClass() # pylint: disable=attribute-defined-outside-init dummy_instance.temporary_attribute = 1 assert dummy_instance.temporary_attribute == 1 del dummy_instance.temporary_attribute ================================================ FILE: src/classes/test_method_objects.py ================================================ """Class Definition Syntax. @see: https://docs.python.org/3/tutorial/classes.html#method-objects Classes can have two types of attribute references: data or methods. Class methods are called by [variable_name].[method_name]([parameters]) as opposed to class data which lacks the (). """ class MyCounter: """A simple example of the counter class""" counter = 10 def get_counter(self): """Return the counter""" return self.counter def increment_counter(self): """Increment the counter""" self.counter += 1 return self.counter def test_method_objects(): """Method Objects.""" # The other kind of instance attribute reference is a method. A method is a function that # “belongs to” an object. (In Python, the term method is not unique to class instances: other # object types can have methods as well. For example, list objects have methods called append, # insert, remove, sort, and so on. However, in the following discussion, we’ll use the term # method exclusively to mean methods of class instance objects, unless explicitly stated # otherwise.) # But be aware that counter.get_counter() is not the same thing as MyCounter.get_counter() — # it is a method object, not a function object. # Usually, a method is called right after it is bound counter = MyCounter() assert counter.get_counter() == 10 # However, it is not necessary to call a method right away: counter.get_counter() is a method # object, and can be stored away and called at a later time. For example: get_counter = counter.get_counter assert get_counter() == 10 # What exactly happens when a method is called? You may have noticed that counter.get_counter() # was called without an argument above, even though the function definition for get_counter() # specified an argument (self). What happened to the argument? Surely Python raises an # exception when a function that requires an argument is called without any — even if the # argument isn’t actually used… # Actually, you may have guessed the answer: the special thing about methods is that the # instance object is passed as the first argument of the function. In our example, the call # counter.get_counter() is exactly equivalent to MyCounter.get_counter(counter). In general, # calling a method with a list of n arguments is equivalent to calling the corresponding # function with an argument list that is created by inserting the method’s instance object # before the first argument. assert counter.get_counter() == 10 assert MyCounter.get_counter(counter) == 10 ================================================ FILE: src/classes/test_multiple_inheritance.py ================================================ """Multiple Inheritance @see: https://docs.python.org/3/tutorial/classes.html#multiple-inheritance Some classes may derive from multiple classes. This means that the derived class would have its attributes, along with the attributes of all the classes that it was derived from. """ def test_multiple_inheritance(): """Multiple Inheritance""" # pylint: disable=too-few-public-methods class Clock: """Clock class""" time = '11:23 PM' def get_time(self): """Get current time Method is hardcoded just for multiple inheritance illustration. """ return self.time # pylint: disable=too-few-public-methods class Calendar: """Calendar class""" date = '12/08/2018' def get_date(self): """Get current date Method is hardcoded just for multiple inheritance illustration. """ return self.date # Python supports a form of multiple inheritance as well. A class definition with multiple # base classes looks like this. class CalendarClock(Clock, Calendar): """Class that uses multiple inheritance. For most purposes, in the simplest cases, you can think of the search for attributes inherited from a parent class as depth-first, left-to-right, not searching twice in the same class where there is an overlap in the hierarchy. Thus, if an attribute is not found in CalendarClock, it is searched for in Clock, then (recursively) in the base classes of Clock, and if it was not found there, it was searched for in Calendar, and so on. In fact, it is slightly more complex than that; the method resolution order changes dynamically to support cooperative calls to super(). This approach is known in some other multiple-inheritance languages as call-next-method and is more powerful than the super call found in single-inheritance languages. Dynamic ordering is necessary because all cases of multiple inheritance exhibit one or more diamond relationships (where at least one of the parent classes can be accessed through multiple paths from the bottommost class). For example, all classes inherit from object, so any case of multiple inheritance provides more than one path to reach object. To keep the base classes from being accessed more than once, the dynamic algorithm linearizes the search order in a way that preserves the left-to-right ordering specified in each class, that calls each parent only once, and that is monotonic (meaning that a class can be subclassed without affecting the precedence order of its parents). """ calendar_clock = CalendarClock() assert calendar_clock.get_date() == '12/08/2018' assert calendar_clock.get_time() == '11:23 PM' ================================================ FILE: src/control_flow/test_break.py ================================================ """BREAK statement @see: https://docs.python.org/3/tutorial/controlflow.html The break statement, like in C, breaks out of the innermost enclosing "for" or "while" loop. """ def test_break_statement(): """BREAK statement""" # Let's terminate the loop in case if we've found the number we need in a range from 0 to 100. number_to_be_found = 42 # This variable will record how many time we've entered the "for" loop. number_of_iterations = 0 for number in range(100): if number == number_to_be_found: # Break here and don't continue the loop. break else: number_of_iterations += 1 # We need to make sure that break statement has terminated the loop once it found the number. assert number_of_iterations == 42 ================================================ FILE: src/control_flow/test_continue.py ================================================ """CONTINUE statement @see: https://docs.python.org/3/tutorial/controlflow.html The continue statement is borrowed from C, continues with the next iteration of the loop. """ def test_continue_statement(): """CONTINUE statement in FOR loop""" # Let's # This list will contain only even numbers from the range. even_numbers = [] # This list will contain every other numbers (in this case - ods). rest_of_the_numbers = [] for number in range(0, 10): # Check if remainder after division is zero (which would mean that number is even). if number % 2 == 0: even_numbers.append(number) # Stop current loop iteration and go to the next one immediately. continue rest_of_the_numbers.append(number) assert even_numbers == [0, 2, 4, 6, 8] assert rest_of_the_numbers == [1, 3, 5, 7, 9] ================================================ FILE: src/control_flow/test_for.py ================================================ """FOR statement @see: https://docs.python.org/3/tutorial/controlflow.html The for statement in Python differs a bit from what you may be used to in C or Pascal. Rather than always iterating over an arithmetic progression of numbers (like in Pascal), or giving the user the ability to define both the iteration step and halting condition (as C), Python’s for statement iterates over the items of any sequence (a list or a string), in the order that they appear in the sequence. For example (no pun intended): """ # pylint: disable=too-many-locals def test_for_statement(): """FOR statement""" # Measure some strings: words = ['cat', 'window', 'defenestrate'] words_length = 0 for word in words: words_length += len(word) # "cat" length is 3 # "window" length is 6 # "defenestrate" length is 12 assert words_length == (3 + 6 + 12) # If you need to modify the sequence you are iterating over while inside the loop # (for example to duplicate selected items), it is recommended that you first make a copy. # Iterating over a sequence does not implicitly make a copy. The slice notation makes this # especially convenient: for word in words[:]: # Loop over a slice copy of the entire list. if len(word) > 6: words.insert(0, word) # Otherwise with for w in words:, the example would attempt to create an infinite list, # inserting defenestrate over and over again. assert words == ['defenestrate', 'cat', 'window', 'defenestrate'] # If you do need to iterate over a sequence of numbers, the built-in function range() comes in # handy. It generates arithmetic progressions: iterated_numbers = [] for number in range(5): iterated_numbers.append(number) assert iterated_numbers == [0, 1, 2, 3, 4] # To iterate over the indices of a sequence, you can combine range() and len() as follows: words = ['Mary', 'had', 'a', 'little', 'lamb'] concatenated_string = '' # pylint: disable=consider-using-enumerate for word_index in range(len(words)): concatenated_string += words[word_index] + ' ' assert concatenated_string == 'Mary had a little lamb ' # Or simply use enumerate(). concatenated_string = '' for word_index, word in enumerate(words): concatenated_string += word + ' ' assert concatenated_string == 'Mary had a little lamb ' # When looping through dictionaries, the key and corresponding value can be retrieved at the # same time using the items() method. knights_names = [] knights_properties = [] knights = {'gallahad': 'the pure', 'robin': 'the brave'} for key, value in knights.items(): knights_names.append(key) knights_properties.append(value) assert knights_names == ['gallahad', 'robin'] assert knights_properties == ['the pure', 'the brave'] # When looping through a sequence, the position index and corresponding value can be retrieved # at the same time using the enumerate() function indices = [] values = [] for index, value in enumerate(['tic', 'tac', 'toe']): indices.append(index) values.append(value) assert indices == [0, 1, 2] assert values == ['tic', 'tac', 'toe'] # To loop over two or more sequences at the same time, the entries can be paired with # the zip() function. questions = ['name', 'quest', 'favorite color'] answers = ['lancelot', 'the holy grail', 'blue'] combinations = [] for question, answer in zip(questions, answers): combinations.append('What is your {0}? It is {1}.'.format(question, answer)) assert combinations == [ 'What is your name? It is lancelot.', 'What is your quest? It is the holy grail.', 'What is your favorite color? It is blue.', ] def test_range_function(): """Range function If you do need to iterate over a sequence of numbers, the built-in function range() comes in handy. It generates arithmetic progressions. In many ways the object returned by range() behaves as if it is a list, but in fact it isn’t. It is an object which returns the successive items of the desired sequence when you iterate over it, but it doesn’t really make the list, thus saving space. We say such an object is iterable, that is, suitable as a target for functions and constructs that expect something from which they can obtain successive items until the supply is exhausted. We have seen that the for statement is such an iterator. The function list() is another; it creates lists from iterables: """ assert list(range(5)) == [0, 1, 2, 3, 4] # The given end point is never part of the generated sequence; range(10) generates 10 values, # the legal indices for items of a sequence of length 10. It is possible to let the range start # at another number, or to specify a different increment (even negative; sometimes this is # called the ‘step’): assert list(range(5, 10)) == [5, 6, 7, 8, 9] assert list(range(0, 10, 3)) == [0, 3, 6, 9] assert list(range(-10, -100, -30)) == [-10, -40, -70] ================================================ FILE: src/control_flow/test_if.py ================================================ """IF statement @see: https://docs.python.org/3/tutorial/controlflow.html There can be zero or more elif parts, and the else part is optional. The keyword ‘elif’ is short for ‘else if’, and is useful to avoid excessive indentation. An if … elif … elif … sequence is a substitute for the switch or case statements found in other languages. """ def test_if_statement(): """IF statement""" number = 15 conclusion = '' if number < 0: conclusion = 'Number is less than zero' elif number == 0: conclusion = 'Number equals to zero' elif number < 1: conclusion = 'Number is greater than zero but less than one' else: conclusion = 'Number bigger than or equal to one' assert conclusion == 'Number bigger than or equal to one' ================================================ FILE: src/control_flow/test_try.py ================================================ """TRY statement @see: https://www.w3schools.com/python/python_try_except.asp "try" statement is used for exception handling. When an error occurs, or exception as we call it, Python will normally stop and generate an error message. These exceptions can be handled using the try statement. The "try" block lets you test a block of code for errors. The "except" block lets you handle the error. The "else" block lets you execute the code if no errors were raised. The "finally" block lets you execute code, regardless of the result of the try- and except blocks. """ def test_try(): """TRY statement""" # The try block will generate an error, because x is not defined: exception_has_been_caught = False try: # pylint: disable=undefined-variable print(not_existing_variable) except NameError: exception_has_been_caught = True assert exception_has_been_caught # You can define as many exception blocks as you want, e.g. if you want to execute a special # block of code for a special kind of error: exception_message = '' try: # pylint: disable=undefined-variable print(not_existing_variable) except NameError: exception_message = 'Variable is not defined' assert exception_message == 'Variable is not defined' # You can use the else keyword to define a block of code to be executed # if no errors were raised. message = '' # pylint: disable=broad-except try: message += 'Success.' except NameError: message += 'Something went wrong.' else: message += 'Nothing went wrong.' assert message == 'Success.Nothing went wrong.' # The finally block, if specified, will be executed regardless if the try block raises an # error or not. message = '' try: # pylint: undefined-variable print(not_existing_variable) # noqa: F821 except NameError: message += 'Something went wrong.' finally: message += 'The "try except" is finished.' assert message == 'Something went wrong.The "try except" is finished.' ================================================ FILE: src/control_flow/test_while.py ================================================ """WHILE statement @see: https://docs.python.org/3/tutorial/controlflow.html @see: https://docs.python.org/3/reference/compound_stmts.html#the-while-statement The while loop executes as long as the condition remains true. In Python, like in C, any non-zero integer value is true; zero is false. The condition may also be a string or list value, in fact any sequence; anything with a non-zero length is true, empty sequences are false. The test used in the example is a simple comparison. The standard comparison operators are written the same as in C: < (less than), > (greater than), == (equal to), <= (less than or equal to), >= (greater than or equal to) and != (not equal to). """ def test_while_statement(): """WHILE statement""" # Let's raise the number to certain power using while loop. number = 2 power = 5 result = 1 while power > 0: result *= number power -= 1 # 2^5 = 32 assert result == 32 ================================================ FILE: src/data_types/test_dictionaries.py ================================================ """Dictionaries. @see: https://docs.python.org/3/tutorial/datastructures.html#dictionaries @see: https://www.w3schools.com/python/python_dictionaries.asp A dictionary is a collection which is unordered, changeable and indexed. In Python dictionaries are written with curly brackets, and they have keys and values. Dictionaries are sometimes found in other languages as “associative memories” or “associative arrays”. Unlike sequences, which are indexed by a range of numbers, dictionaries are indexed by keys, which can be any immutable type; strings and numbers can always be keys. Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key. You can’t use lists as keys, since lists can be modified in place using index assignments, slice assignments, or methods like append() and extend(). It is best to think of a dictionary as a set of key: value pairs, with the requirement that the keys are unique (within one dictionary). A pair of braces creates an empty dictionary: {}. Placing a comma-separated list of key:value pairs within the braces adds initial key:value pairs to the dictionary; this is also the way dictionaries are written on output. """ def test_dictionary(): """Dictionary""" fruits_dictionary = { 'cherry': 'red', 'apple': 'green', 'banana': 'yellow', } assert isinstance(fruits_dictionary, dict) # You may access set elements by keys. assert fruits_dictionary['apple'] == 'green' assert fruits_dictionary['banana'] == 'yellow' assert fruits_dictionary['cherry'] == 'red' # To check whether a single key is in the dictionary, use the in keyword. assert 'apple' in fruits_dictionary assert 'pineapple' not in fruits_dictionary # Change the apple color to "red". fruits_dictionary['apple'] = 'red' # Add new key/value pair to the dictionary fruits_dictionary['pineapple'] = 'yellow' assert fruits_dictionary['pineapple'] == 'yellow' # Performing list(d) on a dictionary returns a list of all the keys used in the dictionary, # in insertion order (if you want it sorted, just use sorted(d) instead). assert list(fruits_dictionary) == ['cherry', 'apple', 'banana', 'pineapple'] assert sorted(fruits_dictionary) == ['apple', 'banana', 'cherry', 'pineapple'] # It is also possible to delete a key:value pair with del. del fruits_dictionary['pineapple'] assert list(fruits_dictionary) == ['cherry', 'apple', 'banana'] # The dict() constructor builds dictionaries directly from sequences of key-value pairs. dictionary_via_constructor = dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) assert dictionary_via_constructor['sape'] == 4139 assert dictionary_via_constructor['guido'] == 4127 assert dictionary_via_constructor['jack'] == 4098 # In addition, dict comprehensions can be used to create dictionaries from arbitrary key # and value expressions: dictionary_via_expression = {x: x**2 for x in (2, 4, 6)} assert dictionary_via_expression[2] == 4 assert dictionary_via_expression[4] == 16 assert dictionary_via_expression[6] == 36 # When the keys are simple strings, it is sometimes easier to specify pairs using # keyword arguments. dictionary_for_string_keys = dict(sape=4139, guido=4127, jack=4098) assert dictionary_for_string_keys['sape'] == 4139 assert dictionary_for_string_keys['guido'] == 4127 assert dictionary_for_string_keys['jack'] == 4098 ================================================ FILE: src/data_types/test_lists.py ================================================ """Lists. # @see: https://www.learnpython.org/en/Lists # @see: https://docs.python.org/3/tutorial/introduction.html # @ee: https://docs.python.org/3/tutorial/datastructures.html#more-on-lists Python knows a number of compound data types, used to group together other values. The most versatile is the list, which can be written as a list of comma-separated values (items) between square brackets. Lists might contain items of different types, but usually the items all have the same type. """ import pytest def test_list_type(): """List type.""" # Lists are very similar to arrays. They can contain any type of variable, and they can contain # as many variables as you wish. Lists can also be iterated over in a very simple manner. # Here is an example of how to build a list. squares = [1, 4, 9, 16, 25] assert isinstance(squares, list) # Like strings (and all other built-in sequence type), lists can be # indexed and sliced: assert squares[0] == 1 # indexing returns the item assert squares[-1] == 25 assert squares[-3:] == [9, 16, 25] # slicing returns a new list # All slice operations return a new list containing the requested elements. # This means that the following slice returns a new (shallow) copy of # the list: assert squares[:] == [1, 4, 9, 16, 25] # Lists also support operations like concatenation: assert squares + [36, 49, 64, 81, 100] == [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] # Unlike strings, which are immutable, lists are a mutable type, i.e. it # is possible to change their content: cubes = [1, 8, 27, 65, 125] # something's wrong here, the cube of 4 is 64! cubes[3] = 64 # replace the wrong value assert cubes == [1, 8, 27, 64, 125] # You can also add new items at the end of the list, by using # the append() method cubes.append(216) # add the cube of 6 cubes.append(7 ** 3) # and the cube of 7 assert cubes == [1, 8, 27, 64, 125, 216, 343] # Assignment to slices is also possible, and this can even change the size # of the list or clear it entirely: letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] letters[2:5] = ['C', 'D', 'E'] # replace some values assert letters == ['a', 'b', 'C', 'D', 'E', 'f', 'g'] letters[2:5] = [] # now remove them assert letters == ['a', 'b', 'f', 'g'] # clear the list by replacing all the elements with an empty list letters[:] = [] assert letters == [] # The built-in function len() also applies to lists letters = ['a', 'b', 'c', 'd'] assert len(letters) == 4 # It is possible to nest lists (create lists containing other lists), # for example: list_of_chars = ['a', 'b', 'c'] list_of_numbers = [1, 2, 3] mixed_list = [list_of_chars, list_of_numbers] assert mixed_list == [['a', 'b', 'c'], [1, 2, 3]] assert mixed_list[0] == ['a', 'b', 'c'] assert mixed_list[0][1] == 'b' def test_list_methods(): """Test list methods.""" fruits = ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana'] # list.append(x) # Add an item to the end of the list. # Equivalent to a[len(a):] = [x]. fruits.append('grape') assert fruits == ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana', 'grape'] # list.remove(x) # Remove the first item from the list whose value is equal to x. # It raises a ValueError if there is no such item. fruits.remove('grape') assert fruits == ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana'] with pytest.raises(Exception): fruits.remove('not existing element') # list.insert(i, x) # Insert an item at a given position. The first argument is the index of the element # before which to insert, so a.insert(0, x) inserts at the front of the list, # and a.insert(len(a), x) is equivalent to a.append(x). fruits.insert(0, 'grape') assert fruits == ['grape', 'orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana'] # list.index(x[, start[, end]]) # Return zero-based index in the list of the first item whose value is equal to x. # Raises a ValueError if there is no such item. # The optional arguments start and end are interpreted as in the slice notation and are used # to limit the search to a particular subsequence of the list. The returned index is computed # relative to the beginning of the full sequence rather than the start argument. assert fruits.index('grape') == 0 assert fruits.index('orange') == 1 assert fruits.index('banana') == 4 assert fruits.index('banana', 5) == 7 # Find next banana starting a position 5 with pytest.raises(Exception): fruits.index('not existing element') # list.count(x) # Return the number of times x appears in the list. assert fruits.count('tangerine') == 0 assert fruits.count('banana') == 2 # list.copy() # Return a shallow copy of the list. Equivalent to a[:]. fruits_copy = fruits.copy() assert fruits_copy == ['grape', 'orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana'] # list.reverse() # Reverse the elements of the list in place. fruits_copy.reverse() assert fruits_copy == [ 'banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange', 'grape', ] # list.sort(key=None, reverse=False) # Sort the items of the list in place (the arguments can be used for sort customization, # see sorted() for their explanation). fruits_copy.sort() assert fruits_copy == [ 'apple', 'apple', 'banana', 'banana', 'grape', 'kiwi', 'orange', 'pear', ] # list.pop([i]) # Remove the item at the given position in the list, and return it. If no index is specified, # a.pop() removes and returns the last item in the list. (The square brackets around the i in # the method signature denote that the parameter is optional, not that you should type square # brackets at that position.) assert fruits == ['grape', 'orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana'] assert fruits.pop() == 'banana' assert fruits == ['grape', 'orange', 'apple', 'pear', 'banana', 'kiwi', 'apple'] # list.clear() # Remove all items from the list. Equivalent to del a[:]. fruits.clear() assert fruits == [] def test_del_statement(): """The del statement There is a way to remove an item from a list given its index instead of its value: the del statement. This differs from the pop() method which returns a value. The del statement can also be used to remove slices from a list or clear the entire list (which we did earlier by assignment of an empty list to the slice). """ numbers = [-1, 1, 66.25, 333, 333, 1234.5] del numbers[0] assert numbers == [1, 66.25, 333, 333, 1234.5] del numbers[2:4] assert numbers == [1, 66.25, 1234.5] del numbers[:] assert numbers == [] # del can also be used to delete entire variables: del numbers with pytest.raises(Exception): # Referencing the name a hereafter is an error (at least until another # value is assigned to it). assert numbers == [] # noqa: F821 def test_list_comprehensions(): """List Comprehensions. List comprehensions provide a concise way to create lists. Common applications are to make new lists where each element is the result of some operations applied to each member of another sequence or iterable, or to create a subsequence of those elements that satisfy a certain condition. A list comprehension consists of brackets containing an expression followed by a for clause, then zero or more for or if clauses. The result will be a new list resulting from evaluating the expression in the context of the for and if clauses which follow it. """ # For example, assume we want to create a list of squares, like: squares = [] for number in range(10): squares.append(number ** 2) assert squares == [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # Note that this creates (or overwrites) a variable named "number" that still exists after # the loop completes. We can calculate the list of squares without any side effects using: squares = list(map(lambda x: x ** 2, range(10))) assert squares == [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # or, equivalently (which is more concise and readable): squares = [x ** 2 for x in range(10)] assert squares == [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # For example, this listcomp combines the elements of two lists if they are not equal. combinations = [(x, y) for x in [1, 2, 3] for y in [3, 1, 4] if x != y] assert combinations == [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)] # and it’s equivalent to: combinations = [] for first_number in [1, 2, 3]: for second_number in [3, 1, 4]: if first_number != second_number: combinations.append((first_number, second_number)) assert combinations == [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)] # Note how the order of the for and if statements is the same in both these snippets. # If the expression is a tuple (e.g. the (x, y) in the previous example), # it must be parenthesized. # Let's see some more examples: vector = [-4, -2, 0, 2, 4] # Create a new list with the values doubled. doubled_vector = [x * 2 for x in vector] assert doubled_vector == [-8, -4, 0, 4, 8] # Filter the list to exclude negative numbers. positive_vector = [x for x in vector if x >= 0] assert positive_vector == [0, 2, 4] # Apply a function to all the elements. abs_vector = [abs(x) for x in vector] assert abs_vector == [4, 2, 0, 2, 4] # Call a method on each element. fresh_fruit = [' banana', ' loganberry ', 'passion fruit '] clean_fresh_fruit = [weapon.strip() for weapon in fresh_fruit] assert clean_fresh_fruit == ['banana', 'loganberry', 'passion fruit'] # Create a list of 2-tuples like (number, square). square_tuples = [(x, x ** 2) for x in range(6)] assert square_tuples == [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)] # Flatten a list using a listcomp with two 'for'. vector = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] flatten_vector = [num for elem in vector for num in elem] assert flatten_vector == [1, 2, 3, 4, 5, 6, 7, 8, 9] def test_nested_list_comprehensions(): """Nested List Comprehensions The initial expression in a list comprehension can be any arbitrary expression, including another list comprehension. """ # Consider the following example of a 3x4 matrix implemented as a list of 3 lists of length 4: matrix = [ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], ] # The following list comprehension will transpose rows and columns: transposed_matrix = [[row[i] for row in matrix] for i in range(4)] assert transposed_matrix == [ [1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12], ] # As we saw in the previous section, the nested listcomp is evaluated in the context of the # for that follows it, so this example is equivalent to: transposed = [] for i in range(4): transposed.append([row[i] for row in matrix]) assert transposed == [ [1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12], ] # which, in turn, is the same as: transposed = [] for i in range(4): # the following 3 lines implement the nested listcomp transposed_row = [] for row in matrix: transposed_row.append(row[i]) transposed.append(transposed_row) assert transposed == [ [1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12], ] # In the real world, you should prefer built-in functions to complex flow statements. # The zip() function would do a great job for this use case: assert list(zip(*matrix)) == [ (1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12), ] ================================================ FILE: src/data_types/test_numbers.py ================================================ """Numbers. @see: https://docs.python.org/3/tutorial/introduction.html @see: https://www.w3schools.com/python/python_numbers.asp There are three numeric types in Python: - int (e.g. 2, 4, 20) - bool (e.g. False and True, acting like 0 and 1) - float (e.g. 5.0, 1.6) - complex (e.g. 5+6j, 4-3j) """ def test_integer_numbers(): """Integer type Int, or integer, is a whole number, positive or negative, without decimals, of unlimited length. """ positive_integer = 1 negative_integer = -3255522 big_integer = 35656222554887711 assert isinstance(positive_integer, int) assert isinstance(negative_integer, int) assert isinstance(big_integer, int) def test_booleans(): """Boolean Booleans represent the truth values False and True. The two objects representing the values False and True are the only Boolean objects. The Boolean type is a subtype of the integer type, and Boolean values behave like the values 0 and 1, respectively, in almost all contexts, the exception being that when converted to a string, the strings "False" or "True" are returned, respectively. """ true_boolean = True false_boolean = False assert true_boolean assert not false_boolean assert isinstance(true_boolean, bool) assert isinstance(false_boolean, bool) # Let's try to cast boolean to string. assert str(true_boolean) == "True" assert str(false_boolean) == "False" def test_float_numbers(): """Float type Float, or "floating point number" is a number, positive or negative, containing one or more decimals. """ float_number = 7.0 # Another way of declaring float is using float() function. float_number_via_function = float(7) float_negative = -35.59 assert float_number == float_number_via_function assert isinstance(float_number, float) assert isinstance(float_number_via_function, float) assert isinstance(float_negative, float) # Float can also be scientific numbers with an "e" to indicate # the power of 10. float_with_small_e = 35e3 float_with_big_e = 12E4 assert float_with_small_e == 35000 assert float_with_big_e == 120000 assert isinstance(12E4, float) assert isinstance(-87.7e100, float) def test_complex_numbers(): """Complex Type""" complex_number_1 = 5 + 6j complex_number_2 = 3 - 2j assert isinstance(complex_number_1, complex) assert isinstance(complex_number_2, complex) assert complex_number_1 * complex_number_2 == 27 + 8j def test_number_operators(): """Basic operations""" # Addition. assert 2 + 4 == 6 # Multiplication. assert 2 * 4 == 8 # Division always returns a floating point number. assert 12 / 3 == 4.0 assert 12 / 5 == 2.4 assert 17 / 3 == 5.666666666666667 # Modulo operator returns the remainder of the division. assert 12 % 3 == 0 assert 13 % 3 == 1 # Floor division discards the fractional part. assert 17 // 3 == 5 # Raising the number to specific power. assert 5 ** 2 == 25 # 5 squared assert 2 ** 7 == 128 # 2 to the power of 7 # There is full support for floating point; operators with # mixed type operands convert the integer operand to floating point. assert 4 * 3.75 - 1 == 14.0 ================================================ FILE: src/data_types/test_sets.py ================================================ """Sets. @see: https://www.w3schools.com/python/python_sets.asp @see: https://docs.python.org/3.7/tutorial/datastructures.html#sets A set is a collection which is unordered and unindexed. In Python sets are written with curly brackets. Set objects also support mathematical operations like union, intersection, difference, and symmetric difference. """ def test_sets(): """Sets""" fruits_set = {"apple", "banana", "cherry"} assert isinstance(fruits_set, set) # It is also possible to use the set() constructor to make a set. # Note the double round-brackets fruits_set_via_constructor = set(("apple", "banana", "cherry")) assert isinstance(fruits_set_via_constructor, set) def test_set_methods(): """Set methods""" fruits_set = {"apple", "banana", "cherry"} # You may check if the item is in set by using "in" statement assert "apple" in fruits_set assert "pineapple" not in fruits_set # Use the len() method to return the number of items. assert len(fruits_set) == 3 # You can use the add() object method to add an item. fruits_set.add("pineapple") assert "pineapple" in fruits_set assert len(fruits_set) == 4 # Use remove() method to remove an item. fruits_set.remove("pineapple") assert "pineapple" not in fruits_set assert len(fruits_set) == 3 # Demonstrate set operations on unique letters from two word: first_char_set = set('abracadabra') second_char_set = set('alacazam') assert first_char_set == {'a', 'r', 'b', 'c', 'd'} # unique letters in first word assert second_char_set == {'a', 'l', 'c', 'z', 'm'} # unique letters in second word # Letters in first word but not in second. assert first_char_set - second_char_set == {'r', 'b', 'd'} # Letters in first word or second word or both. assert first_char_set | second_char_set == {'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'} # Common letters in both words. assert first_char_set & second_char_set == {'a', 'c'} # Letters in first or second word but not both. assert first_char_set ^ second_char_set == {'r', 'd', 'b', 'm', 'z', 'l'} # Similarly to list comprehensions, set comprehensions are also supported: word = {char for char in 'abracadabra' if char not in 'abc'} assert word == {'r', 'd'} ================================================ FILE: src/data_types/test_strings.py ================================================ """Strings. @see: https://docs.python.org/3/tutorial/introduction.html @see: https://www.w3schools.com/python/python_strings.asp @see: https://www.w3schools.com/python/python_ref_string.asp Besides numbers, Python can also manipulate strings, which can be expressed in several ways. They can be enclosed in single quotes ('...') or double quotes ("...") with the same result. """ import pytest def test_string_type(): """String type""" # String with double quotes. name_1 = "John" # String with single quotes. name_2 = 'John' # Strings created with different kind of quotes are treated the same. assert name_1 == name_2 assert isinstance(name_1, str) assert isinstance(name_2, str) # \ can be used to escape quotes. # use \' to escape the single quote or use double quotes instead. single_quote_string = 'doesn\'t' double_quote_string = "doesn't" assert single_quote_string == double_quote_string # \n means newline. multiline_string = 'First line.\nSecond line.' # Without print(), \n is included in the output. # But with print(), \n produces a new line. assert multiline_string == 'First line.\nSecond line.' # Strings can be indexed, with the first character having index 0. # There is no separate character type; a character is simply a string # of size one. Note that since -0 is the same as 0, negative indices # start from -1. word = 'Python' assert word[0] == 'P' # First character. assert word[5] == 'n' # Fifth character. assert word[-1] == 'n' # Last character. assert word[-2] == 'o' # Second-last character. assert word[-6] == 'P' # Sixth from the end or zeroth from the beginning. assert isinstance(word[0], str) # In addition to indexing, slicing is also supported. While indexing is # used to obtain individual characters, slicing allows you to obtain # substring: assert word[0:2] == 'Py' # Characters from position 0 (included) to 2 (excluded). assert word[2:5] == 'tho' # Characters from position 2 (included) to 5 (excluded). # Note how the start is always included, and the end always excluded. # This makes sure that s[:i] + s[i:] is always equal to s: assert word[:2] + word[2:] == 'Python' assert word[:4] + word[4:] == 'Python' # Slice indices have useful defaults; an omitted first index defaults to # zero, an omitted second index defaults to the size of the string being # sliced. assert word[:2] == 'Py' # Character from the beginning to position 2 (excluded). assert word[4:] == 'on' # Characters from position 4 (included) to the end. assert word[-2:] == 'on' # Characters from the second-last (included) to the end. # One way to remember how slices work is to think of the indices as # pointing between characters, with the left edge of the first character # numbered 0. Then the right edge of the last character of a string of n # characters has index n, for example: # # +---+---+---+---+---+---+ # | P | y | t | h | o | n | # +---+---+---+---+---+---+ # 0 1 2 3 4 5 6 # -6 -5 -4 -3 -2 -1 # Attempting to use an index that is too large will result in an error. with pytest.raises(Exception): not_existing_character = word[42] assert not not_existing_character # However, out of range slice indexes are handled gracefully when used # for slicing: assert word[4:42] == 'on' assert word[42:] == '' # Python strings cannot be changed — they are immutable. Therefore, # assigning to an indexed position in the string # results in an error: with pytest.raises(Exception): # pylint: disable=unsupported-assignment-operation word[0] = 'J' # If you need a different string, you should create a new one: assert 'J' + word[1:] == 'Jython' assert word[:2] + 'py' == 'Pypy' # The built-in function len() returns the length of a string: characters = 'supercalifragilisticexpialidocious' assert len(characters) == 34 # String literals can span multiple lines. One way is using triple-quotes: """...""" # or '''...'''. End of lines are automatically included in the string, but it’s possible # to prevent this by adding a \ at the end of the line. The following example: multi_line_string = '''\ First line Second line ''' assert multi_line_string == '''\ First line Second line ''' def test_string_operators(): """Basic operations Strings can be concatenated (glued together) with the + operator, and repeated with *: 3 times 'un', followed by 'ium' """ assert 3 * 'un' + 'ium' == 'unununium' # 'Py' 'thon' python = 'Py' 'thon' assert python == 'Python' # This feature is particularly useful when you want to break long strings: text = ( 'Put several strings within parentheses ' 'to have them joined together.' ) assert text == 'Put several strings within parentheses to have them joined together.' # If you want to concatenate variables or a variable and a literal, use +: prefix = 'Py' assert prefix + 'thon' == 'Python' def test_string_methods(): """String methods""" hello_world_string = "Hello, World!" # The strip() method removes any whitespace from the beginning or the end. string_with_whitespaces = " Hello, World! " assert string_with_whitespaces.strip() == "Hello, World!" # The len() method returns the length of a string. assert len(hello_world_string) == 13 # The lower() method returns the string in lower case. assert hello_world_string.lower() == 'hello, world!' # The upper() method returns the string in upper case. assert hello_world_string.upper() == 'HELLO, WORLD!' # The replace() method replaces a string with another string. assert hello_world_string.replace('H', 'J') == 'Jello, World!' # The split() method splits the string into substrings if it finds instances of the separator. assert hello_world_string.split(',') == ['Hello', ' World!'] # Converts the first character to upper case assert 'low letter at the beginning'.capitalize() == 'Low letter at the beginning' # Returns the number of times a specified value occurs in a string. assert 'low letter at the beginning'.count('t') == 4 # Searches the string for a specified value and returns the position of where it was found. assert 'Hello, welcome to my world'.find('welcome') == 7 # Converts the first character of each word to upper case assert 'Welcome to my world'.title() == 'Welcome To My World' # Returns a string where a specified value is replaced with a specified value. assert 'I like bananas'.replace('bananas', 'apples') == 'I like apples' # Joins the elements of an iterable to the end of the string. my_tuple = ('John', 'Peter', 'Vicky') assert ', '.join(my_tuple) == 'John, Peter, Vicky' # Returns True if all characters in the string are upper case. assert 'ABC'.isupper() assert not 'AbC'.isupper() # Check if all the characters in the text are letters. assert 'CompanyX'.isalpha() assert not 'Company 23'.isalpha() # Returns True if all characters in the string are decimals. assert '1234'.isdecimal() assert not 'a21453'.isdecimal() def test_string_formatting(): """String formatting. Often you’ll want more control over the formatting of your output than simply printing space-separated values. There are several ways to format output """ # To use formatted string literals, begin a string with f or F before the opening quotation # mark or triple quotation mark. Inside this string, you can write a Python expression # between { and } characters that can refer to variables or literal values. year = 2018 event = 'conference' assert f'Results of the {year} {event}' == 'Results of the 2018 conference' # The str.format() method of strings requires more manual effort. You’ll still use { and } to # mark where a variable will be substituted and can provide detailed formatting directives, # but you’ll also need to provide the information to be formatted. yes_votes = 42_572_654 # equivalent of 42572654 no_votes = 43_132_495 # equivalent of 43132495 percentage = yes_votes / (yes_votes + no_votes) assert '{:-9} YES votes {:2.2%}'.format(yes_votes, percentage) == ' 42572654 YES votes 49.67%' # When you don’t need fancy output but just want a quick display of some variables for debugging # purposes, you can convert any value to a string with the repr() or str() functions. The str() # function is meant to return representations of values which are fairly human-readable, while # repr() is meant to generate representations which can be read by the interpreter (or will # force a SyntaxError if there is no equivalent syntax). For objects which don’t have a # particular representation for human consumption, str() will return the same value as repr(). # Many values, such as numbers or structures like lists and dictionaries, have the same # representation using either function. Strings, in particular, have two distinct # representations. greeting = 'Hello, world.' first_num = 10 * 3.25 second_num = 200 * 200 assert str(greeting) == 'Hello, world.' assert repr(greeting) == "'Hello, world.'" assert str(1/7) == '0.14285714285714285' # The argument to repr() may be any Python object: assert repr((first_num, second_num, ('spam', 'eggs'))) == "(32.5, 40000, ('spam', 'eggs'))" # Formatted String Literals # Formatted string literals (also called f-strings for short) let you include the value of # Python expressions inside a string by prefixing the string with f or F and writing # expressions as {expression}. # An optional format specifier can follow the expression. This allows greater control over how # the value is formatted. The following example rounds pi to three places after the decimal. pi_value = 3.14159 assert f'The value of pi is {pi_value:.3f}.' == 'The value of pi is 3.142.' # Passing an integer after the ':' will cause that field to be a minimum number of characters # wide. This is useful for making columns line up: table_data = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678} table_string = '' for name, phone in table_data.items(): table_string += f'{name:7}==>{phone:7d}' assert table_string == ('Sjoerd ==> 4127' 'Jack ==> 4098' 'Dcab ==> 7678') # The String format() Method # Basic usage of the str.format() method looks like this: assert 'We are {} who say "{}!"'.format('knights', 'Ni') == 'We are knights who say "Ni!"' # The brackets and characters within them (called format fields) are replaced with the objects # passed into the str.format() method. A number in the brackets can be used to refer to the # position of the object passed into the str.format() method assert '{0} and {1}'.format('spam', 'eggs') == 'spam and eggs' assert '{1} and {0}'.format('spam', 'eggs') == 'eggs and spam' # If keyword arguments are used in the str.format() method, their values are referred to by # using the name of the argument. formatted_string = 'This {food} is {adjective}.'.format( food='spam', adjective='absolutely horrible' ) assert formatted_string == 'This spam is absolutely horrible.' # Positional and keyword arguments can be arbitrarily combined formatted_string = 'The story of {0}, {1}, and {other}.'.format( 'Bill', 'Manfred', other='Georg' ) assert formatted_string == 'The story of Bill, Manfred, and Georg.' # If you have a really long format string that you don’t want to split up, it would be nice if # you could reference the variables to be formatted by name instead of by position. This can be # done by simply passing the dict and using square brackets '[]' to access the keys table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678} formatted_string = 'Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; Dcab: {0[Dcab]:d}'.format(table) assert formatted_string == 'Jack: 4098; Sjoerd: 4127; Dcab: 8637678' # This could also be done by passing the table as keyword arguments with the ‘**’ notation. formatted_string = 'Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table) assert formatted_string == 'Jack: 4098; Sjoerd: 4127; Dcab: 8637678' ================================================ FILE: src/data_types/test_tuples.py ================================================ """Tuples. @see: https://www.w3schools.com/python/python_tuples.asp @see: https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences A tuple is a collection which is ordered and unchangeable. In Python tuples are written with round brackets. The Tuples have following properties: - You cannot change values in a tuple. - You cannot remove items in a tuple. """ import pytest def test_tuples(): """Tuples""" fruits_tuple = ("apple", "banana", "cherry") assert isinstance(fruits_tuple, tuple) assert fruits_tuple[0] == "apple" assert fruits_tuple[1] == "banana" assert fruits_tuple[2] == "cherry" # You cannot change values in a tuple. with pytest.raises(Exception): # pylint: disable=unsupported-assignment-operation fruits_tuple[0] = "pineapple" # It is also possible to use the tuple() constructor to make a tuple (note the double # round-brackets). # The len() function returns the length of the tuple. fruits_tuple_via_constructor = tuple(("apple", "banana", "cherry")) assert isinstance(fruits_tuple_via_constructor, tuple) assert len(fruits_tuple_via_constructor) == 3 # It is also possible to omit brackets when initializing tuples. another_tuple = 12345, 54321, 'hello!' assert another_tuple == (12345, 54321, 'hello!') # Tuples may be nested: nested_tuple = another_tuple, (1, 2, 3, 4, 5) assert nested_tuple == ((12345, 54321, 'hello!'), (1, 2, 3, 4, 5)) # As you see, on output tuples are always enclosed in parentheses, so that nested tuples are # interpreted correctly; they may be input with or without surrounding parentheses, although # often parentheses are necessary anyway (if the tuple is part of a larger expression). It is # not possible to assign to the individual items of a tuple, however it is possible to create # tuples which contain mutable objects, such as lists. # A special problem is the construction of tuples containing 0 or 1 items: the syntax has some # extra quirks to accommodate these. Empty tuples are constructed by an empty pair of # parentheses; a tuple with one item is constructed by following a value with a comma (it is # not sufficient to enclose a single value in parentheses). Ugly, but effective. For example: empty_tuple = () # pylint: disable=len-as-condition assert len(empty_tuple) == 0 # pylint: disable=trailing-comma-tuple singleton_tuple = 'hello', # <-- note trailing comma assert len(singleton_tuple) == 1 assert singleton_tuple == ('hello',) # The following example is called tuple packing: packed_tuple = 12345, 54321, 'hello!' # The reverse operation is also possible. first_tuple_number, second_tuple_number, third_tuple_string = packed_tuple assert first_tuple_number == 12345 assert second_tuple_number == 54321 assert third_tuple_string == 'hello!' # This is called, appropriately enough, sequence unpacking and works for any sequence on the # right-hand side. Sequence unpacking requires that there are as many variables on the left # side of the equals sign as there are elements in the sequence. Note that multiple assignment # is really just a combination of tuple packing and sequence unpacking. # Swapping using tuples. # Data can be swapped from one variable to another in python using # tuples. This eliminates the need to use a 'temp' variable. first_number = 123 second_number = 456 first_number, second_number = second_number, first_number assert first_number == 456 assert second_number == 123 ================================================ FILE: src/data_types/test_type_casting.py ================================================ """Type casting. @see: https://www.w3schools.com/python/python_casting.asp There may be times when you want to specify a type on to a variable. This can be done with casting. Python is an object-orientated language, and as such it uses classes to define data types, including its primitive types. Casting in python is therefore done using constructor functions: - int() - constructs an integer number from an integer literal, a float literal (by rounding down to the previous whole number) literal, or a string literal (providing the string represents a whole number) - float() - constructs a float number from an integer literal, a float literal or a string literal (providing the string represents a float or an integer) - str() - constructs a string from a wide variety of data types, including strings, integer literals and float literals """ def test_type_casting_to_integer(): """Type casting to integer""" assert int(1) == 1 assert int(2.8) == 2 assert int('3') == 3 def test_type_casting_to_float(): """Type casting to float""" assert float(1) == 1.0 assert float(2.8) == 2.8 assert float("3") == 3.0 assert float("4.2") == 4.2 def test_type_casting_to_string(): """Type casting to string""" assert str("s1") == 's1' assert str(2) == '2' assert str(3.0) == '3.0' ================================================ FILE: src/exceptions/test_handle_exceptions.py ================================================ """Errors and Exceptions. @see: https://docs.python.org/3/tutorial/errors.html#errors-and-exceptions Even if a statement or expression is syntactically correct, it may cause an error when an attempt is made to execute it. Errors detected during execution are called exceptions and are not unconditionally fatal. It is possible to write programs that handle selected exceptions. """ def test_handle_exceptions(): """Handling of exceptions The try statement works as follows. - First, the try clause (the statement(s) between the try and except keywords) is executed. - If no exception occurs, the except clause is skipped and execution of the try statement is finished. - If an exception occurs during execution of the try clause, the rest of the clause is skipped. Then if its type matches the exception named after the except keyword, the except clause is executed, and then execution continues after the try statement. - If an exception occurs which does not match the exception named in the except clause, it is passed on to outer try statements; if no handler is found, it is an unhandled exception and execution stops with a message. """ # Let's simulate division by zero exception. exception_has_been_handled = False try: result = 10 * (1 / 0) # division by zero # We should not get here at all. assert result except ZeroDivisionError: # We should get here because of division by zero. exception_has_been_handled = True assert exception_has_been_handled # Let's simulate undefined variable access exception. exception_has_been_handled = False try: # pylint: disable=undefined-variable result = 4 + spam * 3 # name 'spam' is not defined # We should not get here at all. assert result except NameError: # We should get here because of division by zero. exception_has_been_handled = True assert exception_has_been_handled # A try statement may have more than one except clause, to specify handlers for different # exceptions. At most one handler will be executed. Handlers only handle exceptions that occur # in the corresponding try clause, not in other handlers of the same try statement. An except # clause may name multiple exceptions as a parenthesized tuple, for example: exception_has_been_handled = False try: result = 10 * (1 / 0) # division by zero # We should not get here at all. assert result except (ZeroDivisionError, NameError): # We should get here because of division by zero. exception_has_been_handled = True assert exception_has_been_handled # Exception handlers may be chained. exception_has_been_handled = False try: result = 10 * (1 / 0) # division by zero # We should not get here at all. assert result except NameError: # We should get here because of division by zero. exception_has_been_handled = True except ZeroDivisionError: # We should get here because of division by zero. exception_has_been_handled = True assert exception_has_been_handled # The try … except statement has an optional else clause, which, when present, must follow all # except clauses. It is useful for code that must be executed if the try clause does not raise # an exception. For example: exception_has_been_handled = False no_exceptions_has_been_fired = False try: result = 10 # We should not get here at all. assert result except NameError: # We should get here because of division by zero. exception_has_been_handled = True else: no_exceptions_has_been_fired = True assert not exception_has_been_handled assert no_exceptions_has_been_fired ================================================ FILE: src/exceptions/test_raise_exceptions.py ================================================ """Raising Exceptions. @see: https://docs.python.org/3/tutorial/errors.html#raising-exceptions The raise statement allows the programmer to force a specified exception to occur. """ def test_raise_exception(): """Raising Exceptions. The raise statement allows the programmer to force a specified exception to occur. """ exception_is_caught = False try: # The sole argument to raise indicates the exception to be raised. This must be either an # exception instance or an exception class (a class that derives from Exception). If an # exception class is passed, it will be implicitly instantiated by calling its constructor # with no arguments raise NameError('HiThere') # shorthand for 'raise ValueError()' except NameError: exception_is_caught = True assert exception_is_caught def test_user_defined_exception(): """User-defined Exceptions""" # Programs may name their own exceptions by creating a new exception class. Exceptions should # typically be derived from the Exception class, either directly or indirectly. # Most exceptions are defined with names that end in “Error,” similar to the naming of the # standard exceptions. Many standard modules define their own exceptions to report errors # that may occur in functions they define. class MyCustomError(Exception): """Example of MyCustomError exception.""" def __init__(self, message): super().__init__(message) self.message = message custom_exception_is_caught = False try: raise MyCustomError('My custom message') except MyCustomError: custom_exception_is_caught = True assert custom_exception_is_caught ================================================ FILE: src/files/binary_file ================================================ 0123456789abcdef ================================================ FILE: src/files/multi_line_file.txt ================================================ first line second line third line ================================================ FILE: src/files/test_file_methods.py ================================================ """Methods of File Objects @see: https://docs.python.org/3/tutorial/inputoutput.html#methods-of-file-objects Reading from a file does not always have to be sequential. There are methods to look for specific locations in the file, much like flipping to a page in a book. """ def test_file_methods(): """Methods of File Objects""" multi_line_file = open('src/files/multi_line_file.txt', 'r') binary_file = open('src/files/binary_file', 'r') # To read a file’s contents, call f.read(size), which reads some quantity of data and returns # it as a string (in text mode) or bytes object (in binary mode). size is an optional numeric # argument. When size is omitted or negative, the entire contents of the file will be read and # returned; it’s your problem if the file is twice as large as your machine’s memory. Otherwise, # at most size bytes are read and returned. If the end of the file has been reached, f.read() # will return an empty string (''). read_data = multi_line_file.read() # pylint: disable=duplicate-code assert read_data == 'first line\nsecond line\nthird line' # To change the file object’s position, use f.seek(offset, from_what). The position is computed # from adding offset to a reference point; the reference point is selected by the from_what # argument. A from_what value of 0 measures from the beginning of the file, 1 uses the current # file position, and 2 uses the end of the file as the reference point. from_what can be omitted # and defaults to 0, using the beginning of the file as the reference point. assert binary_file.seek(0) == 0 # Go to the 0th byte in the file assert binary_file.seek(6) == 6 # Go to the 6th byte in the file assert binary_file.read(1) == '6' # f.readline() reads a single line from the file; a newline character (\n) is left at the end # of the string, and is only omitted on the last line of the file if the file doesn’t end in a # newline. This makes the return value unambiguous; if f.readline() returns an empty string, # the end of the file has been reached, while a blank line is represented by '\n', a string # containing only a single newline. multi_line_file.seek(0) assert multi_line_file.readline() == 'first line\n' assert multi_line_file.readline() == 'second line\n' assert multi_line_file.readline() == 'third line' assert multi_line_file.readline() == '' multi_line_file.close() binary_file.close() ================================================ FILE: src/files/test_file_reading.py ================================================ """Reading and Writing Files @see: https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files The process of reading and writing to a file is like finding a book and opening a book. First, the file is located, opened to the first page, then reading/writing begins until it reaches the end of the file. """ def test_files_open(): """Open files open() returns a file object, and is most commonly used with two arguments: open(filename, mode). The first argument is a string containing the filename. The second argument is another string containing a few characters describing the way in which the file will be used. mode can be: - 'r' when the file will only be read, - 'w' for only writing (an existing file with the same name will be erased), - 'a' opens the file for appending; any data written to the file is automatically added to end. - 'r+' opens the file for both reading and writing. The mode argument is optional; 'r' will be assumed if it’s omitted. Normally, files are opened in text mode, that means, you read and write strings from and to the file, which are encoded in a specific encoding. If encoding is not specified, the default is platform dependent (see open()). 'b' appended to the mode opens the file in binary mode: now the data is read and written in the form of bytes objects. This mode should be used for all files that don’t contain text. In text mode, the default when reading is to convert platform-specific line endings (\n on Unix, \r\n on Windows) to just \n. When writing in text mode, the default is to convert occurrences of \n back to platform-specific line endings. This behind-the-scenes modification to file data is fine for text files, but will corrupt binary data like that in JPEG or EXE files. Be very careful to use binary mode when reading and writing such files. It is good practice to use the with keyword when dealing with file objects. The advantage is that the file is properly closed after its suite finishes, even if an exception is raised at some point. Using with is also much shorter than writing equivalent try-finally blocks: """ # Open files without using 'with' statement. file = open('src/files/multi_line_file.txt', 'r') assert not file.closed read_data = file.read() assert read_data == ( 'first line\n' 'second line\n' 'third line' ) file.close() assert file.closed # Open file using with. with open('src/files/multi_line_file.txt', 'r') as file: read_data = file.read() assert read_data == ( 'first line\n' 'second line\n' 'third line' ) assert file.closed # If you’re not using the with keyword, then you should call f.close() to close the file and # immediately free up any system resources used by it. If you don’t explicitly close a file, # Python’s garbage collector will eventually destroy the object and close the open file for you, # but the file may stay open for a while. Another risk is that different Python implementations # will do this clean-up at different times. ================================================ FILE: src/functions/test_function_annotations.py ================================================ """Function Annotations. @see: https://docs.python.org/3/tutorial/controlflow.html#function-annotations Function annotations are completely optional metadata information about the types used by user-defined functions. Annotations are stored in the __annotations__ attribute of the function as a dictionary and have no effect on any other part of the function. Parameter annotations are defined by a colon after the parameter name, followed by an expression evaluating to the value of the annotation. Return annotations are defined by a literal ->, followed by an expression, between the parameter list and the colon denoting the end of the def statement. """ def breakfast(ham: str, eggs: str = 'eggs') -> str: """Breakfast creator. This function has a positional argument, a keyword argument, and the return value annotated. """ return ham + ' and ' + eggs def test_function_annotations(): """Function Annotations.""" assert breakfast.__annotations__ == {'eggs': str, 'ham': str, 'return': str} ================================================ FILE: src/functions/test_function_arbitrary_arguments.py ================================================ """Arbitrary Argument Lists @see: https://docs.python.org/3/tutorial/controlflow.html#arbitrary-argument-lists Function can be called with an arbitrary number of arguments. These arguments will be wrapped up in a tuple. Before the variable number of arguments, zero or more normal arguments may occur. """ def test_function_arbitrary_arguments(): """Arbitrary Argument Lists""" # When a final formal parameter of the form **name is present, it receives a dictionary # containing all keyword arguments except for those corresponding to a formal parameter. # This may be combined with a formal parameter of the form *name which receives a tuple # containing the positional arguments beyond the formal parameter list. # (*name must occur before **name.) For example, if we define a function like this: def test_function(first_param, *arguments): """This function accepts its arguments through "arguments" tuple""" assert first_param == 'first param' assert arguments == ('second param', 'third param') test_function('first param', 'second param', 'third param') # Normally, these variadic arguments will be last in the list of formal parameters, because # they scoop up all remaining input arguments that are passed to the function. Any formal # parameters which occur after the *args parameter are ‘keyword-only’ arguments, meaning that # they can only be used as keywords rather than positional arguments. def concat(*args, sep='/'): return sep.join(args) assert concat('earth', 'mars', 'venus') == 'earth/mars/venus' assert concat('earth', 'mars', 'venus', sep='.') == 'earth.mars.venus' ================================================ FILE: src/functions/test_function_decorators.py ================================================ """Function Decorators. @see: https://www.thecodeship.com/patterns/guide-to-python-function-decorators/ Function decorators are simply wrappers to existing functions. In the context of design patterns, decorators dynamically alter the functionality of a function, method or class without having to directly use subclasses. This is ideal when you need to extend the functionality of functions that you don't want to modify. We can implement the decorator pattern anywhere, but Python facilitates the implementation by providing much more expressive features and syntax for that. """ def test_function_decorators(): """Function Decorators.""" # Function decorators are simply wrappers to existing functions. Putting the ideas mentioned # above together, we can build a decorator. In this example let's consider a function that # wraps the string output of another function by p tags. # This is the function that we want to decorate. def greeting(name): return "Hello, {0}!".format(name) # This function decorates another functions output with

tag. def decorate_with_p(func): def function_wrapper(name): return "

{0}

".format(func(name)) return function_wrapper # Now, let's call our decorator and pass the function we want decorate to it. my_get_text = decorate_with_p(greeting) # Here we go, we've just decorated the function output without changing the function itself. assert my_get_text('John') == '

Hello, John!

' # With decorator. assert greeting('John') == 'Hello, John!' # Without decorator. # Now, Python makes creating and using decorators a bit cleaner and nicer for the programmer # through some syntactic sugar There is a neat shortcut for that, which is to mention the # name of the decorating function before the function to be decorated. The name of the # decorator should be prepended with an @ symbol. @decorate_with_p def greeting_with_p(name): return "Hello, {0}!".format(name) assert greeting_with_p('John') == '

Hello, John!

' # Now let's consider we wanted to decorate our greeting function by one more functions to wrap a # div the string output. # This will be our second decorator. def decorate_with_div(func): def function_wrapper(text): return "
{0}
".format(func(text)) return function_wrapper # With the basic approach, decorating get_text would be along the lines of # greeting_with_div_p = decorate_with_div(decorate_with_p(greeting_with_p)) # With Python's decorator syntax, same thing can be achieved with much more expressive power. @decorate_with_div @decorate_with_p def greeting_with_div_p(name): return "Hello, {0}!".format(name) assert greeting_with_div_p('John') == '

Hello, John!

' # One important thing to notice here is that the order of setting our decorators matters. # If the order was different in the example above, the output would have been different. # Passing arguments to decorators. # Looking back at the example before, you can notice how redundant the decorators in the # example are. 2 decorators(decorate_with_div, decorate_with_p) each with the same # functionality but wrapping the string with different tags. We can definitely do much better # than that. Why not have a more general implementation for one that takes the tag to wrap # with as a string? Yes please! def tags(tag_name): def tags_decorator(func): def func_wrapper(name): return "<{0}>{1}".format(tag_name, func(name)) return func_wrapper return tags_decorator @tags('div') @tags('p') def greeting_with_tags(name): return "Hello, {0}!".format(name) assert greeting_with_tags('John') == '

Hello, John!

' ================================================ FILE: src/functions/test_function_default_arguments.py ================================================ """Default Argument Values @see: https://docs.python.org/3/tutorial/controlflow.html#default-argument-values The most useful form is to specify a default value for one or more arguments. This creates a function that can be called with fewer arguments than it is defined to allow. """ def power_of(number, power=2): """ Raises number to specific power. You may notice that by default the function raises number to the power of two. """ return number ** power def test_default_function_arguments(): """Test default function arguments""" # This function power_of can be called in several ways because it has default value for # the second argument. First we may call it omitting the second argument at all. assert power_of(3) == 9 # We may also want to override the second argument by using the following function calls. assert power_of(3, 2) == 9 assert power_of(3, 3) == 27 ================================================ FILE: src/functions/test_function_definition.py ================================================ """Function Definition @see: https://docs.python.org/3/tutorial/controlflow.html#defining-functions @see: https://www.thecodeship.com/patterns/guide-to-python-function-decorators/ The keyword def introduces a function definition. It must be followed by the function name and the parenthesized list of formal parameters. The statements that form the body of the function start at the next line, and must be indented. """ def fibonacci_function_example(number_limit): """Generate a Fibonacci series up to number_limit. The first statement of the function body can optionally be a string literal; this string literal is the function’s documentation string, or docstring. There are tools which use docstrings to automatically produce online or printed documentation, or to let the user interactively browse through code; it’s good practice to include docstrings in code that you write, so make a habit of it. """ # The execution of a function introduces a new symbol table used for the local variables of the # function. More precisely, all variable assignments in a function store the value in the local # symbol table; whereas variable references first look in the local symbol table, then in the # local symbol tables of enclosing functions, then in the global symbol table, and finally in # the table of built-in names. Thus, global variables cannot be directly assigned a value # within a function (unless named in a global statement), although they may be referenced. fibonacci_list = [] previous_number, current_number = 0, 1 while previous_number < number_limit: # The statement result.append(a) calls a method of the list object result. A method is a # function that ‘belongs’ to an object and is named obj.methodname, where obj is some # object (this may be an expression), and methodname is the name of a method that is # defined by the object’s type. Different types define different methods. Methods of # different types may have the same name without causing ambiguity. (It is possible to # define your own object types and methods, using classes, see Classes) The method # append() shown in the example is defined for list objects; it adds a new element at # the end of the list. In this example it is equivalent to result = result + [a], but # more efficient. fibonacci_list.append(previous_number) # This is multiple assignment statement. We make current number to be previous one and the # sum of previous and current to be a new current. previous_number, current_number = current_number, previous_number + current_number # The return statement returns with a value from a function. return without an expression # argument returns None. Falling off the end of a function also returns None. return fibonacci_list def test_function_definition(): """Function Definition""" # Now call the function we just defined. assert fibonacci_function_example(300) == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233] # A function definition introduces the function name in the current symbol table. The value of # the function name has a type that is recognized by the interpreter as a user-defined function. # This value can be assigned to another name which can then also be used as a function. This # serves as a general renaming mechanism fibonacci_function_clone = fibonacci_function_example assert fibonacci_function_clone(300) == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233] # In Python, functions are first class citizens, they are objects and that means we can do a # lot of useful stuff with them. # Assign functions to variables. def greet(name): return 'Hello, ' + name greet_someone = greet assert greet_someone('John') == 'Hello, John' # Define functions inside other functions. def greet_again(name): def get_message(): return 'Hello, ' result = get_message() + name return result assert greet_again('John') == 'Hello, John' # Functions can be passed as parameters to other functions. def greet_one_more(name): return 'Hello, ' + name def call_func(func): other_name = 'John' return func(other_name) assert call_func(greet_one_more) == 'Hello, John' # Functions can return other functions. In other words, functions generating other functions. def compose_greet_func(): def get_message(): return 'Hello there!' return get_message greet_function = compose_greet_func() assert greet_function() == 'Hello there!' # Inner functions have access to the enclosing scope. # More commonly known as a closure. A very powerful pattern that we will come across while # building decorators. Another thing to note, Python only allows read access to the outer # scope and not assignment. Notice how we modified the example above to read a "name" argument # from the enclosing scope of the inner function and return the new function. def compose_greet_func_with_closure(name): def get_message(): return 'Hello there, ' + name + '!' return get_message greet_with_closure = compose_greet_func_with_closure('John') assert greet_with_closure() == 'Hello there, John!' ================================================ FILE: src/functions/test_function_documentation_string.py ================================================ """Documentation Strings. @see: https://docs.python.org/3/tutorial/controlflow.html#documentation-strings Here are some conventions about the content and formatting of documentation strings. The first line should always be a short, concise summary of the object’s purpose. For brevity, it should not explicitly state the object’s name or type, since these are available by other means (except if the name happens to be a verb describing a function’s operation). This line should begin with a capital letter and end with a period. If there are more lines in the documentation string, the second line should be blank, visually separating the summary from the rest of the description. The following lines should be one or more paragraphs describing the object’s calling conventions, its side effects, etc. """ def do_nothing(): """Do nothing, but document it. No, really, it doesn't do anything. """ pass def test_function_documentation_string(): """Test documentation string.""" # The Python parser does not strip indentation from multi-line string literals in Python, so # tools that process documentation have to strip indentation if desired. This is done using the # following convention. The first non-blank line after the first line of the string determines # the amount of indentation for the entire documentation string. (We can’t use the first line # since it is generally adjacent to the string’s opening quotes so its indentation is not # apparent in the string literal.) Whitespace “equivalent” to this indentation is then stripped # from the start of all lines of the string. Lines that are indented less should not occur, but # if they occur all their leading whitespace should be stripped. Equivalence of whitespace # should be tested after expansion of tabs (to 8 spaces, normally). assert do_nothing.__doc__ == """Do nothing, but document it. No, really, it doesn't do anything. """ ================================================ FILE: src/functions/test_function_keyword_arguments.py ================================================ """Keyword Arguments @see: https://docs.python.org/3/tutorial/controlflow.html#keyword-arguments Functions can be called using keyword arguments of the form kwarg=value. """ import pytest def parrot(voltage, state='a stiff', action='voom', parrot_type='Norwegian Blue'): """Example of multi-argument function This function accepts one required argument (voltage) and three optional arguments (state, action, and type). """ message = 'This parrot wouldn\'t ' + action + ' ' message += 'if you put ' + str(voltage) + ' volts through it. ' message += 'Lovely plumage, the ' + parrot_type + '. ' message += 'It\'s ' + state + '!' return message def test_function_keyword_arguments(): """Test calling function with specifying keyword arguments""" # The parrot function accepts one required argument (voltage) and three optional arguments # (state, action, and type). This function can be called in any of the following ways: message = ( "This parrot wouldn't voom if you put 1000 volts through it. " "Lovely plumage, the Norwegian Blue. " "It's a stiff!" ) # 1 positional argument assert parrot(1000) == message # 1 keyword argument assert parrot(voltage=1000) == message message = ( "This parrot wouldn't VOOOOOM if you put 1000000 volts through it. " "Lovely plumage, the Norwegian Blue. " "It's a stiff!" ) # 2 keyword arguments assert parrot(voltage=1000000, action='VOOOOOM') == message # 2 keyword arguments assert parrot(action='VOOOOOM', voltage=1000000) == message # 3 positional arguments message = ( "This parrot wouldn't jump if you put 1000000 volts through it. " "Lovely plumage, the Norwegian Blue. " "It's bereft of life!" ) assert parrot(1000000, 'bereft of life', 'jump') == message # 1 positional, 1 keyword message = ( "This parrot wouldn't voom if you put 1000 volts through it. " "Lovely plumage, the Norwegian Blue. " "It's pushing up the daisies!" ) assert parrot(1000, state='pushing up the daisies') == message # But all the following calls would be invalid. with pytest.raises(Exception): # Required argument missing. # pylint: disable=no-value-for-parameter parrot() # Non-keyword argument after a keyword argument. # parrot(voltage=5.0, 'dead') with pytest.raises(Exception): # pylint: disable=redundant-keyword-arg parrot(110, voltage=220) with pytest.raises(Exception): # unknown keyword argument # pylint: disable=unexpected-keyword-arg,no-value-for-parameter parrot(actor='John Cleese') # In a function call, keyword arguments must follow positional arguments. All the keyword # arguments passed must match one of the arguments accepted by the function (e.g. actor is not # a valid argument for the parrot function), and their order is not important. This also # includes non-optional arguments (e.g. parrot(voltage=1000) is valid too). No argument may # receive a value more than once. Here’s an example that fails due to this restriction: def function_with_one_argument(number): return number with pytest.raises(Exception): # pylint: disable=redundant-keyword-arg function_with_one_argument(0, number=0) # When a final formal parameter of the form **name is present, it receives a dictionary # containing all keyword arguments except for those corresponding to a formal parameter. # This may be combined with a formal parameter of the form *name which receives a tuple # containing the positional arguments beyond the formal parameter list. # (*name must occur before **name.) For example, if we define a function like this: def test_function(first_param, *arguments, **keywords): """This function accepts its arguments through "arguments" tuple and keywords dictionary.""" assert first_param == 'first param' assert arguments == ('second param', 'third param') assert keywords == { 'fourth_param_name': 'fourth named param', 'fifth_param_name': 'fifth named param' } test_function( 'first param', 'second param', 'third param', fourth_param_name='fourth named param', fifth_param_name='fifth named param', ) ================================================ FILE: src/functions/test_function_scopes.py ================================================ """Scopes and Namespaces. @see: https://docs.python.org/3/tutorial/classes.html#scopes-and-namespaces-example A NAMESPACE is a mapping from names to objects. Most namespaces are currently implemented as Python dictionaries, but that’s normally not noticeable in any way (except for performance), and it may change in the future. Examples of namespaces are: the set of built-in names (containing functions such as abs(), and built-in exception names); the global names in a module; and the local names in a function invocation. In a sense the set of attributes of an object also form a namespace. The important thing to know about namespaces is that there is absolutely no relation between names in different namespaces; for instance, two different modules may both define a function maximize without confusion — users of the modules must prefix it with the module name. By the way, we use the word attribute for any name following a dot — for example, in the expression z.real, real is an attribute of the object z. Strictly speaking, references to names in modules are attribute references: in the expression modname.func_name, modname is a module object and func_name is an attribute of it. In this case there happens to be a straightforward mapping between the module’s attributes and the global names defined in the module: they share the same namespace! A SCOPE is a textual region of a Python program where a namespace is directly accessible. “Directly accessible” here means that an unqualified reference to a name attempts to find the name in the namespace. Although scopes are determined statically, they are used dynamically. At any time during execution, there are at least three nested scopes whose namespaces are directly accessible: - the innermost scope, which is searched first, contains the local names. - the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names. - the next-to-last scope contains the current module’s global names. - the outermost scope (searched last) is the namespace containing built-in names. BE CAREFUL!!! ------------- Changing global or nonlocal variables from within an inner function might be a BAD practice and might lead to harder debugging and to more fragile code! Do this only if you know what you're doing. """ # pylint: disable=invalid-name test_variable = 'initial global value' def test_function_scopes(): """Scopes and Namespaces Example""" # This is an example demonstrating how to reference the different scopes and namespaces, and # how global and nonlocal affect variable binding: # pylint: disable=redefined-outer-name test_variable = 'initial value inside test function' def do_local(): # Create variable that is only accessible inside current do_local() function. # pylint: disable=redefined-outer-name test_variable = 'local value' return test_variable def do_nonlocal(): # Address the variable from outer scope and try to change it. # pylint: disable=redefined-outer-name nonlocal test_variable test_variable = 'nonlocal value' return test_variable def do_global(): # Address the variable from very global scope and try to change it. # pylint: disable=redefined-outer-name,global-statement global test_variable test_variable = 'global value' return test_variable # On this level currently we have access to local for test_function_scopes() function variable. assert test_variable == 'initial value inside test function' # Do local assignment. # It doesn't change global variable and variable from test_function_scopes() scope. do_local() assert test_variable == 'initial value inside test function' # Do non local assignment. # It doesn't change global variable but it does change variable # from test_function_scopes() function scope. do_nonlocal() assert test_variable == 'nonlocal value' # Do global assignment. # This one changes global variable but doesn't change variable from # test_function_scopes() function scope. do_global() assert test_variable == 'nonlocal value' def test_global_variable_access(): """Testing global variable access from within a function""" # Global value of test_variable has been already changed by do_global() function in previous # test so let's check that. # pylint: disable=global-statement global test_variable assert test_variable == 'global value' # On this example you may see how accessing and changing global variables from within inner # functions might make debugging more difficult and code to be less predictable. Since you # might have expected that test_variable should still be equal to 'initial global value' but # it was changed by "someone" and you need to know about the CONTEXT of who had changed that. # So once again access global and non local scope only if you know what you're doing otherwise # it might be considered as bad practice. ================================================ FILE: src/functions/test_function_unpacking_arguments.py ================================================ """Unpacking Argument Lists @see: https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists Unpacking arguments may be executed via * and ** operators. See below for further details. """ def test_function_unpacking_arguments(): """Unpacking Argument Lists""" # The situation may occur when the arguments are already in a list or tuple but need to be # unpacked for a function call requiring separate positional arguments. For instance, the # built-in range() function expects separate start and stop arguments. If they are not # available separately, write the function call with the *-operator to unpack the arguments out # of a list or tuple: # Normal call with separate arguments: assert list(range(3, 6)) == [3, 4, 5] # Call with arguments unpacked from a list. arguments_list = [3, 6] assert list(range(*arguments_list)) == [3, 4, 5] # In the same fashion, dictionaries can deliver keyword arguments with the **-operator: def function_that_receives_names_arguments(first_word, second_word): return first_word + ', ' + second_word + '!' arguments_dictionary = {'first_word': 'Hello', 'second_word': 'World'} assert function_that_receives_names_arguments(**arguments_dictionary) == 'Hello, World!' ================================================ FILE: src/functions/test_lambda_expressions.py ================================================ """Lambda Expressions @see: https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions Small anonymous functions can be created with the lambda keyword. Lambda functions can be used wherever function objects are required. They are syntactically restricted to a single expression. Semantically, they are just syntactic sugar for a normal function definition. Like nested function definitions, lambda functions can reference variables from the containing scope. """ def test_lambda_expressions(): """Lambda Expressions""" # This function returns the sum of its two arguments: lambda a, b: a+b # Like nested function definitions, lambda functions can reference variables from the # containing scope. def make_increment_function(delta): """This example uses a lambda expression to return a function""" return lambda number: number + delta increment_function = make_increment_function(42) assert increment_function(0) == 42 assert increment_function(1) == 43 assert increment_function(2) == 44 # Another use of lambda is to pass a small function as an argument. pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')] # Sort pairs by text key. pairs.sort(key=lambda pair: pair[1]) assert pairs == [(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')] ================================================ FILE: src/getting_started/python_syntax.md ================================================ # Python Syntax **Python Syntax compared to other programming languages** - Python was designed to for readability, and has some similarities to the English language with influence from mathematics. - Python uses new lines to complete a command, as opposed to other programming languages which often use semicolons or parentheses. - Python relies on indentation, using whitespace, to define scope; such as the scope of loops, functions and classes. Other programming languages often use curly-brackets for this purpose. ## Python Indentations Where in other programming languages the indentation in code is for readability only, in Python the indentation is very important. Python uses indentation to indicate a block of code. ```python if 5 > 2: print("Five is greater than two!") ``` Python will give you an error if you skip the indentation. ## Comments Python has commenting capability for the purpose of in-code documentation. Comments start with a `#`, and Python will render the rest of the line as a comment: ```python #This is a comment. print("Hello, World!") ``` ## Docstrings Python also has extended documentation capability, called docstrings. Docstrings can be one line, or multiline. Docstrings are also comments: Python uses triple quotes at the beginning and end of the docstring: ```python """This is a multiline docstring.""" print("Hello, World!") ``` ## References - [w3schools.com](https://www.w3schools.com/python/python_syntax.asp) ================================================ FILE: src/getting_started/test_variables.py ================================================ """Variables @see: https://docs.python.org/3/tutorial/introduction.html @see: https://www.w3schools.com/python/python_variables.asp @see: https://www.learnpython.org/en/Variables_and_Types Python is completely object oriented, and not "statically typed". You do not need to declare variables before using them, or declare their type. Every variable in Python is an object. Unlike other programming languages, Python has no command for declaring a variable. A variable is created the moment you first assign a value to it. A variable can have a short name (like x and y) or a more descriptive name (age, carname, total_volume). Rules for Python variables: - A variable name must start with a letter or the underscore character. - A variable name cannot start with a number. - A variable name can only contain alpha-numeric characters and underscores (A-z, 0-9, and _ ). - Variable names are case-sensitive (age, Age and AGE are three different variables). """ def test_variables(): """Test variables""" integer_variable = 5 string_variable = 'John' assert integer_variable == 5 assert string_variable == 'John' variable_with_changed_type = 4 # x is of type int variable_with_changed_type = 'Sally' # x is now of type str assert variable_with_changed_type == 'Sally' ================================================ FILE: src/getting_started/what_is_python.md ================================================ # What is Python Python is a popular programming language. It was created in 1991 by Guido van Rossum. Python is an easy to learn, powerful programming language. It has efficient high-level data structures and a simple but effective approach to object-oriented programming. Python’s elegant syntax and dynamic typing, together with its interpreted nature, make it an ideal language for scripting and rapid application development in many areas on most platforms. It is used for: - web development (server-side), - software development, - mathematics, - system scripting. ## What can Python do? - Python can be used on a server to create web applications. - Python can be used alongside software to create workflows. - Python can connect to database systems. It can also read and modify files. - Python can be used to handle big data and perform complex mathematics. - Python can be used for rapid prototyping, or for production-ready software development. ## Why Python? - Python works on different platforms (Windows, Mac, Linux, Raspberry Pi, etc). - Python has a simple syntax similar to the English language. - Python has syntax that allows developers to write programs with fewer lines than some other programming languages. - Python runs on an interpreter system, meaning that code can be executed as soon as it is written. This means that prototyping can be very quick. - Python can be treated in a procedural way, an object-orientated way or a functional way. ## Good to know - The most recent major version of Python is Python 3, which we shall be using in this tutorial. However, Python 2, although not being updated with anything other than security updates, is still quite popular. - In this tutorial Python will be written in a text editor. It is possible to write Python in an Integrated Development Environment, such as Thonny, Pycharm, Netbeans or Eclipse which are particularly useful when managing larger collections of Python files. ## References - [w3schools.com](https://www.w3schools.com/python/python_intro.asp) ================================================ FILE: src/modules/fibonacci_module.py ================================================ """Fibonacci numbers module. @see: https://docs.python.org/3/tutorial/modules.html A module is a file containing Python definitions and statements. The file name is the module name with the suffix .py appended. Within a module, the module’s name (as a string) is available as the value of the global variable __name__. """ def fibonacci_at_position(position): """Return Fibonacci number at specified position""" current_position = 0 previous_number, current_number = 0, 1 while current_position < position: current_position += 1 previous_number, current_number = current_number, previous_number + current_number return previous_number def fibonacci_smaller_than(limit): """Return Fibonacci series up to limit""" result = [] previous_number, current_number = 0, 1 while previous_number < limit: result.append(previous_number) previous_number, current_number = current_number, previous_number + current_number return result # When you run a Python module with: # # >>> python fibonacci.py # # the code in the module will be executed, just as if you imported it, but with # the __name__ set to "__main__". That means that by adding this code at the end of your module # you can make the file usable as a script as well as an importable module, because the code that # parses the command line only runs if the module is executed as the “main” file: # # >>> python fibonacci.py 50 if __name__ == '__main__': import sys print(fibonacci_smaller_than(int(sys.argv[1]))) ================================================ FILE: src/modules/sound_package/__init__.py ================================================ ================================================ FILE: src/modules/sound_package/effects/__init__.py ================================================ ================================================ FILE: src/modules/sound_package/effects/echo.py ================================================ """Echo effect.""" def echo_function(): """Echo function mock""" return 'Do echo effect' ================================================ FILE: src/modules/sound_package/effects/reverse.py ================================================ """Reverse effect.""" def reverse_function(): """Reveres function mock""" return 'Do reverse effect' ================================================ FILE: src/modules/sound_package/formats/__init__.py ================================================ ================================================ FILE: src/modules/sound_package/formats/aif.py ================================================ """AIF file support.""" def aif_read(): """AIF file reading function mock""" return 'Read from AIF file' ================================================ FILE: src/modules/sound_package/formats/wav.py ================================================ """WAV file support.""" def wav_read(): """WAV file reading function mock""" return 'Read from WAV file' ================================================ FILE: src/modules/test_modules.py ================================================ """Modules. @see: https://docs.python.org/3/tutorial/modules.html As your program gets longer, you may want to split it into several files for easier maintenance. You may also want to use a handy function that you’ve written in several programs without copying its definition into each program. To support this, Python has a way to put definitions in a file and use them in a script or in an interactive instance of the interpreter. Such a file is called a module; definitions from a module can be imported into other modules or into the main module (the collection of variables that you have access to in a script executed at the top level and in calculator mode). A module is a file containing Python definitions and statements. The file name is the module name with the suffix .py appended. Within a module, the module’s name (as a string) is available as the value of the global variable __name__. When the interpreter executes the import statement, it searches for module in a list of directories assembled from the following sources: - The directory from which the input script was run or the current directory if the interpreter is being run interactively - The list of directories contained in the PYTHONPATH environment variable, if it is set. (The format for PYTHONPATH is OS-dependent but should mimic the PATH environment variable.) - An installation-dependent list of directories configured at the time Python is installed The resulting search path is accessible in the Python variable sys.path, which is obtained from a module named sys: >>> import sys >>> sys.path @see: https://realpython.com/python-modules-packages/ """ # This does not enter the names of the functions defined in fibonacci_module directly in the # current symbol table; it only enters the module name fibonacci_module there. import fibonacci_module # There is a variant of the import statement that imports names from a module directly into the # importing module’s symbol table. For example: # pylint: disable=reimported from fibonacci_module import fibonacci_at_position, fibonacci_smaller_than # There is even a variant to import all names that a module defines. This imports all names except # those beginning with an underscore (_). In most cases Python programmers do not use this facility # since it introduces an unknown set of names into the interpreter, possibly hiding some things you # have already defined. # >>> from fibonacci_module import * # If the module name is followed by as, then the name following as is bound directly to the # imported module: import fibonacci_module as fibonacci_module_renamed # It can also be used when utilising from with similar effects: from fibonacci_module import fibonacci_at_position as fibonacci_at_position_renamed # When a module named spam is imported, the interpreter first searches for a built-in module with # that name. If not found, it then searches for a file named spam.py in a list of directories # given by the variable sys.path. sys.path is initialized from these locations: # # - The directory containing the input script (or the current directory when no file is specified). # - PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH). # - The installation-dependent default. def test_modules(): """Modules""" assert fibonacci_module.fibonacci_at_position(7) == 13 assert fibonacci_at_position(7) == 13 assert fibonacci_module_renamed.fibonacci_at_position(7) == 13 assert fibonacci_at_position_renamed(7) == 13 assert fibonacci_module.fibonacci_smaller_than(100) == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] assert fibonacci_smaller_than(100) == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] assert fibonacci_module_renamed.fibonacci_smaller_than(10) == [0, 1, 1, 2, 3, 5, 8] # If you intend to use a function often you can assign it to a local name. fibonacci = fibonacci_module.fibonacci_smaller_than assert fibonacci(100) == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] # The built-in function dir() is used to find out which names a module defines. It returns a # sorted list of strings. assert dir(fibonacci_module) == [ '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'fibonacci_at_position', 'fibonacci_smaller_than', ] ================================================ FILE: src/modules/test_packages.py ================================================ """Packages. @see: https://docs.python.org/3/tutorial/modules.html#packages Packages are a way of structuring Python’s module namespace by using “dotted module names”. For example, the module name A.B designates a submodule named B in a package named A. Just like the use of modules saves the authors of different modules from having to worry about each other’s global variable names, the use of dotted module names saves the authors of multi-module packages like NumPy or Pillow from having to worry about each other’s module names. The __init__.py files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package or set the __all__ variable, described later. When the interpreter executes the import statement, it searches for module in a list of directories assembled from the following sources: - The directory from which the input script was run or the current directory if the interpreter is being run interactively - The list of directories contained in the PYTHONPATH environment variable, if it is set. (The format for PYTHONPATH is OS-dependent but should mimic the PATH environment variable.) - An installation-dependent list of directories configured at the time Python is installed The resulting search path is accessible in the Python variable sys.path, which is obtained from a module named sys: >>> import sys >>> sys.path @see: https://realpython.com/python-modules-packages/ """ # Users of the package can import individual modules from the package, for example. import sound_package.effects.echo # An alternative way of importing the submodule is: # pylint: disable=reimported from sound_package.effects import echo # Yet another variation is to import the desired function or variable directly: from sound_package.effects.echo import echo_function # Note that when using from package import item, the item can be either a submodule (or subpackage) # of the package, or some other name defined in the package, like a function, class or variable. # The import statement first tests whether the item is defined in the package; if not, it assumes # it is a module and attempts to load it. If it fails to find it, an ImportError exception is # raised. # Contrarily, when using syntax like import item.subitem.subsubitem, each item except for the last # must be a package; the last item can be a module or a package but can’t be a class or function or # variable defined in the previous item. def test_packages(): """Packages.""" assert sound_package.effects.echo.echo_function() == 'Do echo effect' assert echo.echo_function() == 'Do echo effect' assert echo_function() == 'Do echo effect' ================================================ FILE: src/operators/test_arithmetic.py ================================================ """Arithmetic operators @see: https://www.w3schools.com/python/python_operators.asp Arithmetic operators are used with numeric values to perform common mathematical operations """ def test_arithmetic_operators(): """Arithmetic operators""" # Addition. assert 5 + 3 == 8 # Subtraction. assert 5 - 3 == 2 # Multiplication. assert 5 * 3 == 15 assert isinstance(5 * 3, int) # Division. # Result of division is float number. assert 5 / 3 == 1.6666666666666667 assert 8 / 4 == 2 assert isinstance(5 / 3, float) assert isinstance(8 / 4, float) # Modulus. assert 5 % 3 == 2 # Exponentiation. assert 5 ** 3 == 125 assert 2 ** 3 == 8 assert 2 ** 4 == 16 assert 2 ** 5 == 32 assert isinstance(5 ** 3, int) # Floor division. assert 5 // 3 == 1 assert 6 // 3 == 2 assert 7 // 3 == 2 assert 9 // 3 == 3 assert isinstance(5 // 3, int) ================================================ FILE: src/operators/test_assigment.py ================================================ """Assignment operators @see: https://www.w3schools.com/python/python_operators.asp Assignment operators are used to assign values to variables """ def test_assignment_operator(): """Assignment operator """ # Assignment: = number = 5 assert number == 5 # Multiple assignment. # The variables first_variable and second_variable simultaneously get the new values 0 and 1. first_variable, second_variable = 0, 1 assert first_variable == 0 assert second_variable == 1 # You may even switch variable values using multiple assignment. first_variable, second_variable = second_variable, first_variable assert first_variable == 1 assert second_variable == 0 def test_augmented_assignment_operators(): """Assignment operator combined with arithmetic and bitwise operators""" # Assignment: += number = 5 number += 3 assert number == 8 # Assignment: -= number = 5 number -= 3 assert number == 2 # Assignment: *= number = 5 number *= 3 assert number == 15 # Assignment: /= number = 8 number /= 4 assert number == 2 # Assignment: %= number = 8 number %= 3 assert number == 2 # Assignment: %= number = 5 number %= 3 assert number == 2 # Assignment: //= number = 5 number //= 3 assert number == 1 # Assignment: **= number = 5 number **= 3 assert number == 125 # Assignment: &= number = 5 # 0b0101 number &= 3 # 0b0011 assert number == 1 # 0b0001 # Assignment: |= number = 5 # 0b0101 number |= 3 # 0b0011 assert number == 7 # 0b0111 # Assignment: ^= number = 5 # 0b0101 number ^= 3 # 0b0011 assert number == 6 # 0b0110 # Assignment: >>= number = 5 number >>= 3 assert number == 0 # (((5 // 2) // 2) // 2) # Assignment: <<= number = 5 number <<= 3 assert number == 40 # 5 * 2 * 2 * 2 ================================================ FILE: src/operators/test_bitwise.py ================================================ """Bitwise operators @see: https://www.w3schools.com/python/python_operators.asp Bitwise operators manipulate numbers on bit level. """ def test_bitwise_operators(): """Bitwise operators""" # AND # Sets each bit to 1 if both bits are 1. # # Example: # 5 = 0b0101 # 3 = 0b0011 assert 5 & 3 == 1 # 0b0001 # OR # Sets each bit to 1 if one of two bits is 1. # # Example: # 5 = 0b0101 # 3 = 0b0011 assert 5 | 3 == 7 # 0b0111 # NOT # Inverts all the bits. assert ~5 == -6 # XOR # Sets each bit to 1 if only one of two bits is 1. # # Example: # 5 = 0b0101 # 3 = 0b0011 number = 5 # 0b0101 number ^= 3 # 0b0011 assert 5 ^ 3 == 6 # 0b0110 # Signed right shift # Shift right by pushing copies of the leftmost bit in from the left, and let the rightmost # bits fall off. # # Example: # 5 = 0b0101 assert 5 >> 1 == 2 # 0b0010 assert 5 >> 2 == 1 # 0b0001 # Zero fill left shift # Shift left by pushing zeros in from the right and let the leftmost bits fall off. # # Example: # 5 = 0b0101 assert 5 << 1 == 10 # 0b1010 assert 5 << 2 == 20 # 0b10100 ================================================ FILE: src/operators/test_comparison.py ================================================ """Comparison operators @see: https://www.w3schools.com/python/python_operators.asp Comparison operators are used to compare two values. """ def test_comparison_operators(): """Comparison operators""" # Equal. number = 5 assert number == 5 # Not equal. number = 5 assert number != 3 # Greater than. number = 5 assert number > 3 # Less than. number = 5 assert number < 8 # Greater than or equal to number = 5 assert number >= 5 assert number >= 4 # Less than or equal to number = 5 assert number <= 5 assert number <= 6 ================================================ FILE: src/operators/test_identity.py ================================================ """Identity operators @see: https://www.w3schools.com/python/python_operators.asp Identity operators are used to compare the objects, not if they are equal, but if they are actually the same object, with the same memory location. """ def test_identity_operators(): """Identity operators""" # Let's illustrate identity operators based on the following lists. first_fruits_list = ["apple", "banana"] second_fruits_list = ["apple", "banana"] third_fruits_list = first_fruits_list # is # Returns true if both variables are the same object. # Example: # first_fruits_list and third_fruits_list are the same objects. assert first_fruits_list is third_fruits_list # is not # Returns true if both variables are not the same object. # Example: # first_fruits_list and second_fruits_list are not the same objects, even if they have # the same content assert first_fruits_list is not second_fruits_list # To demonstrate the difference between "is" and "==": this comparison returns True because # first_fruits_list is equal to second_fruits_list. assert first_fruits_list == second_fruits_list ================================================ FILE: src/operators/test_logical.py ================================================ """Logical operators @see: https://www.w3schools.com/python/python_operators.asp Logical operators are used to combine conditional statements. """ def test_logical_operators(): """Logical operators""" # Let's work with these number to illustrate logic operators. first_number = 5 second_number = 10 # and # Returns True if both statements are true. assert first_number > 0 and second_number < 20 # or # Returns True if one of the statements is true assert first_number > 5 or second_number < 20 # not # Reverse the result, returns False if the result is true. # pylint: disable=unneeded-not assert not first_number == second_number assert first_number != second_number ================================================ FILE: src/operators/test_membership.py ================================================ """Membership operators @see: https://www.w3schools.com/python/python_operators.asp Membership operators are used to test if a sequence is presented in an object. """ def test_membership_operators(): """Membership operators""" # Let's use the following fruit list to illustrate membership concept. fruit_list = ["apple", "banana"] # in # Returns True if a sequence with the specified value is present in the object. # Returns True because a sequence with the value "banana" is in the list assert "banana" in fruit_list # not in # Returns True if a sequence with the specified value is not present in the object # Returns True because a sequence with the value "pineapple" is not in the list. assert "pineapple" not in fruit_list ================================================ FILE: src/standard_libraries/glob_files/first_file.txt ================================================ ================================================ FILE: src/standard_libraries/glob_files/second_file.txt ================================================ ================================================ FILE: src/standard_libraries/test_datetime.py ================================================ """Dates and Times. @see: https://docs.python.org/3/tutorial/stdlib.html#dates-and-times The datetime module supplies classes for manipulating dates and times in both simple and complex ways. While date and time arithmetic is supported, the focus of the implementation is on efficient member extraction for output formatting and manipulation. The module also supports objects that are timezone aware. """ from datetime import date def test_datetime(): """Dates and Times""" real_now = date.today() assert real_now fake_now = date(2018, 8, 29) assert fake_now.day == 29 assert fake_now.month == 8 assert fake_now.year == 2018 assert fake_now.ctime() == 'Wed Aug 29 00:00:00 2018' assert fake_now.strftime( '%m-%d-%y. %d %b %Y is a %A on the %d day of %B.' ) == '08-29-18. 29 Aug 2018 is a Wednesday on the 29 day of August.' # Dates support calendar arithmetic. birthday = date(1964, 7, 31) age = fake_now - birthday assert age.days == 19752 ================================================ FILE: src/standard_libraries/test_glob.py ================================================ """File Wildcards. @see: https://docs.python.org/3/tutorial/stdlib.html#file-wildcards The glob module provides a function for making file lists from directory wildcard searches: """ import glob def test_glob(): """File Wildcards.""" # == operator for lists relies on the order of elements in the list. # In some cases (like on Linux Mint, python3.6) the glob() function returns list # in reverse order then it might be expected. Thus lets sort both lists before comparison # using sorted() built-in function. assert sorted(glob.glob('src/standard_libraries/glob_files/*.txt')) == sorted([ 'src/standard_libraries/glob_files/first_file.txt', 'src/standard_libraries/glob_files/second_file.txt' ]) ================================================ FILE: src/standard_libraries/test_json.py ================================================ """Serialization. @see: https://www.learnpython.org/en/Serialization Python provides built-in JSON libraries to encode and decode JSON. """ import json def test_json(): """JSON serialization.""" # There are two basic formats for JSON data. Either in a string or the object data-structure. # The object data-structure, in Python, consists of lists and dictionaries nested inside each # other. The object data-structure allows one to use python methods (for lists and dictionaries) # to add, list, search and remove elements from the data-structure. The String format is mainly # used to pass the data into another program or load into a data-structure. person_dictionary = {'first_name': 'John', 'last_name': 'Smith', 'age': 42} assert person_dictionary['first_name'] == 'John' assert person_dictionary['age'] == 42 json_string = '{"first_name": "John", "last_name": "Smith", "age": 42}' # To load JSON back to a data structure, use the "loads" method. This method takes a string # and turns it back into the json object data-structure: person_parsed_dictionary = json.loads(json_string) assert person_parsed_dictionary == person_dictionary assert person_parsed_dictionary['first_name'] == 'John' assert person_parsed_dictionary['age'] == 42 # To encode a data structure to JSON, use the "dumps" method. This method takes an object and # returns a String: encoded_person_string = json.dumps(person_dictionary) assert encoded_person_string == json_string ================================================ FILE: src/standard_libraries/test_math.py ================================================ """Math. @see: https://docs.python.org/3/tutorial/stdlib.html#mathematics Math module is useful as many math functions are already implemented and optimized. """ import math import random import statistics def test_math(): """Math. The math module gives access to the underlying C library functions for floating point math. """ assert math.cos(math.pi / 4) == 0.70710678118654757 assert math.log(1024, 2) == 10.0 def test_random(): """Random. The random module provides tools for making random selections. """ # Choose from the list randomly. random_options = ['apple', 'pear', 'banana'] random_choice = random.choice(random_options) # i.e. 'apple' assert random_choice in random_options # Sampling without replacement. random_sample = random.sample(range(100), 10) # i.e. [30, 83, 16, 4, 8, 81, 41, 50, 18, 33] for sample in random_sample: assert 0 <= sample <= 100 # Choose random number. random_float = random.random() # i.e. 0.17970987693706186 assert 0 <= random_float <= 1 # Random integer chosen from range(6) random_integer = random.randrange(6) # i.e. 4 assert 0 <= random_integer <= 6 def test_statistics(): """Statistics. The statistics module calculates basic statistical properties (the mean, median, variance, etc.) of numeric data. """ data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5] assert statistics.mean(data) == 1.6071428571428572 assert statistics.median(data) == 1.25 assert statistics.variance(data) == 1.3720238095238095 ================================================ FILE: src/standard_libraries/test_re.py ================================================ """String Pattern Matching. @see: https://docs.python.org/3/tutorial/stdlib.html#string-pattern-matching The re module provides regular expression tools for advanced string processing. For complex matching and manipulation, regular expressions offer succinct, optimized solutions: """ import re def test_re(): """String Pattern Matching""" assert re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest') == [ 'foot', 'fell', 'fastest' ] assert re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat') == 'cat in the hat' # When only simple capabilities are needed, string methods are preferred because they are # easier to read and debug: assert 'tea for too'.replace('too', 'two') == 'tea for two' ================================================ FILE: src/standard_libraries/test_zlib.py ================================================ """Data Compression. @see: https://docs.python.org/3/tutorial/stdlib.html#data-compression Common data archiving and compression formats are directly supported by modules including: zlib, gzip, bz2, lzma, zipfile and tarfile. """ import zlib def test_zlib(): """zlib.""" string = b'witch which has which witches wrist watch' assert len(string) == 41 zlib_compressed_string = zlib.compress(string) assert len(zlib_compressed_string) == 37 zlib_decompressed_string = zlib.decompress(zlib_compressed_string) assert zlib_decompressed_string == b'witch which has which witches wrist watch' assert zlib.crc32(string) == 226805979 ================================================ FILE: src/user_input/test_input.py ================================================ """User input @see https://docs.python.org/3/library/functions.html#input User input prompts are very helpful when it comes to interactive programming. Not only in games but also in standard file operations, you may want your user to interact with the program. Therefore, the user needs the opportunity to be able to put in information. """ def user_input(): """Input prompt""" # Printing statement to signal the user that we are waiting for input. user_input = input("Please type in your name\n") # Printing a message based on the input. print(f"Welcome, {user_input}!")