From cfb9b9fda86db909a07c27c882cb35ada53a43d9 Mon Sep 17 00:00:00 2001 From: Remo Giermann Date: Tue, 20 Oct 2020 16:14:26 +0200 Subject: [PATCH 1/2] removing, adding, compressing topics --- README.md | 125 ++++------ README.pt-BR.md | 215 ---------------- src/additions/test_generators.py | 39 --- src/additions/test_pass.py | 46 ---- .../test_class_and_instance_variables.py | 86 ------- src/classes/test_class_definition.py | 46 ---- src/classes/test_class_objects.py | 78 ------ src/classes/test_inheritance.py | 81 ------ src/classes/test_instance_objects.py | 30 --- src/classes/test_method_objects.py | 60 ----- src/classes/test_multiple_inheritance.py | 68 ----- src/control_flow/test_break.py | 25 -- src/control_flow/test_continue.py | 29 --- .../{test_for.py => test_control_flow.py} | 118 ++++++++- src/control_flow/test_if.py | 28 --- src/control_flow/test_try.py | 66 ----- src/control_flow/test_while.py | 31 --- .../{test_strings.py => test_basic_types.py} | 171 +++++-------- src/data_types/test_dictionaries.py | 11 + src/data_types/test_lists.py | 29 --- src/data_types/test_numbers.py | 120 --------- src/data_types/test_sets.py | 70 ------ src/data_types/test_tuples.py | 89 +++++-- src/data_types/test_type_casting.py | 45 ---- src/exceptions/test_handle_exceptions.py | 42 +++- src/exceptions/test_raise_exceptions.py | 49 ---- src/functions/test_arguments.py | 206 ++++++++++++++++ src/functions/test_function_annotations.py | 27 -- .../test_function_arbitrary_arguments.py | 33 --- src/functions/test_function_decorators.py | 91 ------- .../test_function_default_arguments.py | 26 -- .../test_function_documentation_string.py | 42 ---- .../test_function_keyword_arguments.py | 119 --------- src/functions/test_function_scopes.py | 107 -------- .../test_function_unpacking_arguments.py | 30 --- src/functions/test_lambda_expressions.py | 9 +- src/operators/test_arithmetic.py | 44 ---- src/operators/test_assigment.py | 94 ------- src/operators/test_bitwise.py | 57 ----- src/operators/test_comparison.py | 36 --- src/operators/test_identity.py | 35 --- src/operators/test_logical.py | 28 --- src/operators/test_membership.py | 25 -- src/operators/test_operators.py | 232 ++++++++++++++++++ .../glob_files/first_file.txt | 0 .../glob_files/second_file.txt | 0 src/standard_libraries/test_glob.py | 21 -- src/standard_libraries/test_zlib.py | 23 -- 48 files changed, 794 insertions(+), 2288 deletions(-) delete mode 100644 README.pt-BR.md delete mode 100644 src/additions/test_generators.py delete mode 100644 src/additions/test_pass.py delete mode 100644 src/classes/test_class_and_instance_variables.py delete mode 100644 src/classes/test_class_definition.py delete mode 100644 src/classes/test_class_objects.py delete mode 100644 src/classes/test_inheritance.py delete mode 100644 src/classes/test_instance_objects.py delete mode 100644 src/classes/test_method_objects.py delete mode 100644 src/classes/test_multiple_inheritance.py delete mode 100644 src/control_flow/test_break.py delete mode 100644 src/control_flow/test_continue.py rename src/control_flow/{test_for.py => test_control_flow.py} (54%) delete mode 100644 src/control_flow/test_if.py delete mode 100644 src/control_flow/test_try.py delete mode 100644 src/control_flow/test_while.py rename src/data_types/{test_strings.py => test_basic_types.py} (60%) delete mode 100644 src/data_types/test_numbers.py delete mode 100644 src/data_types/test_sets.py delete mode 100644 src/data_types/test_type_casting.py delete mode 100644 src/exceptions/test_raise_exceptions.py create mode 100644 src/functions/test_arguments.py delete mode 100644 src/functions/test_function_annotations.py delete mode 100644 src/functions/test_function_arbitrary_arguments.py delete mode 100644 src/functions/test_function_decorators.py delete mode 100644 src/functions/test_function_default_arguments.py delete mode 100644 src/functions/test_function_documentation_string.py delete mode 100644 src/functions/test_function_keyword_arguments.py delete mode 100644 src/functions/test_function_scopes.py delete mode 100644 src/functions/test_function_unpacking_arguments.py delete mode 100644 src/operators/test_arithmetic.py delete mode 100644 src/operators/test_assigment.py delete mode 100644 src/operators/test_bitwise.py delete mode 100644 src/operators/test_comparison.py delete mode 100644 src/operators/test_identity.py delete mode 100644 src/operators/test_logical.py delete mode 100644 src/operators/test_membership.py create mode 100644 src/operators/test_operators.py delete mode 100644 src/standard_libraries/glob_files/first_file.txt delete mode 100644 src/standard_libraries/glob_files/second_file.txt delete mode 100644 src/standard_libraries/test_glob.py delete mode 100644 src/standard_libraries/test_zlib.py diff --git a/README.md b/README.md index 2a39aa0b..70fb3234 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,32 @@ -# Playground and Cheatsheet for Learning Python +> This is the stripped down version of [Learn +Python](https://github.com/trekhleb/learn-python) by +[Oleksii Trekhleb](https://github.com/trekhleb). If you are missing +something here, go ahead and check out the more comprehensive original +repository. -[![Build Status](https://travis-ci.org/trekhleb/learn-python.svg?branch=master)](https://travis-ci.org/trekhleb/learn-python) +# Playground and Cheatsheet for Learning Python – Distilled version -> This is a collection of Python scripts that are split by [topics](#table-of-contents) and contain +> 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). - -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 +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 +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 +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)_ +## Documentation + +Python homepage: https://python.org + +Language reference: https://docs.python.org/3/reference/index.html + +Standard library reference: https://docs.python.org/3/library/index.html ## How to Use This Repository @@ -35,14 +43,14 @@ Here might go more detailed explanation of the current topic (i.e. general info 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. + + # Lists can be indexed and sliced. # Indexing returns the item. assert squares[0] == 1 # <-- Assertions here illustrate the result. # Slicing returns a new list. @@ -52,10 +60,10 @@ def test_list_type(): 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). +- 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 +- [Run tests](#testing-the-code) and [lint the code](#linting-the-code) to see if it work and is written correctly. ## Table of Contents @@ -64,67 +72,32 @@ written correctly. - [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`) +2. **[Operators](src/operators/test_operators.py)** 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 + - [Basic Types](src/data_types/test_basic_types.py) + - [Lists](src/data_types/test_lists.py) + - [Tuples and Sets](src/data_types/test_tuples.py) - [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) +4. **[Control Flow](src/control_flow/test_control_flow.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) + - [Function Definition](src/functions/test_function_definition.py) + - [Function Argument Possibilities](src/functions/test_arguments.py) + - [Lambda Expressions](src/functions/test_lambda_expressions.py) +6. **Modules** + - [Modules](src/modules/test_modules.py) - [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** +7. **[Exception Handling](src/exceptions/test_handle_exceptions.py)** +8. **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) +9. **Additional Topics (further reading)** + - [The `pass` statement](https://docs.python.org/3/tutorial/controlflow.html#pass-statements) + - [Generators](https://docs.python.org/3/tutorial/classes.html#generators) + - [Classes](https://docs.python.org/3/tutorial/classes.html) +10. **Exercise** + - Process data from an API ## Prerequisites @@ -133,8 +106,8 @@ written correctly. 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 +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 @@ -189,8 +162,8 @@ to [PEP 8](https://www.python.org/dev/peps/pep-0008/) style guide please run: pylint ./src/ ``` -In case if linter will detect error (i.e. `missing-docstring`) you may want to read more about -specific error by running: +In case the linter detects an error (i.e. `missing-docstring`) you may want +to read more about the specific error by running: ```bash pylint --help-msg=missing-docstring @@ -217,4 +190,6 @@ flake8 ./src --statistics --show-source --count ## Supporting the project -You may support this project via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb). +Many thanks to the original author [trekhleb](https://github.com/trekhleb). + +You may support the **original** project via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb). diff --git a/README.pt-BR.md b/README.pt-BR.md deleted file mode 100644 index e6bd025f..00000000 --- a/README.pt-BR.md +++ /dev/null @@ -1,215 +0,0 @@ -# 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). - -É 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). \ No newline at end of file diff --git a/src/additions/test_generators.py b/src/additions/test_generators.py deleted file mode 100644 index ff3bce26..00000000 --- a/src/additions/test_generators.py +++ /dev/null @@ -1,39 +0,0 @@ -"""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 i 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 diff --git a/src/additions/test_pass.py b/src/additions/test_pass.py deleted file mode 100644 index 57a6de9b..00000000 --- a/src/additions/test_pass.py +++ /dev/null @@ -1,46 +0,0 @@ -"""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 diff --git a/src/classes/test_class_and_instance_variables.py b/src/classes/test_class_and_instance_variables.py deleted file mode 100644 index c4004d79..00000000 --- a/src/classes/test_class_and_instance_variables.py +++ /dev/null @@ -1,86 +0,0 @@ -"""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 mistaken 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'] diff --git a/src/classes/test_class_definition.py b/src/classes/test_class_definition.py deleted file mode 100644 index 9251c60e..00000000 --- a/src/classes/test_class_definition.py +++ /dev/null @@ -1,46 +0,0 @@ -"""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' diff --git a/src/classes/test_class_objects.py b/src/classes/test_class_objects.py deleted file mode 100644 index 2d5a4cdb..00000000 --- a/src/classes/test_class_objects.py +++ /dev/null @@ -1,78 +0,0 @@ -"""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) diff --git a/src/classes/test_inheritance.py b/src/classes/test_inheritance.py deleted file mode 100644 index 5884da2c..00000000 --- a/src/classes/test_inheritance.py +++ /dev/null @@ -1,81 +0,0 @@ -"""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) diff --git a/src/classes/test_instance_objects.py b/src/classes/test_instance_objects.py deleted file mode 100644 index e58dc343..00000000 --- a/src/classes/test_instance_objects.py +++ /dev/null @@ -1,30 +0,0 @@ -"""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 diff --git a/src/classes/test_method_objects.py b/src/classes/test_method_objects.py deleted file mode 100644 index 1d4e66a9..00000000 --- a/src/classes/test_method_objects.py +++ /dev/null @@ -1,60 +0,0 @@ -"""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 diff --git a/src/classes/test_multiple_inheritance.py b/src/classes/test_multiple_inheritance.py deleted file mode 100644 index 2ad73f8d..00000000 --- a/src/classes/test_multiple_inheritance.py +++ /dev/null @@ -1,68 +0,0 @@ -"""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 i - nherited 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' diff --git a/src/control_flow/test_break.py b/src/control_flow/test_break.py deleted file mode 100644 index 42e7faa3..00000000 --- a/src/control_flow/test_break.py +++ /dev/null @@ -1,25 +0,0 @@ -"""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 diff --git a/src/control_flow/test_continue.py b/src/control_flow/test_continue.py deleted file mode 100644 index 23c015bd..00000000 --- a/src/control_flow/test_continue.py +++ /dev/null @@ -1,29 +0,0 @@ -"""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] diff --git a/src/control_flow/test_for.py b/src/control_flow/test_control_flow.py similarity index 54% rename from src/control_flow/test_for.py rename to src/control_flow/test_control_flow.py index 7411277b..99c06efe 100644 --- a/src/control_flow/test_for.py +++ b/src/control_flow/test_control_flow.py @@ -1,18 +1,78 @@ -"""FOR statement +""" +Control flow -@see: https://docs.python.org/3/tutorial/controlflow.html +@see https://docs.python.org/3/reference/compound_stmts.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): """ +def test_if_statement(): + """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. + """ + + 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' + +def test_while_statement(): + """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). + """ + + # 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 # pylint: disable=too-many-locals def test_for_statement(): - """FOR statement""" + """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): + """ + # Measure some strings: words = ['cat', 'window', 'defenestrate'] @@ -105,6 +165,48 @@ def test_for_statement(): 'What is your favorite color? It is blue.', ] +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 + +def test_continue_statement(): + """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. + """ + + # 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] def test_range_function(): """Range function diff --git a/src/control_flow/test_if.py b/src/control_flow/test_if.py deleted file mode 100644 index d512267d..00000000 --- a/src/control_flow/test_if.py +++ /dev/null @@ -1,28 +0,0 @@ -"""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' diff --git a/src/control_flow/test_try.py b/src/control_flow/test_try.py deleted file mode 100644 index fed06f59..00000000 --- a/src/control_flow/test_try.py +++ /dev/null @@ -1,66 +0,0 @@ -"""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.' diff --git a/src/control_flow/test_while.py b/src/control_flow/test_while.py deleted file mode 100644 index 4bc58028..00000000 --- a/src/control_flow/test_while.py +++ /dev/null @@ -1,31 +0,0 @@ -"""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 diff --git a/src/data_types/test_strings.py b/src/data_types/test_basic_types.py similarity index 60% rename from src/data_types/test_strings.py rename to src/data_types/test_basic_types.py index ae86432f..00001be3 100644 --- a/src/data_types/test_strings.py +++ b/src/data_types/test_basic_types.py @@ -1,19 +1,71 @@ -"""Strings. +import pytest -@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 +def test_numbers(): + """Numbers. -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. -""" + @see: https://docs.python.org/3/tutorial/introduction.html + @see: https://www.w3schools.com/python/python_numbers.asp -import pytest + 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) + """ + + positive_integer = 1 + negative_integer = -3255522 + big_integer = 35656222554887711 + + assert isinstance(positive_integer, int) + assert isinstance(negative_integer, int) + assert isinstance(big_integer, int) + + + # Booleans + 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" + + # Floating point numbers + float_number = 7.0 + float_negative = -35.59 + float_number_via_function = float(7) + + assert isinstance(float_number, float) + assert isinstance(float_number_via_function, float) + assert isinstance(float_negative, float) + assert float_number == float_number_via_function + + # In exponential notation + 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_string_type(): - """String type""" + """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. + """ # String with double quotes. name_1 = "John" @@ -68,17 +120,6 @@ def test_string_type(): 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] @@ -117,7 +158,6 @@ def test_string_type(): Second line ''' - def test_string_operators(): """Basic operations @@ -198,7 +238,6 @@ def test_string_methods(): assert '1234'.isdecimal() assert not 'a21453'.isdecimal() - def test_string_formatting(): """String formatting. @@ -222,89 +261,3 @@ def test_string_formatting(): 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' diff --git a/src/data_types/test_dictionaries.py b/src/data_types/test_dictionaries.py index da3b9cc8..51fec26e 100644 --- a/src/data_types/test_dictionaries.py +++ b/src/data_types/test_dictionaries.py @@ -77,3 +77,14 @@ def test_dictionary(): assert dictionary_for_string_keys['sape'] == 4139 assert dictionary_for_string_keys['guido'] == 4127 assert dictionary_for_string_keys['jack'] == 4098 + + # You can iterate over the keys of a dictionary: + assert [key for key in dictionary_for_string_keys.keys()] == ['sape', 'guido', 'jack'] + + # You can also iterate over thevalues of a dictionary: + assert [value for value in dictionary_for_string_keys.values()] == [4139, 4127, 4098] + + # And you can iterate over its key-value pairs: + assert [kv for kv in dictionary_for_string_keys.items()] == [('sape', 4139), ('guido', 4127), ('jack', 4098)] + assert [k for (k, v) in dictionary_for_string_keys.items()] == ['sape', 'guido', 'jack'] + assert [v for (k, v) in dictionary_for_string_keys.items()] == [4139, 4127, 4098] diff --git a/src/data_types/test_lists.py b/src/data_types/test_lists.py index 33ffdbe9..dcf7dd49 100644 --- a/src/data_types/test_lists.py +++ b/src/data_types/test_lists.py @@ -169,35 +169,6 @@ def test_list_methods(): 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. diff --git a/src/data_types/test_numbers.py b/src/data_types/test_numbers.py deleted file mode 100644 index 66bb111c..00000000 --- a/src/data_types/test_numbers.py +++ /dev/null @@ -1,120 +0,0 @@ -"""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 diff --git a/src/data_types/test_sets.py b/src/data_types/test_sets.py deleted file mode 100644 index 1dfb1329..00000000 --- a/src/data_types/test_sets.py +++ /dev/null @@ -1,70 +0,0 @@ -"""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'} diff --git a/src/data_types/test_tuples.py b/src/data_types/test_tuples.py index b122824e..f7c615a8 100644 --- a/src/data_types/test_tuples.py +++ b/src/data_types/test_tuples.py @@ -1,21 +1,18 @@ -"""Tuples. - -@see: https://www.w3schools.com/python/python_tuples.asp -@see: https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences +import pytest -A tuple is a collection which is ordered and unchangeable. In Python tuples are written with -round brackets. +def test_tuples(): + """Tuples. -The Tuples have following properties: -- You cannot change values in a tuple. -- You cannot remove items in a tuple. -""" + @see: https://www.w3schools.com/python/python_tuples.asp + @see: https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences -import pytest + A tuple is a collection which is ordered and unchangeable. In Python tuples are written with + round brackets. - -def test_tuples(): - """Tuples""" + The Tuples have following properties: + - You cannot change values in a tuple. + - You cannot remove items in a tuple. + """ fruits_tuple = ("apple", "banana", "cherry") assert isinstance(fruits_tuple, tuple) @@ -86,3 +83,67 @@ def test_tuples(): assert first_number == 456 assert second_number == 123 + + + +def test_sets(): + """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. + """ + 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) + + # 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'} diff --git a/src/data_types/test_type_casting.py b/src/data_types/test_type_casting.py deleted file mode 100644 index e5b1fef3..00000000 --- a/src/data_types/test_type_casting.py +++ /dev/null @@ -1,45 +0,0 @@ -"""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' diff --git a/src/exceptions/test_handle_exceptions.py b/src/exceptions/test_handle_exceptions.py index 342561a3..34f1c189 100644 --- a/src/exceptions/test_handle_exceptions.py +++ b/src/exceptions/test_handle_exceptions.py @@ -9,7 +9,6 @@ It is possible to write programs that handle selected exceptions. """ - def test_handle_exceptions(): """Handling of exceptions @@ -27,6 +26,13 @@ def test_handle_exceptions(): - 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. + + In short: + + 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. """ # Let's simulate division by zero exception. @@ -104,3 +110,37 @@ def test_handle_exceptions(): assert not exception_has_been_handled assert no_exceptions_has_been_fired + + # 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.' + +def test_raise_exception(): + """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. + """ + 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') + except NameError: + exception_is_caught = True + + assert exception_is_caught diff --git a/src/exceptions/test_raise_exceptions.py b/src/exceptions/test_raise_exceptions.py deleted file mode 100644 index 3d5ede1c..00000000 --- a/src/exceptions/test_raise_exceptions.py +++ /dev/null @@ -1,49 +0,0 @@ -"""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 diff --git a/src/functions/test_arguments.py b/src/functions/test_arguments.py new file mode 100644 index 00000000..e446225e --- /dev/null +++ b/src/functions/test_arguments.py @@ -0,0 +1,206 @@ +""" +Function arguments + +- default arguments + @see: https://docs.python.org/3/tutorial/controlflow.html#default-argument-values +- keyword arguments + @see: https://docs.python.org/3/tutorial/controlflow.html#keyword-arguments +- arbitrary argument lists + @see: https://docs.python.org/3/tutorial/controlflow.html#arbitrary-argument-lists +- unpacking argument lists + @see: https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists +""" + +import pytest + +def test_default_function_arguments(): + """ + Default function arguments + + @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. + """ + + # The following function raises a number by the given power. + # By default the function raises number to the power of two. + def power_of(number, power=2): + return number ** power + + # This function 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 + + +def test_function_keyword_arguments(): + """Example of multi-argument function + + @see: https://docs.python.org/3/tutorial/controlflow.html#keyword-arguments + + Functions can be called using keyword arguments of the form kwarg=value. + """ + + # This function accepts one required argument (voltage) and three optional arguments + # (state, action, and type). + def parrot(voltage, state='a stiff', action='voom', parrot_type='Norwegian Blue'): + 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 + # 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 amd 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', + ) + +def test_function_arbitrary_arguments(): + """ + Arbitrary Argument Lists + + @see: https://docs.python.org/3/tutorial/controlflow.html#arbitrary-argument-lists + + Functions 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. + """ + + # 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 amd keywords dictionary.""" + 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' + +def test_function_unpacking_arguments(): + """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. + """ + + # 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!' diff --git a/src/functions/test_function_annotations.py b/src/functions/test_function_annotations.py deleted file mode 100644 index 4c6495e6..00000000 --- a/src/functions/test_function_annotations.py +++ /dev/null @@ -1,27 +0,0 @@ -"""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} diff --git a/src/functions/test_function_arbitrary_arguments.py b/src/functions/test_function_arbitrary_arguments.py deleted file mode 100644 index b3f36627..00000000 --- a/src/functions/test_function_arbitrary_arguments.py +++ /dev/null @@ -1,33 +0,0 @@ -"""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 amd keywords dictionary.""" - 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' diff --git a/src/functions/test_function_decorators.py b/src/functions/test_function_decorators.py deleted file mode 100644 index 1603a5ff..00000000 --- a/src/functions/test_function_decorators.py +++ /dev/null @@ -1,91 +0,0 @@ -"""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!

