+
+ OUTPUT
+
+
+
+
+
+RangeIndex: 3853648 entries, 0 to 3853647
+Data columns (total 18 columns):
+# Column Dtype
+--- ------ -----
+0 city object
+1 city_ibge_code float64
+2 date object
+3 epidemiological_week int64
+4 estimated_population float64
+5 estimated_population_2019 float64
+6 is_last bool
+7 is_repeated bool
+8 last_available_confirmed int64
+9 last_available_confirmed_per_100k_inhabitants float64
+10 last_available_date object
+11 last_available_death_rate float64
+12 last_available_deaths int64
+13 order_for_place int64
+14 place_type object
+15 state object
+16 new_confirmed int64
+17 new_deaths int64
+dtypes: bool(2), float64(5), int64(6), object(5)
+memory usage: 477.8+ MB
+
+
+
+
E para demonstrar o verdadeiro poder do Ibis, iremos transformar nosso arquivo CSV em uma Base de Dados SQL. Na instalação padrão do Ibis, o backend SQL é o `sqlite3`, então nos exemplos a seguir utilizaremos SQLite para realizar buscas na base de dados. Caso queira utilizar outra Engine SQL, como [BigQuery](https://github.com/ibis-project/ibis-bigquery/) ou [Postgres](https://ibis-project.org/docs/3.1.0/backends/PostgreSQL/), acesse a [documentação oficial](https://ibis-project.org/docs/3.1.0/backends/PostgreSQL/) e siga instruções de instalação.
@@ -255,7 +267,17 @@ df.to_sql('casos_covid19_BR', sqlite3.connect('data/casof.db'))
- 3853648
+
+
+ OUTPUT
+
+
+
+
+2020-02-25
+2022-03-27
+
+
+
+
## E por que usar Ibis ao invés das ferramentas SQL diretamente?
@@ -312,9 +344,19 @@ Por exemplo: já vimos que é possível criar buscas SQL através de expressões
print(data_min.compile())
```
- SELECT min(t0.date) AS first_entry
- FROM main."casos_covid19_BR" AS t0
-
+
+
+ OUTPUT
+
+
+
+
+SELECT min(t0.date) AS first_entry
+FROM main."casos_covid19_BR" AS t0
+
+
+
+
Um dos pontos chave do Ibis, é a possibilidade de criar Expressões com o resultado de interesse, renomeá-las, e utilizá-las para outras buscas sem precisar repetir código:
@@ -348,9 +390,19 @@ epiweek_covid = casos.group_by('epidemiological_week').aggregate((
print(epiweek_covid.compile())
```
- SELECT t0.epidemiological_week, sum(t0.new_confirmed) AS total_new_cases, sum(t0.new_deaths) AS total_new_deaths
- FROM main."casos_covid19_BR" AS t0 GROUP BY t0.epidemiological_week
-
+
+
+ OUTPUT
+
+
+
+
+SELECT t0.epidemiological_week, sum(t0.new_confirmed) AS total_new_cases, sum(t0.new_deaths) AS total_new_deaths
+FROM main."casos_covid19_BR" AS t0 GROUP BY t0.epidemiological_week
+
+
+
+
Lembra que o Ibis utiliza o Pandas como Backend de execução? Podemos agora salvar o Pandas DataFrame gerado na execução em uma variável para termos acesso às funções do Pandas:
@@ -363,67 +415,69 @@ df.head()
+
+
+ OUTPUT
+
+
+
+
+SELECT (t0.new_confirmed / t0.estimated_population) * 100 AS porc_cases
+FROM main."casos_covid19_BR" AS t0
+
+
+
+
```python
@@ -576,9 +642,19 @@ print(south_br.compile().compile(
compile_kwargs={"literal_binds": True}))
```
- SELECT CASE WHEN (t0.state = 'SC') THEN 'Santa Catarina' WHEN (t0.state = 'RS') THEN 'Rio Grande do Sul' WHEN (t0.state = 'PR') THEN 'Parana' ELSE CAST(NULL AS TEXT) END AS "Regiao Sul"
- FROM main."casos_covid19_BR" AS t0
-
+
+
+ OUTPUT
+
+
+
+
+SELECT CASE WHEN (t0.state = 'SC') THEN 'Santa Catarina' WHEN (t0.state = 'RS') THEN 'Rio Grande do Sul' WHEN (t0.state = 'PR') THEN 'Parana' ELSE CAST(NULL AS TEXT) END AS "Regiao Sul"
+FROM main."casos_covid19_BR" AS t0
+
+
+
+
Agora que temos a porcentagem de casos e a região separadas em duas variáveis, podemos agregar as buscas e encontrar as porcentagem de casos nos estados em questão e retorná-lo em Dataframe:
@@ -589,11 +665,21 @@ sul = casos.group_by(south_br).aggregate(percentage_cases.mean().name('Media Cas
print(sul.compile().compile(compile_kwargs={"literal_binds": True}))
```
- SELECT t0."Regiao Sul", t0."Media Casos"
- FROM (SELECT CASE WHEN (t1.state = 'SC') THEN 'Santa Catarina' WHEN (t1.state = 'RS') THEN 'Rio Grande do Sul' WHEN (t1.state = 'PR') THEN 'Parana' ELSE CAST(NULL AS TEXT) END AS "Regiao Sul", avg((t1.new_confirmed / t1.estimated_population) * 100) AS "Media Casos"
- FROM main."casos_covid19_BR" AS t1 GROUP BY CASE WHEN (t1.state = 'SC') THEN 'Santa Catarina' WHEN (t1.state = 'RS') THEN 'Rio Grande do Sul' WHEN (t1.state = 'PR') THEN 'Parana' ELSE CAST(NULL AS TEXT) END) AS t0
- WHERE t0."Regiao Sul" IS NOT NULL AND t0."Media Casos" IS NOT NULL
-
+
+
+ OUTPUT
+
+
+
+
+SELECT t0."Regiao Sul", t0."Media Casos"
+FROM (SELECT CASE WHEN (t1.state = 'SC') THEN 'Santa Catarina' WHEN (t1.state = 'RS') THEN 'Rio Grande do Sul' WHEN (t1.state = 'PR') THEN 'Parana' ELSE CAST(NULL AS TEXT) END AS "Regiao Sul", avg((t1.new_confirmed / t1.estimated_population) * 100) AS "Media Casos"
+FROM main."casos_covid19_BR" AS t1 GROUP BY CASE WHEN (t1.state = 'SC') THEN 'Santa Catarina' WHEN (t1.state = 'RS') THEN 'Rio Grande do Sul' WHEN (t1.state = 'PR') THEN 'Parana' ELSE CAST(NULL AS TEXT) END) AS t0
+WHERE t0."Regiao Sul" IS NOT NULL AND t0."Media Casos" IS NOT NULL
+
+
+
+
```python
@@ -604,50 +690,52 @@ sul.execute()
+
+
+ OUTPUT
+
+
+
+
+Overwriting .makim.yaml
+
+
+
```python
@@ -176,11 +186,21 @@ groups:
!makim --makim-file ./.makim.yaml frontend_vue.build
```
- Linting Python code...
- Running Java backend tests...
- Running React frontend tests...
- Building Vue.js frontend...
-
+
+
+ OUTPUT
+
+
+
+
+Linting Python code...
+Running Java backend tests...
+Running React frontend tests...
+Building Vue.js frontend...
+
+
+
+
## Conclusion
diff --git a/pages/blog/unlocking-the-power-of-multiple-dispatch-in-python-with-plum-dispatch/header.png b/pages/blog/unlocking-the-power-of-multiple-dispatch-in-python-with-plum-dispatch/header.png
new file mode 100644
index 00000000..bbcca2fd
Binary files /dev/null and b/pages/blog/unlocking-the-power-of-multiple-dispatch-in-python-with-plum-dispatch/header.png differ
diff --git a/pages/blog/unlocking-the-power-of-multiple-dispatch-in-python-with-plum-dispatch/index.ipynb b/pages/blog/unlocking-the-power-of-multiple-dispatch-in-python-with-plum-dispatch/index.ipynb
new file mode 100644
index 00000000..1fd01fb7
--- /dev/null
+++ b/pages/blog/unlocking-the-power-of-multiple-dispatch-in-python-with-plum-dispatch/index.ipynb
@@ -0,0 +1,211 @@
+{
+ "cells": [
+ {
+ "cell_type": "raw",
+ "id": "f170f83a-7776-4ed8-b295-4eb57b5d0219",
+ "metadata": {},
+ "source": [
+ "---\n",
+ "title: \"Unlocking the Power of Multiple Dispatch in Python with Plum-Dispatch\"\n",
+ "slug: unlocking-the-power-of-multiple-dispatch-in-python-with-plum-dispatch\n",
+ "date: 2024-01-05\n",
+ "authors: [\"Ivan Ogasawara\"]\n",
+ "tags: [open-source, multiple-dispatch, python]\n",
+ "categories: [python]\n",
+ "description: |\n",
+ " ...\n",
+ "thumbnail: \"/header.png\"\n",
+ "template: \"blog-post.html\"\n",
+ "---"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "46aadcef-e7c2-480a-bf3a-bbe20d09cc3b",
+ "metadata": {},
+ "source": [
+ "Python, known for its simplicity and readability, sometimes requires a bit of creativity when it comes to implementing certain programming paradigms. One such paradigm is multiple dispatch (or multimethods), which allows functions to behave differently based on the type of their arguments. While not natively supported in Python, this feature can be incredibly powerful, particularly in complex applications such as mathematical computations, data processing, or when working with abstract syntax trees (ASTs). This is where `plum-dispatch` comes into play.\n",
+ "\n",
+ "## What is Multiple Dispatch?\n",
+ "\n",
+ "Multiple dispatch is a feature where the function to be executed is determined by the types of multiple arguments. This is different from single dispatch (which Python supports natively via the `functools.singledispatch` decorator), where the function called depends only on the type of the first argument.\n",
+ "\n",
+ "## Introducing Plum-Dispatch\n",
+ "\n",
+ "`plum-dispatch` is a Python library that provides an efficient and easy-to-use implementation of multiple dispatch. It allows you to define multiple versions of a function, each tailored to different types of input arguments.\n",
+ "\n",
+ "### Installation\n",
+ "\n",
+ "First things first, let's install `plum-dispatch`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "5d233782-8974-4758-aac8-0a6cfe757376",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "!pip install plum-dispatch -q"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "84a8444d-6f2b-442e-8ab8-44f92c645c01",
+ "metadata": {},
+ "source": [
+ "### Basic Usage\n",
+ "\n",
+ "To demonstrate the basic usage of `plum-dispatch`, let's start with a simple example. Suppose we have a function that needs to behave differently when passed an integer versus when it's passed a string."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "8a1320a3-4531-4d60-80af-4c8ae6301ad4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from plum import dispatch\n",
+ "\n",
+ "class Processor:\n",
+ " @dispatch\n",
+ " def process(self, data: int):\n",
+ " return f\"Processing integer: {data}\"\n",
+ "\n",
+ " @dispatch\n",
+ " def process(self, data: str):\n",
+ " return f\"Processing string: {data}\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b396547c-3601-4d32-b6b3-25eba3c13be0",
+ "metadata": {},
+ "source": [
+ "In this example, `Processor` has two `process` methods, one for integers and one for strings. `plum-dispatch` takes care of determining which method to call based on the type of `data`."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6f2f654d-c142-408b-981c-ea0f4875a36d",
+ "metadata": {},
+ "source": [
+ "### Advanced Example: Working with ASTs\n",
+ "\n",
+ "`plum-dispatch` shines in more complex scenarios, such as when working with different types of nodes in an abstract syntax tree. Let's create a simple AST representation with different node types and a visitor class to process these nodes."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "4314c83a-8c69-41e7-be27-7738cd1003a9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class StringNode:\n",
+ " def __init__(self, value):\n",
+ " self.value = value\n",
+ "\n",
+ "class NumberNode:\n",
+ " def __init__(self, value):\n",
+ " self.value = value\n",
+ "\n",
+ "class BaseASTVisitor:\n",
+ " @dispatch\n",
+ " def visit(self, node: StringNode):\n",
+ " raise Exception(\"Not implemented yet.\")\n",
+ "\n",
+ " @dispatch\n",
+ " def visit(self, node: NumberNode):\n",
+ " raise Exception(\"Not implemented yet.\")\n",
+ "\n",
+ "class ASTVisitor(BaseASTVisitor):\n",
+ " @dispatch\n",
+ " def visit(self, node: StringNode):\n",
+ " return f\"Visited StringNode with value: {node.value}\"\n",
+ "\n",
+ " @dispatch\n",
+ " def visit(self, node: NumberNode):\n",
+ " return f\"Visited NumberNode with value: {node.value}\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d04e9401-e2a3-415a-9b85-0d1e0bf459e6",
+ "metadata": {},
+ "source": [
+ "With `plum-dispatch`, our `ASTVisitor` can have a single `visit` method that behaves differently depending on whether it's visiting a `StringNode` or a `NumberNode`."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "312c3a2f-27b4-4abc-ab0d-ab6cd531066d",
+ "metadata": {},
+ "source": [
+ "### Putting It All Together\n",
+ "Now, let's see `plum-dispatch` in action:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "a321b28b-25ab-47a7-bd28-bbed52107952",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Processing integer: 123\n",
+ "Processing string: abc\n",
+ "Visited StringNode with value: Hello\n",
+ "Visited NumberNode with value: 456\n"
+ ]
+ }
+ ],
+ "source": [
+ "processor = Processor()\n",
+ "print(processor.process(123)) # \"Processing integer: 123\"\n",
+ "print(processor.process(\"abc\")) # \"Processing string: abc\"\n",
+ "\n",
+ "visitor = ASTVisitor()\n",
+ "print(visitor.visit(StringNode(\"Hello\"))) # \"Visited StringNode with value: Hello\"\n",
+ "print(visitor.visit(NumberNode(456))) # \"Visited NumberNode with value: 456\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1045a8fa-87ca-44fa-86ea-425429377ee1",
+ "metadata": {},
+ "source": [
+ "## Conclusion\n",
+ "\n",
+ "`plum-dispatch` offers a neat and powerful way to implement multiple dispatch in Python, making your code more modular, readable, and elegant. Whether you're dealing with simple data types or complex structures like ASTs, `plum-dispatch` can help you write more efficient and maintainable code.\n",
+ "\n",
+ "For more complex examples and advanced usage, check out the [plum-dispatch documentation](https://github.com/wesselb/plum)."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/pages/blog/unlocking-the-power-of-multiple-dispatch-in-python-with-plum-dispatch/index.md b/pages/blog/unlocking-the-power-of-multiple-dispatch-in-python-with-plum-dispatch/index.md
new file mode 100644
index 00000000..66172a73
--- /dev/null
+++ b/pages/blog/unlocking-the-power-of-multiple-dispatch-in-python-with-plum-dispatch/index.md
@@ -0,0 +1,121 @@
+---
+title: "Unlocking the Power of Multiple Dispatch in Python with Plum-Dispatch"
+slug: unlocking-the-power-of-multiple-dispatch-in-python-with-plum-dispatch
+date: 2024-01-05
+authors: ["Ivan Ogasawara"]
+tags: [open-source, multiple-dispatch, python]
+categories: [python]
+description: |
+ ...
+thumbnail: "/header.png"
+template: "blog-post.html"
+---
+Python, known for its simplicity and readability, sometimes requires a bit of creativity when it comes to implementing certain programming paradigms. One such paradigm is multiple dispatch (or multimethods), which allows functions to behave differently based on the type of their arguments. While not natively supported in Python, this feature can be incredibly powerful, particularly in complex applications such as mathematical computations, data processing, or when working with abstract syntax trees (ASTs). This is where `plum-dispatch` comes into play.
+
+## What is Multiple Dispatch?
+
+Multiple dispatch is a feature where the function to be executed is determined by the types of multiple arguments. This is different from single dispatch (which Python supports natively via the `functools.singledispatch` decorator), where the function called depends only on the type of the first argument.
+
+## Introducing Plum-Dispatch
+
+`plum-dispatch` is a Python library that provides an efficient and easy-to-use implementation of multiple dispatch. It allows you to define multiple versions of a function, each tailored to different types of input arguments.
+
+### Installation
+
+First things first, let's install `plum-dispatch`:
+
+
+```python
+!pip install plum-dispatch -q
+```
+
+### Basic Usage
+
+To demonstrate the basic usage of `plum-dispatch`, let's start with a simple example. Suppose we have a function that needs to behave differently when passed an integer versus when it's passed a string.
+
+
+```python
+from plum import dispatch
+
+class Processor:
+ @dispatch
+ def process(self, data: int):
+ return f"Processing integer: {data}"
+
+ @dispatch
+ def process(self, data: str):
+ return f"Processing string: {data}"
+```
+
+In this example, `Processor` has two `process` methods, one for integers and one for strings. `plum-dispatch` takes care of determining which method to call based on the type of `data`.
+
+### Advanced Example: Working with ASTs
+
+`plum-dispatch` shines in more complex scenarios, such as when working with different types of nodes in an abstract syntax tree. Let's create a simple AST representation with different node types and a visitor class to process these nodes.
+
+
+```python
+class StringNode:
+ def __init__(self, value):
+ self.value = value
+
+class NumberNode:
+ def __init__(self, value):
+ self.value = value
+
+class BaseASTVisitor:
+ @dispatch
+ def visit(self, node: StringNode):
+ raise Exception("Not implemented yet.")
+
+ @dispatch
+ def visit(self, node: NumberNode):
+ raise Exception("Not implemented yet.")
+
+class ASTVisitor(BaseASTVisitor):
+ @dispatch
+ def visit(self, node: StringNode):
+ return f"Visited StringNode with value: {node.value}"
+
+ @dispatch
+ def visit(self, node: NumberNode):
+ return f"Visited NumberNode with value: {node.value}"
+```
+
+With `plum-dispatch`, our `ASTVisitor` can have a single `visit` method that behaves differently depending on whether it's visiting a `StringNode` or a `NumberNode`.
+
+### Putting It All Together
+Now, let's see `plum-dispatch` in action:
+
+
+```python
+processor = Processor()
+print(processor.process(123)) # "Processing integer: 123"
+print(processor.process("abc")) # "Processing string: abc"
+
+visitor = ASTVisitor()
+print(visitor.visit(StringNode("Hello"))) # "Visited StringNode with value: Hello"
+print(visitor.visit(NumberNode(456))) # "Visited NumberNode with value: 456"
+```
+
+
+
+ OUTPUT
+
+
+
+
+Processing integer: 123
+Processing string: abc
+Visited StringNode with value: Hello
+Visited NumberNode with value: 456
+
+
+
+
+
+## Conclusion
+
+`plum-dispatch` offers a neat and powerful way to implement multiple dispatch in Python, making your code more modular, readable, and elegant. Whether you're dealing with simple data types or complex structures like ASTs, `plum-dispatch` can help you write more efficient and maintainable code.
+
+For more complex examples and advanced usage, check out the [plum-dispatch documentation](https://github.com/wesselb/plum).
diff --git a/theme/css/styles.css b/theme/css/styles.css
index 42bb4dee..1b0a4451 100644
--- a/theme/css/styles.css
+++ b/theme/css/styles.css
@@ -1512,7 +1512,7 @@ code{
word-break:break-all
}
code.noClass{
- --inlineColor: rgb(194, 29, 0);
+ --inlineColor: #d63384;
color:var(--inlineColor);
display:inline;
line-break:anywhere
@@ -1563,11 +1563,12 @@ code.noClass{
margin:0
}
.highlight pre{
- color:var(--light) !important;
+ /* color:var(--light) !important; */
border-radius:4px;
font-family:'Monaco', monospace;
padding-top:1.5rem;
- padding-bottom:2rem
+ padding-bottom:2rem;
+ padding-left: 10px;
}
.highlight table{
display:grid;
@@ -1755,5 +1756,49 @@ a.page-number.active {
.highlight *{
- color: white!important;
+ background: #44002e!important;
+}
+
+.highlight span.n,
+.highlight span.o {
+ color: #ff7b72;
+}
+
+.highlight span.fm {
+ color: #447fcf;
+}
+
+.highlight span.p {
+ color: white;
+}
+
+.highlight span.bp {
+ color: #ffa657;
+}
+
+.language-text.highlight *{
+ background-color: #333!important;
+}
+
+.language-text.highlight code.noClass{
+ --inlineColor: white!important;
+ color: var(--inlineColor)!important;
+}
+
+.language-text.highlight .output {
+ padding-bottom: 0px;
+}
+
+.code-output {
+ border-top: 10px solid #383838;
+}
+
+
+.code-label {
+ font-size: 18px;
+ border-bottom: 1px solid #fafafa;
+ line-height: 23.4px;
+ position: absolute;
+ right: 25px;
+ margin-top: 15px;
}
diff --git a/theme/custom-markdown.tpl b/theme/custom-markdown.tpl
new file mode 100644
index 00000000..1b215ea9
--- /dev/null
+++ b/theme/custom-markdown.tpl
@@ -0,0 +1,29 @@
+{% extends 'markdown/index.md.j2'%}
+{% block data_text %}
+
+
+ OUTPUT
+
+
+
+ {{ super().split('\n') | map('trim') | join('\n') }}
+
+
+{% endblock data_text %}
+
+{% block data_html %}
+{{ super().split('\n') | map('trim') | join('\n') }}
+{% endblock data_html %}
+
+
+{% block stream %}
+
+
+ OUTPUT
+
+
+
+ {{ super().split('\n') | map('trim') | join('\n') }}
+
+
+{% endblock stream %}