' diff --git a/src/functions/test_function_default_arguments.py b/src/functions/test_function_default_arguments.py deleted file mode 100644 index aa2a09ad..00000000 --- a/src/functions/test_function_default_arguments.py +++ /dev/null @@ -1,26 +0,0 @@ -"""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 diff --git a/src/functions/test_function_documentation_string.py b/src/functions/test_function_documentation_string.py deleted file mode 100644 index b20d11a9..00000000 --- a/src/functions/test_function_documentation_string.py +++ /dev/null @@ -1,42 +0,0 @@ -"""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. - """ diff --git a/src/functions/test_function_keyword_arguments.py b/src/functions/test_function_keyword_arguments.py deleted file mode 100644 index 65d066c1..00000000 --- a/src/functions/test_function_keyword_arguments.py +++ /dev/null @@ -1,119 +0,0 @@ -"""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 amd 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', - ) diff --git a/src/functions/test_function_scopes.py b/src/functions/test_function_scopes.py deleted file mode 100644 index 5d3525e5..00000000 --- a/src/functions/test_function_scopes.py +++ /dev/null @@ -1,107 +0,0 @@ -"""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. diff --git a/src/functions/test_function_unpacking_arguments.py b/src/functions/test_function_unpacking_arguments.py deleted file mode 100644 index 2e231b2f..00000000 --- a/src/functions/test_function_unpacking_arguments.py +++ /dev/null @@ -1,30 +0,0 @@ -"""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!' diff --git a/src/functions/test_lambda_expressions.py b/src/functions/test_lambda_expressions.py index f4eb1288..ebe4e4d7 100644 --- a/src/functions/test_lambda_expressions.py +++ b/src/functions/test_lambda_expressions.py @@ -8,14 +8,19 @@ definitions, lambda functions can reference variables from the containing scope. """ - def test_lambda_expressions(): """Lambda Expressions""" + # You can assign an anonymous (lambda) function to a variable and use it like a usual function + square = lambda x: x * x + + assert square(2) == 4 + assert square(3) == 9 + assert square(4) == 16 + # 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 diff --git a/src/operators/test_arithmetic.py b/src/operators/test_arithmetic.py deleted file mode 100644 index fa66ad66..00000000 --- a/src/operators/test_arithmetic.py +++ /dev/null @@ -1,44 +0,0 @@ -"""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) diff --git a/src/operators/test_assigment.py b/src/operators/test_assigment.py deleted file mode 100644 index dedfca47..00000000 --- a/src/operators/test_assigment.py +++ /dev/null @@ -1,94 +0,0 @@ -"""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 diff --git a/src/operators/test_bitwise.py b/src/operators/test_bitwise.py deleted file mode 100644 index 20118a16..00000000 --- a/src/operators/test_bitwise.py +++ /dev/null @@ -1,57 +0,0 @@ -"""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 diff --git a/src/operators/test_comparison.py b/src/operators/test_comparison.py deleted file mode 100644 index 55ce1492..00000000 --- a/src/operators/test_comparison.py +++ /dev/null @@ -1,36 +0,0 @@ -"""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 diff --git a/src/operators/test_identity.py b/src/operators/test_identity.py deleted file mode 100644 index 1450801c..00000000 --- a/src/operators/test_identity.py +++ /dev/null @@ -1,35 +0,0 @@ -"""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 diff --git a/src/operators/test_logical.py b/src/operators/test_logical.py deleted file mode 100644 index 87aa7592..00000000 --- a/src/operators/test_logical.py +++ /dev/null @@ -1,28 +0,0 @@ -"""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 diff --git a/src/operators/test_membership.py b/src/operators/test_membership.py deleted file mode 100644 index cf5ed03e..00000000 --- a/src/operators/test_membership.py +++ /dev/null @@ -1,25 +0,0 @@ -"""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 diff --git a/src/operators/test_operators.py b/src/operators/test_operators.py new file mode 100644 index 00000000..0215d266 --- /dev/null +++ b/src/operators/test_operators.py @@ -0,0 +1,232 @@ +""" +Operators overview + +@see: https://docs.python.org/3/reference/lexical_analysis.html#operators + +@note: for brevity, bitwise operators have been left out. +""" + +def test_arithmetic_operators(): + """Arithmetic operators + + @see: https://www.w3schools.com/python/python_operators.asp + + Arithmetic operators are used with numeric values to perform common mathematical operations + """ + + # 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) + + +def test_comparison_operators(): + """Comparison operators + + @see: https://www.w3schools.com/python/python_operators.asp + + Comparison operators are used to compare two values. + """ + + # 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 + +def test_logical_operators(): + """Logical operators + + @see: https://www.w3schools.com/python/python_operators.asp + + Logical operators are used to combine boolean values. + """ + + # Let's work with these numbers 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 + +def test_identity_operators(): + """Identity operators + + @see: https://www.w3schools.com/python/python_operators.asp + + Identity operators are used to compare two objects, not for equality, but whether they are actually + the same object, with the same memory location. + """ + + # 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 + +def test_membership_operators(): + """Membership operators + + @see: https://www.w3schools.com/python/python_operators.asp + + Membership operators are used to test if an element is present in a sequence. + """ + + # 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 + +def test_assignment_operator(): + """Assignment operators + + @see: https://www.w3schools.com/python/python_operators.asp + + Assignment operators are used to assign values to variables + """ + + # 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 diff --git a/src/standard_libraries/glob_files/first_file.txt b/src/standard_libraries/glob_files/first_file.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/src/standard_libraries/glob_files/second_file.txt b/src/standard_libraries/glob_files/second_file.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/src/standard_libraries/test_glob.py b/src/standard_libraries/test_glob.py deleted file mode 100644 index c236f73c..00000000 --- a/src/standard_libraries/test_glob.py +++ /dev/null @@ -1,21 +0,0 @@ -"""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' - ]) diff --git a/src/standard_libraries/test_zlib.py b/src/standard_libraries/test_zlib.py deleted file mode 100644 index 55335b58..00000000 --- a/src/standard_libraries/test_zlib.py +++ /dev/null @@ -1,23 +0,0 @@ -"""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 From 1e3cd3247fe696ca04db7a0451eb40e421598c17 Mon Sep 17 00:00:00 2001 From: Remo Giermann Date: Thu, 5 Nov 2020 13:22:57 +0100 Subject: [PATCH 2/2] added API example code as an exercise --- src/exercise/helper.py | 17 +++++++++++++++++ src/exercise/main.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/exercise/helper.py create mode 100644 src/exercise/main.py diff --git a/src/exercise/helper.py b/src/exercise/helper.py new file mode 100644 index 00000000..c805814f --- /dev/null +++ b/src/exercise/helper.py @@ -0,0 +1,17 @@ +import json + +def prettyPrintJSON(obj, indent=1): + print(json.dumps(obj, indent)) + +def printTable(keys, rows): + table = [[key] + [str(row[key]) for row in rows] for key in keys] + columnWidths = [max(len(row) for row in column) for column in table] + numColumns = len(keys) + lineLength = sum(columnWidths) + 3 * numColumns + + print(*[k.rjust(columnWidths[i]) for i, k in enumerate(keys)], sep=' | ') + print(lineLength * '=') + + for row in rows: + values = [str(row[k]) for k in keys] + print(*[v.rjust(columnWidths[i]) for i, v in enumerate(values)], sep=' | ') diff --git a/src/exercise/main.py b/src/exercise/main.py new file mode 100644 index 00000000..0774115e --- /dev/null +++ b/src/exercise/main.py @@ -0,0 +1,31 @@ +import requests +import json + +from helper import * + +def getCountryData(countryCode): + res = requests.get(f'https://restcountries.eu/rest/v2/alpha/{countryCode}') + res.raise_for_status() + return res.json() + +def getCovidGlobalSummary(): + res = requests.get('https://api.covid19api.com/summary') + res.raise_for_status() + return res.json() + +def printGlobalSummary(sortBy=['TotalConfirmed', 'NewConfirmed']): + summary = getCovidGlobalSummary() + globalCases, countries = summary['Global'], summary['Countries'] + + for sortKey in reversed(sortBy): + countries.sort(key=lambda x: x[sortKey], reverse=True) + + print(f"Summary: global cases: {globalCases['TotalConfirmed']} (+{globalCases['NewConfirmed']}) confirmed", end=', ') + print(f"{globalCases['TotalDeaths']} (+{globalCases['NewDeaths']}) deaths") + print() + + printTable(['Country', 'NewConfirmed', 'TotalConfirmed', 'NewDeaths', 'TotalDeaths'], countries) + + +if __name__ == '__main__': + printGlobalSummary()