[[ch_closure_decorator]]
== Decoradores e Clausuras
:example-number: 0
:figure-number: 0

[quote, PEP 318—Decorators for Functions and Methods ("Decoradores para Funções e Métodos"—EN)]
____

Houve uma certa quantidade de reclamações sobre a escolha do nome "decorador" para esse recurso. A mais frequente foi sobre o nome não ser consistente com seu uso no livro da GoF.footnote:[GoF se refere ao livro __Design Patterns__ (traduzido no Brasil como _"Padrões de Projeto"_), de 1985. Seus (quatro) autores ficaram conhecidos como a "Gang of Four" (_Gangue dos Quatro_).] O nome ++decorator++ provavelmente se origina de seu uso no âmbito dos compiladores--uma árvore sintática é percorrida e anotada.
____

Decoradores de função((("decorators and closures", "purpose of"))) nos permitem "marcar" funções no código-fonte, para aprimorar de alguma forma seu comportamento.
É um mecanismo muito poderoso. Por exemplo, o decorador `@functools.cache`
armazena um mapeamento de argumentos para resultados,
e depois usa esse mapeamento para evitar computar novamente o resultado quando a função é chamada com argumentos já vistos. Isso pode acelerar muito uma aplicação.

Mas para dominar esse recurso é preciso antes entender clausuras (_closures_)—o nome dado à estrutura onde uma função captura variáveis presentes no escopo onde a função é definida, necessárias para a execução da função futuramente.footnote:[NT: Adotamos a tradução "clausura" para "closure". Alguns autores usam "fechamento". O termo em inglês é pronunciado "clôujure", e o nome da linguagem Clojure brinca com esse fato. Gosto da palavra clausura por uma analogia cultural. Em conventos, a clausura é um espaço fechado onde algumas freiras vivem isoladas. Suas memórias são seu único vínculo com o exterior, mas elas refletem o mundo do passado. Em programação, uma clausura é um espaço isolado onde a função tem acesso a variáveis que existiam quando a própria função foi criada, variáveis de um escopo que não existe mais, preservadas apenas na memória clausura.]

A palavra reservada mais obscura de Python é `nonlocal`, introduzida no Python 3.0.
É perfeitamente possível ter uma vida produtiva e lucrativa programando em Python sem jamais usá-la,
seguindo uma dieta estrita de orientação a objetos centrada em classes.
Entretanto, caso queira implementar seus próprios decoradores de função,
precisa entender clausuras, e então a necessidade de `nonlocal` fica evidente.

Além de sua aplicação aos decoradores, clausuras também são essenciais para qualquer tipo de programação utilizando _callbacks_, e para codar em um estilo funcional quando isso fizer sentido.

O((("decorators and closures", "topics covered"))) objetivo último deste capítulo é explicar exatamente como funcionam os decoradores de função, desde simples decoradores de registro até os complicados decoradores parametrizados. Mas antes de chegar a esse objetivo, precisamos tratar de:

* Como Python analisa a sintaxe de decoradores
* Como Python decide se uma variável é local
* Porque clausuras existem e como elas funcionam
* Qual problema é resolvido por `nonlocal`

Após criar essa base, poderemos então enfrentar os outros tópicos relativos aos decoradores:

* A implementação de um decorador bem comportado
* Os poderosos decoradores na biblioteca padrão: `@cache`, `@lru_cache`, e `@singledispatch`
* A implementação de um decorador parametrizado


=== Novidades neste capítulo

O((("decorators and closures", "significant changes to"))) decorador de _caching_ `functools.cache`—introduzido no Python 3.9—é mais simples que o tradicional `functools.lru_cache`, então falo primeiro daquele. Este último é tratado na <<lru_cache_sec>>, incluindo a forma simplificada introduzida no Python 3.8.

A <<generic_functions>> foi expandida e agora inclui dicas de tipo, a forma recomendada de usar `functools.singledispatch` desde o Python 3.7.

A <<parameterized_dec_sec>> agora inclui um exemplo baseado em classes, o <<clockdeco_param_cls_ex>>.

Transferi o pass:[<a href="#ch_design_patterns" data-type="xref" data-xrefstyle="chap-num-title">#ch_design_patterns</a>] para o final da <<function_objects_part>>, para melhorar a fluidez do livro.
E a <<decorated_strategy>> também aparece agora naquele capítulo, juntamente com outras variantes do padrão de projeto Estratégia usando invocáveis.

Começamos com uma introdução muito suave aos decoradores, e dali seguiremos para o restante dos tópicos listados no início do capítulo.


=== Introdução aos decoradores

Um((("decorators and closures", "decorator basics", id="DACbasic09"))) decorador é um invocável que recebe outra função como um argumento (a função decorada).

Um decorador pode executar algum processamento com a função decorada, e ou a devolve ou a substitui por outra função ou por um objeto invocável.footnote:[Se você substituir "função"por "classe" na sentença anterior, o resultado é uma descrição resumida do papel de um decorador de classe. Decoradores de classe são tratadas no <<ch_class_metaprog>>.]

Em outras palavras, supondo a existência de um decorador chamado `decorate`, esse código:

[source, python]
----
@decorate
def target():
    print('running target()')
----

tem o mesmo efeito de:

[source, python]
----
def target():
    print('running target()')

target = decorate(target)
----

O resultado final é o mesmo: após a execução de qualquer dos dois trechos, o nome `target` está vinculado a qualquer que seja a função devolvida por `decorate(target)`—que tanto pode ser a função inicialmente chamada `target` quanto uma outra função diferente.

Para confirmar que a função decorada é substituída, veja a sessão de console no <<decorator_replaces>>.

[[decorator_replaces]]
.Um decorador normalmente substitui uma função por outra, diferente
====
[source, python]
----
>>> def deco(func):
...     def inner():
...         print('running inner()')
...     return inner  <1>
...
>>> @deco
... def target():  <2>
...     print('running target()')
...
>>> target()  <3>
running inner()
>>> target  <4>
<function deco.<locals>.inner at 0x10063b598>
----
====
<1> `deco` devolve seu objeto função `inner`.
<2> `target` é decorada por `deco`.
<3> Invocar a `target` decorada causa, na verdade, a execução de `inner`.
<4> A inspeção revela que `target` é agora uma referência a `inner`.


Estritamente falando, decoradores são apenas açúcar sintático. Como vimos, é sempre possível chamar um decorador como um invocável normal, passando outra função como parâmetro. Algumas vezes isso inclusive é conveniente, especialmente quando estamos fazendo _metaprogramação_—mudando o comportamento de um programa durante a execução.

[role="pagebreak-before less_space"]
Três fatos essenciais nos dão um bom resumo dos decoradores:

* Um decorador é uma função ou outro invocável.
* Um decorador pode substituir a função decorada por outra, diferente.
* Decoradores são executados imediatamente quando um módulo é carregado.

Vamos agora nos concentrar nesse terceiro ponto.((("", startref="DACbasic09")))


=== Quando Python executa decoradores

Uma((("decorators and closures", "decorator execution")))((("import time versus runtime"))) característica fundamental dos decoradores é serem executados logo após a função decorada ser definida. Isso normalmente acontece no _tempo de importação_ (isto é, quando um módulo é carregado pelo Python). Observe _registration.py_ no <<registration_ex>>.

[[registration_ex]]
.O módulo registration.py
====
[source, python]
----
include::../code/09-closure-deco/registration.py[tags=REGISTRATION]
----
====
<1> `registry` vai manter referências para funções decoradas por `@register`.
<2> `register` recebe uma função como argumento.
<3> Exibe a função que está sendo decorada, para fins de demonstração.
<4> Insere `func` em `registry`.
<5> Devolve `func`: precisamos devolver uma função; aqui devolvemos a mesma função recebida como argumento.
<6> `f1` e `f2` são decoradas por `@register`.
<7> `f3` não é decorada.
<8> `main` mostra `registry`, depois chama `f1()`, `f2()`, e `f3()`.
<9> `main()` só é invocada se _registration.py_ for executado como um script.

O resultado da execução de _registration.py_ se parece com isso:

----
$ python3 registration.py
running register(<function f1 at 0x100631bf8>)
running register(<function f2 at 0x100631c80>)
running main()
registry -> [<function f1 at 0x100631bf8>, <function f2 at 0x100631c80>]
running f1()
running f2()
running f3()
----

Observe que `register` roda (duas vezes) antes de qualquer outra função no módulo.
Quando `register` é chamada, ela recebe o objeto função a ser decorado como argumento—por exemplo,
`<function f1 at 0x100631bf8>`.

Após o carregamento do módulo, a lista `registry` contém
referências para as duas funções decoradas:
`f1` e `f2`. Essa funções, bem como `f3`, são executadas apenas quando chamadas explicitamente por `main`.

Se _registration.py_ for importado (e não executado como um script), a saída é essa:

[source, python]
----
>>> import registration
running register(<function f1 at 0x10063b1e0>)
running register(<function f2 at 0x10063b268>)
----

Nesse momento, se você inspecionar `registry`, verá isso:

[source, python]
----
>>> registration.registry
[<function f1 at 0x10063b1e0>, <function f2 at 0x10063b268>]
----

O ponto central do <<registration_ex>> é enfatizar que decoradores de função são executados assim que o módulo é importado, mas as funções decoradas só rodam quando são invocadas explicitamente. Isso ressalta a diferença entre o que pythonistas chamam de _tempo de importação_ e _tempo de execução_.

[[registration_deco_sec]]
=== Decoradores de registro

Considerando((("decorators and closures", "registration decorators")))((("registration decorators"))) a forma como decoradores são normalmente usados em código do mundo real, o <<registration_ex>> é incomum por duas razões:

* A função do decorador é definida no mesmo módulo das funções decoradas. Em geral, um decorador real é definido em um módulo e aplicado a funções de outros módulos.
* O decorador `register` devolve a mesma função recebida como argumento. Na prática, a maior parte dos decoradores define e devolve uma função interna.

Apesar do decorador `register` no <<registration_ex>> devolver a função decorada inalterada, a técnica não é inútil.
Decoradores parecidos são usados por muitos frameworks Python para adicionar funções a um registro central—por exemplo,
um registro mapeando padrões de URLs para funções que geram respostas HTTP.
Tais decoradores de registro podem ou não modificar as funções decoradas.

Vamos ver um decorador de registro em ação na <<decorated_strategy>> (<<ch_design_patterns>>).

A maioria dos decoradores modificam a função decorada.
Eles normalmente fazem isso definindo e devolvendo uma função interna para substituir a função decorada.
Código que usa funções internas quase sempre depende de clausuras para operar corretamente.
Para entender as clausuras, precisamos dar um passo atrás e revisar como o escopo de variáveis funciona no Python.

=== Regras de escopo de variáveis

No((("decorators and closures", "variable scope rules", id="DACvars09")))((("variable scope rules", id="vsr09")))((("scope", "variable scope rules", id="Svsr09"))) <<ex_global_undef>>, definimos e testamos uma função que lê duas variáveis:
uma variável local `a`—definida como parâmetro de função—e a variável `b`, que não é definida em lugar algum na função.

[[ex_global_undef]]
.Função lendo uma variável local e uma variável global
====
[source, python]
----
>>> def f1(a):
...     print(a)
...     print(b)
...
>>> f1(3)
3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in f1
NameError: global name 'b' is not defined
----
====

O erro obtido não é surpreendente. Continuando do <<ex_global_undef>>, se atribuirmos um valor a um `b` global e então chamarmos `f1`, funciona:

[source, python]
----
>>> b = 6
>>> f1(3)
3
6
----

Agora vamos ver um exemplo que pode ser surpreendente.

Dê uma olhada na função `f2`, no <<ex_local_unbound>>. As primeiras duas linhas são as mesmas da `f1` do <<ex_global_undef>>, e então ela faz uma atribuição a `b`. Mas para com um erro no segundo `print`, antes da atribuição ser executada.

[[ex_local_unbound]]
.A variável `b` é local, porque um valor é atribuído a ela no corpo da função
====
[source, python]
----
>>> b = 6
>>> def f2(a):
...     print(a)
...     print(b)
...     b = 9
...
>>> f2(3)
3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in f2
UnboundLocalError: local variable 'b' referenced before assignment
----
====

Observe que o a saída começa com `3`, provando que o comando `print(a)` foi executado. Mas o segundo, `print(b)`, nunca roda. Quando vi isso pela primeira vez me espantei, pensava que o `6` deveria ser exibido, pois há uma variável global `b`, e a atribuição para a `b` local ocorre após `print(b)`.

Mas o fato é que, quando Python compila o corpo da função, ele decide que `b` é uma variável local, por ser atribuída dentro da função. O bytecode gerado reflete essa decisão, e tentará obter `b` no escopo local. Mais tarde, quando a chamada `f2(3)` é realizada, o corpo de `f2` obtém e exibe o valor da variável local `a`, mas ao tentar obter o valor da variável local `b`, descobre que `b` não está vinculado a nada.

Isso não é um bug, mas uma escolha de projeto: Python não exige que você declare variáveis, mas assume que uma variável atribuída no corpo de uma função é local. Isso é muito melhor que o comportamento de Javascript, que também não requer declarações de variáveis, mas se você esquecer de declarar uma variável como local (com `var`), pode acabar alterando uma variável global sem nem saber.

Se queremos que o interpretador trate `b` como uma variável global e também atribuir um novo valor a ela dentro da função, usamos a declaração `global`:

[source, python]
----
>>> b = 6
>>> def f3(a):
...     global b
...     print(a)
...     print(b)
...     b = 9
...
>>> f3(3)
3
6
>>> b
9
----

Nos exemplos anteriores, vimos dois escopos em ação:

O escopo global de módulo:: Composto((("scope", "module global scope"))) por nomes atribuídos a valores fora de qualquer bloco de classe ou função.

O escopo local da função f3:: Composto((("scope", "function local scope"))) por nomes atribuídos a valores como parâmetros, ou diretamente no corpo da função.

Há um outro escopo de onde variáveis podem vir, chamado _nonlocal_, e ele é fundamental para clausuras; vamos tratar disso em breve.

Após ver mais de perto como o escopo de variáveis funciona no Python, podemos enfrentar as clausuras na próxima seção, <<closures_sec>>. Se você tiver curiosidade sobre as diferenças no bytecode das funções no <<#ex_global_undef>> e no <<#ex_local_unbound>>, veja o quadro a seguir.((("", startref="DACvars09")))((("", startref="vsr09")))((("", startref="Svsr09")))

.Comparando bytecodes
****

O((("dis module")))((("bytecode, disassembling")))((("functions", "disassembling bytecode of"))) módulo `dis` module oferece uma forma fácil de descompilar o bytecode de funções de Python. Leia no <<#ex_f1_dis>> e no <<#ex_f2_dis>> os bytecodes de `f1` e `f2`, do <<#ex_global_undef>> e do <<#ex_local_unbound>>, respectivamente.

[[ex_f1_dis]]
.Bytecode da função `f1` do <<ex_global_undef>>
====
[source, python]
----
include::../code/09-closure-deco/global_x_local.rst[tags=F1_DIS]
----
====
<1> Carrega o nome global `print`.
<2> Carrega o nome local `a`.
<3> Carrega o nome global `b`.

Compare o bytecode de `f1`, visto no <<ex_f1_dis>> acima, com o bytecode de `f2` no <<ex_f2_dis>>.

[[ex_f2_dis]]
.Bytecode da função `f2` do <<ex_local_unbound>>
====
[source, python]
----
include::../code/09-closure-deco/global_x_local.rst[tags=F2_DIS]
----
====
<1> Carrega o nome _local_ `b`. Isso mostra que o compilador considera `b` uma variável local, mesmo com uma atribuição a `b` ocorrendo mais tarde, porque a natureza da variável—se ela é ou não local—não pode mudar no corpo da função.

A máquina virtual (VM) do CPython que executa o bytecode é uma máquina de _stack_, então as operações `LOAD` e `POP` se referem ao _stack_. A descrição mais detalhada dos opcodes de Python está além da finalidade desse livro, mas eles estão documentados junto com o módulo, em https://docs.python.org/pt-br/3/library/dis.html["dis—Disassembler de bytecode de Python"].

****

[[closures_sec]]
=== Clausuras

Na((("decorators and closures", "closure basics", id="DACclos09")))((("anonymous functions"))) blogosfera, as clausuras são algumas vezes confundidas com funções anônimas.
Muita gente confunde os dois conceitos por causa da história paralela dos dois recursos:
definir funções dentro de outras funções não é tão comum ou conveniente, até existirem funções anônimas.
E clausuras só importam a partir do momento em que você tem funções aninhadas.
Daí que muitos aprendem as duas ideias ao mesmo tempo.

Na verdade, uma clausura é uma função—vamos chamá-la de `f`—com um escopo estendido, incorporando variáveis referenciadas no corpo de `f` que não são nem variáveis globais nem variáveis locais de `f`. Tais variáveis devem vir do escopo local de uma função externa que englobe `f`.

Não interessa aqui se a função é anônima ou não; o que importa é que ela pode acessar variáveis não-globais definidas fora de seu corpo.

É um conceito difícil de entender, melhor ilustrado por um exemplo.

Imagine uma função `avg`, para calcular a média de uma série de valores que cresce continuamente; por exemplo, o preço de fechamento de uma commodity através de toda a sua história. A cada dia, um novo preço é acrescentado, e a média é computada levando em conta todos os preços até ali.

Começando do zero, `avg` poderia ser usada assim:

[source, python]
----
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(12)
11.0
----

Da onde vem `avg`, e onde ela mantém o histórico com os valores anteriores?

Para começar, o <<ex_average_oo>> mostra uma implementação baseada em uma classe.

[[ex_average_oo]]
.average_oo.py: uma classe para calcular uma média contínua
====
[source, python]
----
class Averager():

    def __init__(self):
        self.series = []

    def __call__(self, new_value):
        self.series.append(new_value)
        total = sum(self.series)
        return total / len(self.series)
----
====

A classe `Averager` cria instâncias invocáveis:

[source, python]
----
>>> avg = Averager()
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(12)
11.0
----

O <<ex_average_fn>>, a seguir, é uma implementação funcional, usando a função de ordem superior `make_averager`.

[[ex_average_fn]]
.average.py: uma função de ordem superior para a clacular uma média contínua
====
[source, python]
----
def make_averager():
    series = []

    def averager(new_value):
        series.append(new_value)
        total = sum(series)
        return total / len(series)

    return averager
----
====

Quando invocada, `make_averager` devolve um objeto função `averager`. Cada vez que um `averager` é invocado, ele insere o argumento recebido na série, e calcula a média atual, como mostra o <<ex_average_demo1>>.

[[ex_average_demo1]]
.Testando o <<ex_average_fn>>
====
[source, python]
----
>>> avg = make_averager()
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(15)
12.0
----
====

Note as semelhanças entre os dois exemplos: chamamos `Averager()` ou `make_averager()` para obter um objeto invocável `avg`, que atualizará a série histórica e calculará a média atual. No <<ex_average_oo>>, `avg` é uma instância de `Averager`, no <<ex_average_fn>> é a função interna  `averager`. Nos dois casos, basta chamar `avg(n)` para incluir `n` na série e obter a média atualizada.

É óbvio onde o `avg` da classe `Averager` mantém o histórico: no atributo de instância `self.series`. Mas onde a função `avg` no segundo exemplo encontra a `series`?

Observe que `series` é uma variável local de `make_averager`, pois a atribuição `series = []` acontece no corpo daquela função. Mas quando `avg(10)` é chamada, `make_averager` já retornou, e seu escopo local há muito deixou de existir.

Dentro de `averager`, `series` é uma((("free variables")))((("variables", "free"))) _variável livre_. Esse é um termo técnico para designar uma variável que não está vinculada no escopo local. Veja a <<closure_fig>>.

[[closure_fig]]
.A clausura para `averager` estende o escopo daquela função para incluir a vinculação da variável livre `series`.
image::../images/flpy_0901.png[Diagrama de uma clausura]

Inspecionar o objeto `averager` devolvido mostra como Python mantém os nomes de variáveis locais e livres no atributo `+__code__+`, que representa o corpo compilado da função. O <<ex_average_demo2>> demonstra isso.

[[ex_average_demo2]]
.Inspecionando a função criada por `make_averager` no <<ex_average_fn>>
====
[source, python]
----
>>> avg.__code__.co_varnames
('new_value', 'total')
>>> avg.__code__.co_freevars
('series',)
----
====

O valor de `series` é mantido no atributo `+__closure__+` da função devolvida, `avg`. Cada item em `+avg.__closure__+` corresponde a um nome em `+__code__+`. Esses itens são `cells`, e tem um atributo chamado `cell_contents`, onde o valor real pode ser encontrado. O <<ex_average_demo3>> mostra esses atributos.

[[ex_average_demo3]]
.Continuando do <<ex_average_demo1>>
====
[source, python]
----
>>> avg.__code__.co_freevars
('series',)
>>> avg.__closure__
(<cell at 0x107a44f78: list object at 0x107a91a48>,)
>>> avg.__closure__[0].cell_contents
[10, 11, 12]
----
====

Resumindo: uma clausura é uma função que retém os vínculos das variáveis livres que existem quando a função é definida, de forma que elas possam ser usadas mais tarde, quando a função for invocada mas o escopo de sua definição não estiver mais disponível.

Note que a única situação na qual uma função pode ter de lidar com variáveis externas não-globais é quando ela estiver aninhada dentro de outra função, e aquelas variáveis sejam parte do escopo local da função externa.((("", startref="DACclos09")))

[[nonlocal_sec]]
=== A declaração nonlocal

Nossa((("decorators and closures", "nonlocal declarations", id="DACnonlocal09")))((("nonlocal keyword", id="nonlocal09")))((("keywords", "nonlocal keyword", id="Knon09"))) implementação anterior de `make_averager` não era eficiente. No <<ex_average_fn>>, armazenamos todos os valores na série histórica e calculamos sua `sum` cada vez que `averager` é invocada. Uma implementação melhor armazenaria apenas o total e número de itens até aquele momento, e calcularia a média com esses dois números.

O <<ex_average_broken>> é uma implementação errada, apenas para ilustrar um ponto. Você consegue ver onde o código quebra?

[[ex_average_broken]]
.Um função de ordem superior incorreta para calcular um média contínua sem manter todo o histórico
====
[source, python]
----
def make_averager():
    count = 0
    total = 0

    def averager(new_value):
        count += 1
        total += new_value
        return total / count

    return averager
----
====

Se você testar o <<ex_average_broken>>, eis o resultado:

[source, python]
----
>>> avg = make_averager()
>>> avg(10)
Traceback (most recent call last):
  ...
UnboundLocalError: local variable 'count' referenced before assignment
>>>
----

O problema é que a instrução `count += 1` significa o mesmo que `count = count + 1`, quando `count` é um número ou qualquer tipo imutável. Então estamos efetivamente atribuindo um valor a `count` no corpo de `averager`, e isso a torna uma variável local. O mesmo problema afeta a variável `total`.

Não tivemos esse problema no <<ex_average_fn>>, porque nunca atribuimos nada ao nome `series`; apenas chamamos `series.append` e invocamos `sum` e `len` nele. Nos valemos, então, do fato de listas serem mutáveis.

Mas com tipos imutáveis, como números, strings, tuplas, etc., só é possível ler, nunca atualizar. Se você tentar revinculá-las, como em `count = count + 1`, estará criando implicitamente uma variável local `count`. Ela não será mais uma variável livre, e assim não será armazenada na clausura.

A palavra reservada `nonlocal` foi introduzida no Python 3 para contornar esse problema. Ela permite declarar uma variável como variável livre, mesmo quando ela for atribuída dentro da função. Se um novo valor é atribuído a uma variável `nonlocal`, o vínculo armazenado na clausura é modificado. Uma implemetação correta da nossa última versão de `make_averager` se pareceria com o <<ex_average_fixed>>.

[[ex_average_fixed]]
.Calcula uma média contínua sem manter todo o histórico (corrigida com o uso de `nonlocal`)
====
[source, python]
----
def make_averager():
    count = 0
    total = 0

    def averager(new_value):
        nonlocal count, total
        count += 1
        total += new_value
        return total / count

    return averager
----
====

Após estudar o `nonlocal`, podemos resumir como a consulta de variáveis funciona no Python.

[[var_lookup_logic_sec]]
==== A lógica da consulta de variáveis

Quando((("variables", "lookup logic"))) uma função é definida, o compilador de bytecode de Python determina como encontrar uma variável `x` que aparece na função, baseado nas seguintes regras:footnote:[Agradeço ao revisor técnico Leonardo Rochael por sugerir esse resumo.]

* Se há uma declaração `global x`, `x` vem de e é atribuída à variável global `x` do módulo.footnote:[Python não tem um escopo global de programa, apenas escopos globais de módulos.]
* Se há uma declaração `nonlocal x`, `x` vem de e atribuída à variável local `x` na função circundante mais próxima de onde `x` for definida.
* Se `x` é um parâmetro ou tem um valor atribuído a si no corpo da função, então `x` é uma variável local.
* Se `x` é referenciada mas não atribuída, e não é um parâmetro:
** `x` será procurada nos escopos locais do corpos das funções circundantes (os escopos _nonlocal_).
** Se `x` não for encontrada nos escopos circundantes, será lida do escopo global do módulo.
** Se `x` não for encontrada no escopo global, será lida de `+__builtins__.__dict__+`.

Tendo visto as clausuras de Python, podemos agora de fato implementar decoradores com funções aninhadas.((("", startref="DACnonlocal09")))((("", startref="nonlocal09")))((("", startref="Knon09")))


=== Implementando um decorador simples

O <<ex_clockdeco0>> é((("decorators and closures", "decorator implementation", id="DACdecimp09"))) um decorador que cronometra cada invocação da função decorada e exibe o tempo decorrido, os argumentos passados, e o resultado da chamada.

[[ex_clockdeco0]]
._clockdeco0.py_: decorador simples que mostra o tempo de execução de funções
====
[source, python]
----
include::../code/09-closure-deco/clock/clockdeco0.py[]
----
====
<1> Define a função interna `clocked` para aceitar qualquer número de argumentos posicionais.
<2> Essa linha só funciona porque a clausura para `clocked` engloba a variável livre `func`.
<3> Devolve a função interna para substituir a função decorada.

O <<ex_clockdeco_demo>> demonstra o uso do decorador `clock`.

[[ex_clockdeco_demo]]
.Usando o decorador `clock`
====
[source, python]
----
include::../code/09-closure-deco/clock/clockdeco_demo.py[]
----
====

O resultado da execução do <<ex_clockdeco_demo>> é o seguinte:

[source]
----
$ python3 clockdeco_demo.py
**************************************** Calling snooze(.123)
[0.12363791s] snooze(0.123) -> None
**************************************** Calling factorial(6)
[0.00000095s] factorial(1) -> 1
[0.00002408s] factorial(2) -> 2
[0.00003934s] factorial(3) -> 6
[0.00005221s] factorial(4) -> 24
[0.00006390s] factorial(5) -> 120
[0.00008297s] factorial(6) -> 720
6! = 720
----

==== Como isso funciona

Lembre-se que esse código:

[source, python]
----
@clock
def factorial(n):
    return 1 if n < 2 else n*factorial(n-1)
----

na verdade faz isso:

[source, python]
----
def factorial(n):
    return 1 if n < 2 else n*factorial(n-1)

factorial = clock(factorial)
----

Então, nos dois exemplos, `clock` recebe a função `factorial` como seu argumento `func` (veja o <<ex_clockdeco0>>).
Ela então cria e devolve a função `clocked`, que o interpretador Python atribui a `factorial` (no primeiro exemplo, por baixo dos panos).
De fato, se você importar o módulo `clockdeco_demo` e verificar o `+__name__+` de `factorial`, verá isso:

[source, python]
----
>>> import clockdeco_demo
>>> clockdeco_demo.factorial.__name__
'clocked'
>>>
----

Então `factorial` agora mantém uma referência para a função `clocked`.
Daqui por diante, cada vez que `factorial(n)` for chamada, `clocked(n)` será executada.
Essencialmente, `clocked` faz o seguinte:

. Registra o tempo inicial `t0`.
. Chama a função `factorial` original, salvando o resultado.
. Computa o tempo decorrido.
. Formata e exibe os dados coletados.
. Devolve o resultado salvo no passo 2.

Esse é o comportamento típico de um decorador: ele substitui a função decorada com uma nova função que aceita os mesmos argumentos e (normalmente) devolve o que quer que a função decorada deveria devolver, enquanto realiza também algum processamento adicional.

[TIP]
====
Em _Padrões de Projetos_, de Gamma et al., a descrição curta do padrão decorador começa com: "Atribui dinamicamente responsabilidades adicionais a um objeto." Decoradores de função se encaixam nessa descrição. Mas, no nível da implementação, os decoradores de Python guardam pouca semelhança com o decorador clássico descrito no _Padrões de Projetos_ original. O <<closures_soapbox>> fala um pouco mais sobre esse assunto.
====

O decorador `clock` implementado no <<ex_clockdeco0>> tem alguns defeitos: ele não suporta argumentos nomeados, e encobre o `+__name__+` e o `+__doc__+` da função decorada.
O <<ex_clockdeco2>> usa o decorador `functools.wraps` para copiar os atributos relevantes de `func` para `clocked`.
E nessa nova versão os argumentos nomeados também são tratados corretamente.

[[ex_clockdeco2]]
._clockdeco.py_: um decorador `clock` melhora
====
[source, python]
----
include::../code/09-closure-deco/clock/clockdeco.py[]
----
====

O `functools.wraps` é apenas um dos decoradores prontos para uso da biblioteca padrão. Na próxima seção veremos o decorador mais impressionante oferecido por `functools`: `cache`.((("", startref="DACdecimp09")))


=== Decoradores na biblioteca padrão

Python((("decorators and closures", "decorators in Python standard library", id="DACstandard09"))) tem três funções embutidas projetadas para decorar métodos:
`property`, `classmethod` e `staticmethod`.
Vamos discutir `property` na <<prop_validation_sec>> e os outros na <<classmethod_x_staticmethod_sec>>.

No <<ex_clockdeco2>> vimos outro decorador importante: `functools.wraps`, um auxiliar na criação de decoradores bem comportados.
Três dos decoradores mais interessantes da biblioteca padrão são `cache`, `lru_cache` e `singledispatch`—todos do módulo `functools`. Falaremos deles a seguir.

[[memoization_sec]]
==== Memoização com functools.cache

O((("memoization", id="memoiz09")))((("functools module", "functools.cache decorator", id="functool09"))) decorador `functools.cache` implementa _memoização_:footnote:[Esclarecendo, isso não é um erro de ortografia: https://fpy.li/9-2[_memoization_] é um termo da ciência da computação vagamente relacionado a "memorização", mas não idêntico.]
uma técnica de otimização que funciona salvando os resultados de invocações anteriores de uma função dispendiosa, evitando repetir o processamento para argumentos previamente utilizados.

[TIP]
====
O `functools.cache` foi introduzido no Python 3.9.
Se você precisar rodar esses exemplo no Python 3.8, substitua `@cache` por `@lru_cache`.
Em versões anteriores é preciso invocar o decorador, escrevendo `@lru_cache()`, como explicado na <<lru_cache_sec>>.
====

Uma boa demonstração é aplicar `@cache` à função recursiva, e dolorosamente lenta, que gera o __enésimo__ número da sequência de Fibonacci, como mostra o <<ex_fibo_demo>>.

[[ex_fibo_demo]]
.O modo recursivo e extremamente dispendioso de calcular o _enésimo_ número na série de Fibonacci
====
[source, python]
----
include::../code/09-closure-deco/fibo_demo.py[]
----
====

Aqui está o resultado da execução de _fibo_demo.py_. Exceto pela última linha, toda a saída é produzida pelo decorador `clock`:

[source, text]
----
$ python3 fibo_demo.py
[0.00000042s] fibonacci(0) -> 0
[0.00000049s] fibonacci(1) -> 1
[0.00006115s] fibonacci(2) -> 1
[0.00000031s] fibonacci(1) -> 1
[0.00000035s] fibonacci(0) -> 0
[0.00000030s] fibonacci(1) -> 1
[0.00001084s] fibonacci(2) -> 1
[0.00002074s] fibonacci(3) -> 2
[0.00009189s] fibonacci(4) -> 3
[0.00000029s] fibonacci(1) -> 1
[0.00000027s] fibonacci(0) -> 0
[0.00000029s] fibonacci(1) -> 1
[0.00000959s] fibonacci(2) -> 1
[0.00001905s] fibonacci(3) -> 2
[0.00000026s] fibonacci(0) -> 0
[0.00000029s] fibonacci(1) -> 1
[0.00000997s] fibonacci(2) -> 1
[0.00000028s] fibonacci(1) -> 1
[0.00000030s] fibonacci(0) -> 0
[0.00000031s] fibonacci(1) -> 1
[0.00001019s] fibonacci(2) -> 1
[0.00001967s] fibonacci(3) -> 2
[0.00003876s] fibonacci(4) -> 3
[0.00006670s] fibonacci(5) -> 5
[0.00016852s] fibonacci(6) -> 8
8
----

O desperdício é óbvio: `fibonacci(1)` é chamada oito vezes, `fibonacci(2)` cinco vezes, etc.
Mas acrescentar apenas duas linhas, para usar `cache`, melhora muito o desempenho. Veja o <<fibo_demo_cache_ex>>.

[[fibo_demo_cache_ex]]
.Implementação mais rápida, usando _caching_
====
[source, python]
----
include::../code/09-closure-deco/fibo_demo_cache.py[]
----
====
<1> Essa linha funciona com Python 3.9 ou posterior. Veja a <<lru_cache_sec>> para uma alternativa que suporta versões anteriores de Python.
<2> Esse é um exemplo de decoradores empilhados: `@cache` é aplicado à função devolvida por `@clock`.

[[stacked_decorators_tip]]
.Decoradore empilhados
[TIP]
====
Para((("stacked decorators"))) entender os decoradores empilhados, lembre-se que a `@` é açúcar sintático para indicar a aplicação da função decoradora à função abaixo dela.
Se houver mais de um decorador, eles se comportam como chamadas a funções aninhadas. Isso:

[source, python]
----
@alpha
@beta
def my_fn():
    ...
----

é o mesmo que isso:

[source, python]
----
my_fn = alpha(beta(my_fn))
----

Em outras palavras, o decorador `beta` é aplicado primeiro, e a função devolvida por ele é então passada para `alpha`.

====

Usando o `cache` no <<fibo_demo_cache_ex>>, a função `fibonacci` é chamada apenas uma vez para cada valor de `n`:

[source, text]
----
$ python3 fibo_demo_lru.py
[0.00000043s] fibonacci(0) -> 0
[0.00000054s] fibonacci(1) -> 1
[0.00006179s] fibonacci(2) -> 1
[0.00000070s] fibonacci(3) -> 2
[0.00007366s] fibonacci(4) -> 3
[0.00000057s] fibonacci(5) -> 5
[0.00008479s] fibonacci(6) -> 8
8
----

Em outro teste, para calcular `fibonacci(30)`, o <<fibo_demo_cache_ex>> fez as 31 chamadas necessárias em 0,00017s (tempo total), enquanto o <<ex_fibo_demo>> sem cache, demorou 12,09s em um notebook Intel Core i7, porque chamou `fibonacci(1)` 832.040 vezes, para um total de 2.692.537 chamadas.

Todos os argumentos recebidos pela função decorada devem ser _hashable_, pois o `lru_cache` subjacente usa um `dict` para armazenar os resultados, e as chaves são criadas a partir dos argumentos posicionais e nomeados usados nas chamados.

Além de tornar viáveis esses algoritmos recursivos tolos, `@cache` brilha de verdade em aplicações que precisam buscar informações de APIs remotas.

[WARNING]
====
O `functools.cache` pode consumir toda a memória disponível, se houver um número muito grande de itens no cache. Eu o considero mais adequado para scripts rápidos de linha de comando.
Para processos de longa duração, recomendo usar `functools.lru_cache` com um parâmetro `maxsize` adequado, como explicado na próxima seção.((("", startref="DACstandard09")))((("", startref="memoiz09")))((("", startref="functool09")))
====


[[lru_cache_sec]]
==== Usando o lru_cache

O((("functools module", "functools.lru_cache function"))) decorador `functools.cache` é, na realidade, um mero invólucro em torno da antiga função `functools.lru_cache`, que é mais flexível e também compatível com Python 3.8 e outras versões anteriores.

A maior vantagem de `@lru_cache` é a possibilidade de limitar seu uso de memória através do parâmetro `maxsize`, que tem um default bastante conservador de 128—significando que o cache pode manter no máximo 128 registros simultâneos.

LRU((("Least Recently Used (LRU)"))) é a sigla de _Least Recently Used_ (literalmente "Usado Menos Recentemente").
Significa que registros que há algum tempo não são lidos, são descartados para dar lugar a novos itens.

Desde o Python 3.8, `lru_cache` pode ser aplicado de duas formas.
Abaixo vemos o modo mais simples em uso:

[source, python]
----
@lru_cache
def costly_function(a, b):
    ...
----

A outra forma—disponível desde o Python 3.2—é invocá-lo como uma função,
com `()`:

[source, python]
----
@lru_cache()
def costly_function(a, b):
    ...
----

Nos dois casos, os parâmetros default seriam utilizados.
São eles:

`maxsize=128`::
    Estabelece o número máximo de registros a serem armazenados.
    Após o cache estar cheio, o registro menos recentemente usado é descartado, para dar lugar a cada novo item.
    Para um desempenho ótimo, `maxsize` deve ser uma potência de 2.
    Se você passar `maxsize=None`, a lógica LRU é desabilitada e o cache funciona mais rápido, mas os itens nunca são descartados, podendo levar a um consumo excessivo de memória.
    É assim que o `@functools.cache` funciona.

`typed=False`::
    Determina se os resultados de diferentes tipos de argumentos devem ser armazenados separadamente, Por exemplo, na configuração default, argumentos inteiros e de ponto flutuante considerados iguais são armazenados apenas uma vez. Assim, haverá apenas uma entrada para as chamadas `f(1)` e `f(1.0)`.
    Se `typed=True`, aqueles argumentos produziriam registros diferentes, possivelmente armazenando resultados distintos.

Eis um exemplo de invocação de `@lru_cache` com parâmetros diferentes dos defaults:

[source, python]
----
@lru_cache(maxsize=2**20, typed=True)
def costly_function(a, b):
    ...
----

Vamos agora examinar outro decorador poderoso: `functools.singledispatch`.

[[generic_functions]]
==== Funções genéricas com despacho único

Imagine((("single dispatch generic functions", id="singlegen09")))((("functions", "single dispatch generic functions", id="Fsingle09")))((("generic functions, single dispatch", id="genfunc09"))) que estamos criando uma ferramenta para depurar aplicações web. Queremos gerar código HTML para tipos diferentes de objetos Python.

Poderíamos começar com uma função como essa:

[source, python]
----
import html

def htmlize(obj):
    content = html.escape(repr(obj))
    return f'<pre>{content}</pre>'
----

Isso funcionará para qualquer tipo de Python, mas agora queremos estender a função para gerar HTML específico para determinados tipos.
Alguns exemplos seriam:

`str`:: Substituir os caracteres de mudança de linha na string por `'<br/>\n'` e usar tags `<p>` tags em vez de `<pre>`.

`int`:: Mostrar o número em formato decimal e hexadecimal (com um caso especial para `bool`).

`list`:: Gerar uma lista em HTML, formatando cada item de acordo com seu tipo.

`float` e `Decimal`:: Mostrar o valor como de costume, mas também na forma de fração (por que não?).

O comportamento que desejamos aparece no <<singledispatch_demo>>.

[[singledispatch_demo]]
.`htmlize()` gera HTML adaptado para diferentes tipos de objetos
====
[source, python]
----
include::../code/09-closure-deco/htmlizer.py[tags=HTMLIZE_DEMO]
----
====
<1> A função original é registrada para `object`, então ela serve para capturar e tratar todos os tipos de argumentos que não foram capturados pelas outras implementações.
<2> Objetos `str` também passam por escape de HTML, mas são cercados por `<p></p>`, com quebras de linha `<br/>` inseridas antes de cada `'\n'`.
<3> Um `int` é exibido nos formatos decimal e hexadecimal, dentro de um bloco `<pre></pre>`.
<4> Cada item na lista é formatado de acordo com seu tipo, e a sequência inteira é apresentada como uma lista HTML.
<5> Apesar de ser um subtipo de `int`, `bool` recebe um tratamento especial.
<6> Mostra `Fraction` como uma fração.
<7> Mostra `float` e `Decimal` com a fração equivalemte aproximada.

===== Despacho único de funções

Como não temos no Python a sobrecarga de métodos ao estilo de Java, não podemos simplesmente criar variações de `htmlize` com assinaturas diferentes para cada tipo de dado que queremos tratar de forma distinta. Uma solução possível em Python seria transformar `htmlize` em uma função de despacho, com uma cadeia de `if/elif/…` ou `match/case/…` chamando funções especializadas como `htmlize_str`, `htmlize_int`, etc.
Isso não é extensível pelos usuários de nosso módulo, e é desajeitado:
com o tempo, a despachante `htmlize` de tornaria grande demais, e o acoplamento entre ela e as funções especializadas seria excessivamente sólido.

O decorador((("functools module", "functools.singledispatch decorator", id="functoolssingle09"))) `functools.singledispatch` permite que diferentes módulos contribuam para a solução geral, e que você forneça facilmente funções especializadas, mesmo para tipos pertencentes a pacotes externos que não possam ser editados.
Se você decorar um função simples com `@singledispatch`, ela se torna o ponto de entrada para uma _função genérica_:
Um grupo de funções que executam a mesma operação de formas diferentes, dependendo do tipo do primeiro argumento.
É isso que signifca o termo _despacho único_. Se mais argumentos fossem usados para selecionar a função específica, teríamos um _despacho múltiplo_.
O <<singledispatch_ex>> mostra como funciona.


[WARNING]
====
`functools.singledispatch` existe desde o Python 3.4, mas só passou a suportar dicas de tipo no Python 3.7.
As últimas duas funções no <<singledispatch_ex>> ilustram a sintaxe que funciona em todas as versões de Python desde a 3.4.
====


[[singledispatch_ex]]
.`@singledispatch` cria uma `@htmlize.register` customizada, para empacotar várias funções em uma função genérica
====
[source, python]
----
include::../code/09-closure-deco/htmlizer.py[tags=HTMLIZE]
----
====
<1> `@singledispatch` marca a função base, que trata o tipo `object`.
<2> Cada função especializada é decorada com `@«base».register`.
<3> O tipo do primeiro argumento passado durante a execução determina quando essa definição de função em particular será utilizada. O nome das funções especializadas é irrelevante; `_` é uma boa escolha para deixar isso claro.footnote:[Infelizmente, o Mypy 0.770 reclama quando vê múltiplas funções com o mesmo nome.]
<4> Registra uma nova função para cada tipo que precisa de tratamento especial, com uma dica de tipo correspondente no primeiro parâmetro.
<5> As ABCs em `numbers` são úteis para uso em conjunto com `singledispatch`.footnote:[Apesar do alerta em <<numeric_tower_warning>>, as ABCs de `numbers` não foram descontinuadas, e você as encontra em código de Python 3.]
<6> `bool` é um _subtipo-de_ `numbers.Integral`, mas a lógica de `singledispatch` busca a implementação com o tipo correspondente mais específico, independente da ordem na qual eles aparecem no código.
<7> Se você não quiser ou não puder adicionar dicas de tipo à função decorada, você pode passar o tipo para o decorador `@«base».register`. Essa sintaxe funciona em Python 3.4 ou posterior.
<8> O decorador `@«base».register` devolve a função sem decoração, então é possível empilhá-los para registrar dois ou mais tipos na mesma implementação.footnote:[Talvez algum dia seja possível expressar isso com um único `@htmlize.register` sem parâmetros, e uma dica de tipo usando `Union`. Mas quando tentei, Python gerou um `TypeError` com uma mensagem dizendo que `Union` não é uma classe. Então, apesar da _sintaxe_ da PEP 484 ser suportada, a _semântica_ ainda não chegou lá.]

////
++++

<div id="singledispatch_ex" data-type="example">
<h5><code>@singledispatch</code> creates a custom <code>@htmlize.register</code> to bundle several functions into a generic function</h5>

<pre data-type="programlisting" data-code-language="py"><code class="kn">from</code><code> </code><code class="nn">functools</code><code> </code><code class="kn">import</code><code> </code><code class="n">singledispatch</code><code>
</code><code class="kn">from</code><code> </code><code class="nn">collections</code><code> </code><code class="kn">import</code><code> </code><code class="n">abc</code><code>
</code><code class="kn">import</code><code> </code><code class="nn">fractions</code><code>
</code><code class="kn">import</code><code> </code><code class="nn">decimal</code><code>
</code><code class="kn">import</code><code> </code><code class="nn">html</code><code>
</code><code class="kn">import</code><code> </code><code class="nn">numbers</code><code>
</code><code>
</code><code class="nd">@singledispatch</code><code>  </code><a class="co" id="man_co_decorators_and_closures_CO8-1" href="#man_callout_decorators_and_closures_CO8-1"><img src="callouts/1.png" alt="1"/></a><code>
</code><code class="k">def</code><code> </code><code class="nf">htmlize</code><code class="p">(</code><code class="n">obj</code><code class="p">:</code><code> </code><code class="nb">object</code><code class="p">)</code><code> </code><code class="o">-</code><code class="o">&gt;</code><code> </code><code class="nb">str</code><code class="p">:</code><code>
</code><code>    </code><code class="n">content</code><code> </code><code class="o">=</code><code> </code><code class="n">html</code><code class="o">.</code><code class="n">escape</code><code class="p">(</code><code class="nb">repr</code><code class="p">(</code><code class="n">obj</code><code class="p">)</code><code class="p">)</code><code>
</code><code>    </code><code class="k">return</code><code> </code><code class="n">f</code><code class="s1">'</code><code class="s1">&lt;pre&gt;{content}&lt;/pre&gt;</code><code class="s1">'</code><code>
</code><code>
</code><code class="nd">@htmlize.register</code><code>  </code><a class="co" id="man_co_decorators_and_closures_CO8-2" href="#man_callout_decorators_and_closures_CO8-2"><img src="callouts/2.png" alt="2"/></a><code>
</code><code class="k">def</code><code> </code><code class="nf">_</code><code class="p">(</code><code class="n">text</code><code class="p">:</code><code> </code><code class="nb">str</code><code class="p">)</code><code> </code><code class="o">-</code><code class="o">&gt;</code><code> </code><code class="nb">str</code><code class="p">:</code><code>  </code><a class="co" id="man_co_decorators_and_closures_CO8-3" href="#man_callout_decorators_and_closures_CO8-3"><img src="callouts/3.png" alt="3"/></a><code>
</code><code>    </code><code class="n">content</code><code> </code><code class="o">=</code><code> </code><code class="n">html</code><code class="o">.</code><code class="n">escape</code><code class="p">(</code><code class="n">text</code><code class="p">)</code><code class="o">.</code><code class="n">replace</code><code class="p">(</code><code class="s1">'</code><code class="se">\n</code><code class="s1">'</code><code class="p">,</code><code> </code><code class="s1">'</code><code class="s1">&lt;br/&gt;</code><code class="se">\n</code><code class="s1">'</code><code class="p">)</code><code>
</code><code>    </code><code class="k">return</code><code> </code><code class="n">f</code><code class="s1">'</code><code class="s1">&lt;p&gt;{content}&lt;/p&gt;</code><code class="s1">'</code><code>
</code><code>
</code><code class="nd">@htmlize.register</code><code>  </code><a class="co" id="man_co_decorators_and_closures_CO8-4" href="#man_callout_decorators_and_closures_CO8-4"><img src="callouts/4.png" alt="4"/></a><code>
</code><code class="k">def</code><code> </code><code class="nf">_</code><code class="p">(</code><code class="n">seq</code><code class="p">:</code><code> </code><code class="n">abc</code><code class="o">.</code><code class="n">Sequence</code><code class="p">)</code><code> </code><code class="o">-</code><code class="o">&gt;</code><code> </code><code class="nb">str</code><code class="p">:</code><code>
</code><code>    </code><code class="n">inner</code><code> </code><code class="o">=</code><code> </code><code class="s1">'</code><code class="s1">&lt;/li&gt;</code><code class="se">\n</code><code class="s1">&lt;li&gt;</code><code class="s1">'</code><code class="o">.</code><code class="n">join</code><code class="p">(</code><code class="n">htmlize</code><code class="p">(</code><code class="n">item</code><code class="p">)</code><code> </code><code class="k">for</code><code> </code><code class="n">item</code><code> </code><code class="ow">in</code><code> </code><code class="n">seq</code><code class="p">)</code><code>
</code><code>    </code><code class="k">return</code><code> </code><code class="s1">'</code><code class="s1">&lt;ul&gt;</code><code class="se">\n</code><code class="s1">&lt;li&gt;</code><code class="s1">'</code><code> </code><code class="o">+</code><code> </code><code class="n">inner</code><code> </code><code class="o">+</code><code> </code><code class="s1">'</code><code class="s1">&lt;/li&gt;</code><code class="se">\n</code><code class="s1">&lt;/ul&gt;</code><code class="s1">'</code><code>
</code><code>
</code><code class="nd">@htmlize.register</code><code>  </code><a class="co" id="man_co_decorators_and_closures_CO8-5" href="#man_callout_decorators_and_closures_CO8-5"><img src="callouts/5.png" alt="5"/></a><code>
</code><code class="k">def</code><code> </code><code class="nf">_</code><code class="p">(</code><code class="n">n</code><code class="p">:</code><code> </code><code class="n">numbers</code><code class="o">.</code><code class="n">Integral</code><code class="p">)</code><code> </code><code class="o">-</code><code class="o">&gt;</code><code> </code><code class="nb">str</code><code class="p">:</code><code>
</code><code>    </code><code class="k">return</code><code> </code><code class="n">f</code><code class="s1">'</code><code class="s1">&lt;pre&gt;{n} (0x{n:x})&lt;/pre&gt;</code><code class="s1">'</code><code>
</code><code>
</code><code class="nd">@htmlize.register</code><code>  </code><a class="co" id="man_co_decorators_and_closures_CO8-6" href="#man_callout_decorators_and_closures_CO8-6"><img src="callouts/6.png" alt="6"/></a><code>
</code><code class="k">def</code><code> </code><code class="nf">_</code><code class="p">(</code><code class="n">n</code><code class="p">:</code><code> </code><code class="nb">bool</code><code class="p">)</code><code> </code><code class="o">-</code><code class="o">&gt;</code><code> </code><code class="nb">str</code><code class="p">:</code><code>
</code><code>    </code><code class="k">return</code><code> </code><code class="n">f</code><code class="s1">'</code><code class="s1">&lt;pre&gt;{n}&lt;/pre&gt;</code><code class="s1">'</code><code>
</code><code>
</code><code class="nd">@htmlize.register</code><code class="p">(</code><code class="n">fractions</code><code class="o">.</code><code class="n">Fraction</code><code class="p">)</code><code>  </code><a class="co" id="man_co_decorators_and_closures_CO8-7" href="#man_callout_decorators_and_closures_CO8-7"><img src="callouts/7.png" alt="7"/></a><code>
</code><code class="k">def</code><code> </code><code class="nf">_</code><code class="p">(</code><code class="n">x</code><code class="p">)</code><code> </code><code class="o">-</code><code class="o">&gt;</code><code> </code><code class="nb">str</code><code class="p">:</code><code>
</code><code>    </code><code class="n">frac</code><code> </code><code class="o">=</code><code> </code><code class="n">fractions</code><code class="o">.</code><code class="n">Fraction</code><code class="p">(</code><code class="n">x</code><code class="p">)</code><code>
</code><code>    </code><code class="k">return</code><code> </code><code class="n">f</code><code class="s1">'</code><code class="s1">&lt;pre&gt;{frac.numerator}/{frac.denominator}&lt;/pre&gt;</code><code class="s1">'</code><code>
</code><code>
</code><code class="nd">@htmlize.register</code><code class="p">(</code><code class="n">decimal</code><code class="o">.</code><code class="n">Decimal</code><code class="p">)</code><code>  </code><a class="co" id="man_co_decorators_and_closures_CO8-8" href="#man_callout_decorators_and_closures_CO8-8"><img src="callouts/8.png" alt="8"/></a><code>
</code><code class="nd">@htmlize.register</code><code class="p">(</code><code class="nb">float</code><code class="p">)</code><code>
</code><code class="k">def</code><code> </code><code class="nf">_</code><code class="p">(</code><code class="n">x</code><code class="p">)</code><code> </code><code class="o">-</code><code class="o">&gt;</code><code> </code><code class="nb">str</code><code class="p">:</code><code>
</code><code>    </code><code class="n">frac</code><code> </code><code class="o">=</code><code> </code><code class="n">fractions</code><code class="o">.</code><code class="n">Fraction</code><code class="p">(</code><code class="n">x</code><code class="p">)</code><code class="o">.</code><code class="n">limit_denominator</code><code class="p">(</code><code class="p">)</code><code>
</code><code>    </code><code class="k">return</code><code> </code><code class="n">f</code><code class="s1">'</code><code class="s1">&lt;pre&gt;{x} ({frac.numerator}/{frac.denominator})&lt;/pre&gt;</code><code class="s1">'</code></pre></div>
<dl class="calloutlist">
<dt><a class="co" id="man_callout_decorators_and_closures_CO8-1" href="#man_co_decorators_and_closures_CO8-1"><img src="callouts/1.png" alt="1"/></a></dt>
<dd><p><code>@singledispatch</code> marks the base function that handles the <code>object</code> type.</p></dd>
<dt><a class="co" id="man_callout_decorators_and_closures_CO8-2" href="#man_co_decorators_and_closures_CO8-2"><img src="callouts/2.png" alt="2"/></a></dt>
<dd><p>Each specialized function is decorated with <code>@«base».register</code>.</p></dd>
<dt><a class="co" id="man_callout_decorators_and_closures_CO8-3" href="#man_co_decorators_and_closures_CO8-3"><img src="callouts/3.png" alt="3"/></a></dt>
<dd><p>The type of the first argument given at runtime determines when this particular function definition will be used. The name of the specialized functions is irrelevant; <code>_</code> is a good choice to make this
clear.<span data-type="footnote">Unfortunately, Mypy 0.770 complains when it sees multiple functions with the same name.</span></p></dd>
<dt><a class="co" id="man_callout_decorators_and_closures_CO8-4" href="#man_co_decorators_and_closures_CO8-4"><img src="callouts/4.png" alt="4"/></a></dt>
<dd><p>For each additional type to get special treatment,
register a new function with a matching type hint in the first parameter.</p></dd>
<dt><a class="co" id="man_callout_decorators_and_closures_CO8-5" href="#man_co_decorators_and_closures_CO8-5"><img src="callouts/5.png" alt="5"/></a></dt>
<dd><p>The <code>numbers</code> ABCs are useful for use with <code>singledispatch</code>.<span data-type="footnote">Despite the warning in <a href="#numeric_tower_warning" data-type="xref">#numeric_tower_warning</a>, the <code>number</code> ABCs are not deprecated and you find them in Python 3 code.</span></p></dd>
<dt><a class="co" id="man_callout_decorators_and_closures_CO8-6" href="#man_co_decorators_and_closures_CO8-6"><img src="callouts/6.png" alt="6"/></a></dt>
<dd><p><code>bool</code> is a <em>subtype-of</em> <code>numbers.Integral</code>, but the <code>singledispatch</code> logic seeks the implementation with the most specific matching type, regardless of the order they appear in the code.</p></dd>
<dt class="pagebreak-before"><a class="co" id="man_callout_decorators_and_closures_CO8-7" href="#man_co_decorators_and_closures_CO8-7"><img src="callouts/7.png" alt="7"/></a></dt>
<dd><p>If you don’t want to, or cannot, add type hints to the decorated function, you can pass a type to the <code>@«base».register</code> decorator. This syntax works in Python 3.4 or later.</p></dd>
<dt><a class="co" id="man_callout_decorators_and_closures_CO8-8" href="#man_co_decorators_and_closures_CO8-8"><img src="callouts/8.png" alt="8"/></a></dt>
<dd><p>The <code>@«base».register</code> decorator returns the undecorated function, so it’s possible to stack them to register two or more types on the same implementation.<span data-type="footnote">Maybe one day you'll also be able to express this with single unparameterized <code>@htmlize.register</code> and type hint using <code>Union</code>, but when I tried, Python raised a <code>TypeError</code> with a message saying that <code>Union</code> is not a class. So, although PEP 484 <em>syntax</em> is supported by <code>@singledispatch</code>, the <em>semantics</em> are not there yet.</span></p></dd>
</dl>
++++
////


Sempre que possível, registre as funções especializadas para tratar ABCs (classes abstratas), como `numbers.Integral` e `abc.MutableSequence`, ao invés das implementações concretas como `int` e `list`.
Isso permite ao seu código suportar uma variedade maior de tipos compatíveis.
Por exemplo, uma extensão de Python pode fornecer alternativas para o tipo `int` com número fixo de bits como subclasses de `numbers.Integral`.footnote:[NumPy, por exemplo, implementa vários tipos de
https://fpy.li/9-3[números inteiros e de ponto flutuante] (EN) em formatos voltados para a arquitetura da máquina.]

[TIP]
====
Usar ABCs ou `typing.Protocol` com `@singledispatch` permite que seu código suporte classes existentes ou futuras que sejam subclasses reais ou virtuais daquelas ABCs, ou que implementem aqueles protocolos. O uso de ABCs e o conceito de uma subclasse virtual são assuntos do <<ch_ifaces_prot_abc>>.
====

Uma qualidade notável do mecanismo de `singledispatch` é que você pode registrar funções especializadas em qualquer lugar do sistema, em qualquer módulo. Se mais tarde você adicionar um módulo com um novo tipo definido pelo usuário, é fácil acrescentar uma nova função específica para  tratar aquele tipo. E é possível também escrever funções customizadas para classes que você não escreveu e não pode modificar.

O `singledispatch` foi uma adição muito bem pensada à biblioteca padrão, e oferece muitos outros recursos que não me cabe descrever aqui. Uma boa referência é a https://fpy.li/pep443[PEP 443--Single-dispatch generic functions] (EN) mas ela não menciona o uso de dicas de tipo, acrescentado posteriormente. A documentação do módulo `functools` foi aperfeiçoada e oferece um tratamento mais atualizado, com vários exemplos na seção referente ao https://docs.python.org/pt-br/3/library/functools.html#functools.singledispatch[`singledispatch`] (EN).

[NOTE]
====
O `@singledispatch` não foi criado para trazer para Python a sobrecarga de métodos no estilo de Java. Uma classe única com muitas variações sobrecarregadas de um método é melhor que uma única função com uma longa sequênca de blocos `if/elif/elif/elif`. Mas as duas soluções são incorretas, pois concentram responsabilidade excessiva em uma única unidade de código—a classe ou a função. A vantagem de `@singledispatch` é seu suporte à extensão modular: cada módulo pode registrar uma função especializada para cada tipo suportado. Em um caso de uso realista, as implementações das funções genéricas não estariam todas no mesmo módulo, como ocorre no <<singledispatch_ex>>.
====

Vimos alguns decoradores recebendo argumentos, por exemplo `@lru_cache()` e o
`htmlize.register(float)` criado  por `@singledispatch` no <<singledispatch_ex>>.
A próxima seção mostra como criar decoradores que aceitam parâmetros.((("", startref="singlegen09")))((("", startref="Fsingle09")))((("", startref="genfunc09")))((("", startref="functoolssingle09")))


[[parameterized_dec_sec]]
=== Decoradores parametrizados

Ao((("decorators and closures", "parameterized decorators", id="DACparam09")))((("parameterized decorators", id="paramdec09"))) analisar um decorador no código-fonte, Python passa a função decorada como primeiro argumento para a função do decorador. Mas como fazemos um decorador aceitar outros argumentos? A resposta é: criar uma fábrica de decoradores que recebe aqueles argumentos e devolve um decorador, que é então aplicado à função a ser decorada. Confuso? Com certeza. Vamos começar com um exemplo baseado no decorador mais simples que vimos: `register` no <<registration_ex_repeat>>.

[[registration_ex_repeat]]
.O módulo registration.py resumido, do <<registration_ex>>, repetido aqui por conveniência
====
[source, python]
----
include::../code/09-closure-deco/registration_abridged.py[tags=REGISTRATION_ABRIDGED]
----
====

==== Um decorador de registro parametrizado

Para((("registration decorators", id="regdecor09"))) tornar mais fácil a habilitação ou desabilitação do registro executado por `register`, faremos esse último aceitar um parâmetro opcional `active` que, se `False`, não registra a função decorada. Conceitualmente, a nova função `register` não é um decorador mas uma fábrica de decoradores. Quando chamada, ela devolve o decorador que será realmente aplicado à função alvo.

[[registration_param_ex]]
.Para aceitar parâmetros, o novo decorador `register` precisa ser invocado como uma função
====
[source, python]
----
include::../code/09-closure-deco/registration_param.py[tags=REGISTRATION_PARAM]
----
====
<1> `registry` é agora um `set`, tornando mais rápido acrescentar ou remover funções.
<2> `register` recebe um argumento nomeado opcional.
<3> A função interna `decorate` é o verdadeiro decorador; observe como ela aceita uma função como argumento.
<4> Registra `func` apenas se o argumento `active` (obtido da clausura) for `True`.
<5> Se `not active` e `func in registry`, remove a função.
<6> Como `decorate` é um decorador, ele deve devolver uma função.
<7> `register` é nossa fábrica de decoradores, então devolve `decorate`.
<8> A fábrica `@register` precisa ser invocada como uma função, com os parâmetros desejados.
<9> Mesmo se nenhum parâmetro for passado, ainda assim `register` deve ser chamado como uma função—`@register()`—isto é, para devolver o verdadeiro decorador, `decorate`.

O ponto central aqui é que `register()` devolve `decorate`, que então é aplicado à função decorada.

O código do <<registration_param_ex>> está em um módulo _registration_param.py_. Se o importarmos, veremos o seguinte:

[source, python]
----
>>> import registration_param
running register(active=False)->decorate(<function f1 at 0x10063c1e0>)
running register(active=True)->decorate(<function f2 at 0x10063c268>)
>>> registration_param.registry
[<function f2 at 0x10063c268>]
----

Veja como apenas a função `f2` aparece no `registry`; `f1` não aparece porque `active=False` foi passado para a fábrica de decoradores `register`, então o `decorate` aplicado a  `f1` não adiciona essa função a `registry`.

Se, ao invés de usar a sintaxe `@`, usarmos `register` como uma função regular, a sintaxe necessária para decorar uma função `f` seria `register()(f)`, para inserir `f` ao `registry`, ou `register(active=False)(f)`, para não inseri-la (ou removê-la). Veja o <<registration_param_demo>> para uma demonstração da adição e remoção de funções do `registry`.

[[registration_param_demo]]
.Usando o módulo registration_param listado no <<registration_param_ex>>
====
[source, python]
----
>>> from registration_param import *
running register(active=False)->decorate(<function f1 at 0x10073c1e0>)
running register(active=True)->decorate(<function f2 at 0x10073c268>)
>>> registry  # <1>
{<function f2 at 0x10073c268>}
>>> register()(f3)  # <2>
running register(active=True)->decorate(<function f3 at 0x10073c158>)
<function f3 at 0x10073c158>
>>> registry  # <3>
{<function f3 at 0x10073c158>, <function f2 at 0x10073c268>}
>>> register(active=False)(f2)  # <4>
running register(active=False)->decorate(<function f2 at 0x10073c268>)
<function f2 at 0x10073c268>
>>> registry  # <5>
{<function f3 at 0x10073c158>}
----
====
<1> Quando o módulo é importado, `f2` é inserida no `registry`.
<2> A expressão `register()` devolve `decorate`, que então é aplicado a `f3`.
<3> A linha anterior adicionou `f3` ao `registry`.
<4> Essa chamada remove `f2` do `registry`.
<5> Confirma que apenas `f3` permanece no `registry`.

O funcionamento de decoradores parametrizados é bastante complexo, e esse que acabamos de discutir é mais simples que a maioria. Decoradores parametrizados em geral substituem a função decorada, e sua construção exige um nível adicional de aninhamento. Vamos agora explorar a arquitetura de uma dessas pirâmides de funções.((("", startref="regdecor09")))


==== Um decorador parametrizado de cronometragem

Nessa((("clock decorators", "parameterized", id="CDparam09"))) seção vamos revisitar o decorador `clock`, acrescentando um recurso: os usuários podem passar uma string de formatação, para controlar a saída do relatório sobre função cronometrada. Veja o <<clockdeco_param_ex>>.

[NOTE]
====
Para simplificar, o <<clockdeco_param_ex>> está baseado na implementação inicial de `clock` no <<ex_clockdeco0>>, e não na versão aperfeiçoada do <<ex_clockdeco2>> que usa `@functools.wraps`, acrescentando assim mais uma camada de função.
====

[[clockdeco_param_ex]]
.Módulo clockdeco_param.py: o decorador `clock` parametrizado
====
[source, python]
----
include::../code/09-closure-deco/clock/clockdeco_param.py[tags=CLOCKDECO_PARAM]
----
====
<1> `clock` é a nossa fábrica de decoradores parametrizados.
<2> `decorate` é o verdadeiro decorador.
<3> `clocked` envolve a função decorada.
<4> `_result` é o resultado efetivo da função decorada.
<5> `_args` mantém os verdadeiros argumentos de `clocked`, enquanto `args` é a `str` usada para exibição.
<6> `result` é a `str` que representa `_result`, para exibição.
<7> Usar `**locals()` aqui permite que qualquer variável local de `clocked` seja referenciada em `fmt`.footnote:[O revisor técnico Miroslav Šedivý observou: "Isso também quer dizer que analisadores de código-fonte (_linters_) vão reclamar de variáveis não utilizadas, pois eles tendem a ignorar o uso de `locals()`." Sim, esse é mais um exemplo de como ferramentas estáticas de verificação desencorajam o uso dos recursos dinâmicos de Python que primeiro me atraíram (e a incontáveis outros programadores) na linguagem. Para fazer o _linter_ feliz, eu poderia escrever cada variável local duas vezes na chamada: pass:[<code>fmt.format(elapsed=&#x200b;elapsed, name=name, args=args, result=result)</code>]. Prefiro não fazer isso. Se você usa ferramentas estáticas de verificação, é importante saber quando ignorá-las.]
<8> `clocked` vai substituir a função decorada, então ela deve devolver o mesmo que aquela função devolve.
<9> `decorate` devolve `clocked`.
<10> `clock` devolve `decorate`.
<11> Nesse auto-teste, `clock()` é chamado sem argumentos, então o decorador aplicado usará o formato default, `str`.

Se você rodar o <<clockdeco_param_ex>> no console, o resultado é o seguinte:

[source]
----
$ python3 clockdeco_param.py
[0.12412500s] snooze(0.123) -> None
[0.12411904s] snooze(0.123) -> None
[0.12410498s] snooze(0.123) -> None
----

Para exercitar a nova funcionalidade, vamos dar uma olhada em dois outros módulos que usam o `clockdeco_param`, o <<#ex_clockdecoparam_demo1>> e o <<#ex_clockdecoparam_demo2>>, e nas saídas que eles geram.

[[ex_clockdecoparam_demo1]]
.clockdeco_param_demo1.py
====
[source, python]
----
include::../code/09-closure-deco/clock/clockdeco_param_demo1.py[]
----
====

Saída do <<ex_clockdecoparam_demo1>>:

[source]
----
$ python3 clockdeco_param_demo1.py
snooze: 0.12414693832397461s
snooze: 0.1241159439086914s
snooze: 0.12412118911743164s
----

[[ex_clockdecoparam_demo2]]
.clockdeco_param_demo2.py
====
[source, python]
----
include::../code/09-closure-deco/clock/clockdeco_param_demo2.py[]
----
====

Saída do <<ex_clockdecoparam_demo2>>:

[source]
----
$ python3 clockdeco_param_demo2.py
snooze(0.123) dt=0.124s
snooze(0.123) dt=0.124s
snooze(0.123) dt=0.124s
----

[NOTE]
====
Lennart Regebro—um dos revisores técnicos da primeira edição—argumenta seria melhor programar decoradores como classes implementando `+__call__+`, e não como funções (caso dos exemplos nesse capítulo). Concordo que aquela abordagem é melhor para decoradores não-triviais. Mas para explicar a ideia básica desse recurso da linguagem, funções são mais fáceis de entender. Para técnicas robustas de criação de decoradores, veja as referências na <<decorator_further>>, especialmente o blog de Graham Dumpleton e o módulo `wrapt`, .
====

A próxima seção traz um exemplo no estilo recomendado por Regebro e Dumpleton.((("", startref="CDparam09")))

==== Um decorador de cronometragem em forma de classe

Como((("clock decorators", "class-based"))) um último exemplo, o <<clockdeco_param_cls_ex>> mostra a implementação de um decorador parametrizado `clock`, programado como uma classe com `+__call__+`.
Compare o <<clockdeco_param_ex>> com o <<clockdeco_param_cls_ex>>.
Qual você prefere?

[[clockdeco_param_cls_ex]]
.Módulo clockdeco_cls.py: decorador parametrizado `clock`, implementado como uma classe
====
[source, python]
----
include::../code/09-closure-deco/clock/clockdeco_cls.py[tags=CLOCKDECO_CLS]
----
====
<1> Ao invés de uma função externa `clock`, a classe `clock` é nossa fábrica de decoradores parametrizados. A nomeei com um `c` minúsculo, para deixar claro que essa implementação é uma substituta direta para aquela no <<clockdeco_param_ex>>.
<2> O argumento passado em `clock(my_format)` é atribuído ao parâmetro `fmt` aqui. O construtor da classe devolve uma instância de `clock`, com `my_format` armazenado em `self.fmt`.
<3> `+__call__+` torna a instância de `clock` invocável. Quando chamada, a instância substitui a função decorada com `clocked`.
<4> `clocked` envolve a função decorada.

Isso encerra nossa exploração dos decoradores de função. Veremos os decoradores de classe no <<ch_class_metaprog>>.((("", startref="DACparam09")))((("", startref="paramdec09")))


=== Resumo do capítulo

Percorremos((("decorators and closures", "overview of"))) um terreno acidentado nesse capítulo. Tentei tornar a jornada tão suave quanto possível, mas entramos definitivamente nos domínios da meta-programação.

Partimos de um decorador simples `@register`, sem uma função interna, e terminamos com um `@clock()` parametrizado envolvendo dois níveis de funções aninhadas.

Decoradores de registro, apesar de serem essencialmente simples, tem aplicações reais nos frameworks Python. Vamos aplicar a ideia de registro em uma implementação do padrão de projeto Estratégia, no <<ch_design_patterns>>.

Entender como os decoradores realmente funcionam exigiu falar da diferença entre _tempo de importação_ e _tempo de execução_. Então mergulhamos no escopo de variáveis, clausuras e a nova declaração `nonlocal`. Dominar as clausuras e `nonlocal` é valioso não apenas para criar decoradores, mas também para escrever programas orientados a eventos para GUIs ou E/S assíncrona com _callbacks_, e para adotar um estilo funcional quando fizer sentido.

Decoradores parametrizados quase sempre implicam em pelo menos dois níveis de funções aninhadas, talvez mais se você quiser usar `@functools.wraps`, e produzir um decorador com um suporte melhor a técnicas mais avançadas. Uma dessas técnicas é o empilhamento de decoradores, que vimos no <<fibo_demo_cache_ex>>. Para decoradores mais sofisticados, uma implementação baseada em classes pode ser mais fácil de ler e manter.

Como exemplos de decoradores parametrizados na biblioteca padrão, visitamos os poderosos `@cache` e `@singledispatch`, do módulo `functools`.


[[decorator_further]]
=== Para saber mais

O((("decorators and closures", "further reading on"))) item #26 do livro https://fpy.li/effectpy[_Effective Python_, 2nd ed.] (EN) (Addison-Wesley), de Brett Slatkin, trata das melhores práticas para decoradores de função, e recomenda sempre usar `functools.wraps`—que vimos no <<ex_clockdeco2>>.footnote:[Como queria manter o código o mais simples possível, não segui o excelente conselho de Slatkin em todos os exemplos.]

Graham Dumpleton tem, em seu blog, uma https://fpy.li/9-5[série de posts abrangentes] (EN) sobre técnicas para implementar decoradores bem comportados, começando com https://fpy.li/9-6["How you implemented your Python decorator is wrong" (_A forma como você implementou seu decorador em Python está errada_)]. Seus conhecimentos profundos sobre o assunto também estão muito bem demonstrados no módulo https://fpy.li/9-7[`wrapt`], que Dumpleton escreveu para simplificar a implementação de decoradores e invólucros (_wrappers_) dinâmicos de função, que suportam introspecção e se comportam de forma correta quando decorados novamente, quando aplicados a métodos e quando usados como descritores de atributos. O <<ch_descriptors>> na <<classes_protocols_part>> é sobre descritores.

https://fpy.li/9-8["Metaprogramming" (_Metaprogramação_)] (EN), o capítulo 9 do _Python Cookbook_, 3ª ed. de David Beazley e Brian K. Jones (O'Reilly), tem várias receitas ilustrando desde decoradores elementares até alguns muito sofisticados, incluindo um que pode ser invocado como um decorador regular ou como uma fábrica de decoradores, por exemplo, `@clock` ou `@clock()`. É a  "Recipe 9.6. Defining a Decorator That Takes an Optional Argument" (_Receita 9.6. Definindo um Decorador Que Recebe um Argumento Opcional_)  desse livro de receitas.

Michele Simionato criou um pacote com objetivo de "simplificar o uso de decoradores para o programador comum, e popularizar os decoradores através da apresentação de vários exemplos não-triviais", de acordo com a documentação. Ele está disponível no PyPI, em https://fpy.li/9-9[decorator [.keep-together]#package# (_pacote decorador_)] (EN).

Criada quando os decoradores ainda eram um recurso novo no Python, a página wiki https://fpy.li/9-10[Python Decorator Library] (EN) tem dezenas de exemplos. Como começou há muitos anos, algumas das técnicas apresentadas foram suplantadas, mas ela ainda é uma excelente fonte de inspiração.

https://fpy.li/9-11["Closures in Python" (_Clausuras em Python_)] (EN) é um post de blog curto de Fredrik Lundh, explicando a terminologia das clausuras.

A https://fpy.li/9-12[PEP 3104--Access to Names in Outer Scopes (_Acesso a Nomes em Escopos Externos_)] (EN) descreve a introdução da declaração pass:[<span class="keep-together"><code>nonlocal</code></span>], para permitir a re-vinculação de nomes que não são nem locais nem globais. Ela também inclui uma excelente revisão de como essa questão foi resolvida em outras linguagens dinâmicas (Perl, Ruby, JavaScript, etc.) e os prós e contras das opções de design disponíveis para Python.

Em um nível mais teórico, a https://fpy.li/9-13[PEP 227--Statically Nested Scopes (_Escopos Estaticamente Aninhados_)] (EN) documenta a introdução do escopo léxico como um opção no Python 2.1 e como padrão no Python 2.2, explicando a justificativa e as opções de design para a implementação de clausuras no Python.

A https://fpy.li/9-14[PEP 443] (EN) traz a justificativa e uma descrição detalhada do mecanismo de funções genéricas de despacho único.
Um post de Guido van Rossum de março de 2005
https://fpy.li/9-15["Five-Minute Multimethods in Python" (_Multi-métodos em Python em Cinco Minutos_)] (EN),
mostra os passos para uma implementação de funcões genéricas (também chamadas multi-métodos) usando decoradores.
O código de multi-métodos de Guido é interessante, mas é apenas um exemplo didático.
Para conhecer uma implementação de funções genéricas de despacho múltiplo moderna e pronta para uso em produção,
veja a https://fpy.li/9-16[Reg] de
Martijn Faassen–autor de https://fpy.li/9-17[Morepath],
um framework web guiado por modelos e orientado a REST.

[[closures_soapbox]]
[role="pagebreak-before less_space"]
.Ponto de vista
****

[role="soapbox-title"]
**Escopo dinâmico versus escopo léxico**

O((("Soapbox sidebars", "dynamic scope versus lexical scope", id="SSdynamic09")))((("decorators and closures", "Soapbox discussion", id="DACsoap09")))((("scope", "dynamic scope versus lexical scope", id="Scynamic09"))) projetista de qualquer linguagem que contenha funções de primeira classe se depara com essa questão:
sendo um objeto de primeira classe, uma função é definida dentro de um determinado escopo, mas pode ser invocada em outros escopos.
A pergunta é: como avaliar as variáveis livres?
A resposta inicial e mais simples é "escopo dinâmico".
Isso significa que variáveis livres são avaliadas olhando para dentro do ambiente onde a funcão é invocada.

Se Python tivesse escopo dinâmico e não tivesse clausuras, poderíamos improvisar `avg`—similar ao <<ex_average_fn>>—assim:

[source, python]
----
>>> ### this is not a real Python console session! ###
>>> avg = make_averager()
>>> series = []  # <1>
>>> avg(10)
10.0
>>> avg(11)  # <2>
10.5
>>> avg(12)
11.0
>>> series = [1]  # <3>
>>> avg(5)
3.0
----
<1> Antes de usar `avg`, precisamos definir por nós mesmos `series = []`, então precisamos saber que `averager` (dentro de `make_averager`) se refere a uma lista chamada `series`.
<2> Por trás da cortina, `series` acumula os valores cuja média será calculada.
<3> Quando `series = [1]` é executada, a lista anterior é perdida. Isso poderia ocorrer por acidente, ao se tratar duas médias continuas independentes ao mesmo tempo.

Funções deveriam ser opacas, sua implementação invisível para os usuários. Mas com escopo dinâmico, se a função usa variáveis livres, o programador precisa saber do funcionamento interno da função, para ser capaz de configurar um ambiente onde ela execute corretamente. Após anos lutando com a linguagem de preparação de documentos LaTeX, o excelente livro _Practical LaTeX_ (LaTeX Prático), de George Grätzer (Springer), me ensinou que as variáveis no LaTeX usam escopo dinâmico. Por isso me confundiam tanto!

O Lisp do Emacs também usa escopo dinâmico, pelo menos como default. Veja https://fpy.li/9-18["Dynamic Binding" (_Vinculação Dinâmica_)] no manual do Emacs para uma breve explicação.

O escopo dinâmico é mais fácil de implementar, e essa foi provavelmente a razão de John McCarthy ter tomado esse caminho quando criou o Lisp, a primeira linguagem a ter funções de primeira classe. O texto de Paul Graham, https://fpy.li/9-19["The Roots of Lisp" (_As Raízes do Lisp_)] é uma explicação acessível do artigo original de John McCarthy sobre a linguagem Lisp, pass:[<a href="https://fpy.li/9-20">"<span class='keep-together'>Recursive</span> <span class='keep-together'>Functions</span> of <span class='keep-together'>Symbolic</span> Expressions and Their Computation by Machine, Part I" (<em>Funções Recursivas de Expressões Simbólicas e Sua Computação via Máquina</em>)</a>]. O artigo de McCarthy é uma obra prima no nível da Nona Sinfonia de Beethoven. Paul Graham o traduziu para o resto de nós, da matemática para o inglês e o código executável.

O comentário de Paul Graham explica como o escopo dinâmico é complexo. Citando o "_The Roots of Lisp_":

[quote]
____
É um testemunho eloquente dos perigos do escopo dinâmico, que mesmo o primeiro exemplo de funções de ordem superior em Lisp estivesse errado por causa dele. Talvez, em 1960, McCarthy não estivesse inteiramente ciente das implicações do escopo dinâmico, que continuou presente nas implementações de Lisp por um tempo surpreendentemente longo—até Sussman e Steele desenvolverem o Scheme, em 1975. O escopo léxico não complica demais a definição de `eval`, mas pode tornar mais difícil escrever compiladores.
____

Hoje em dia o escopo léxico é o padrão: variáveis livres são avaliadas considerando o ambiente onde a função foi definida. O escopo léxico complica a implementação de linguagens com funções de primeira classe, pois requer o suporte a clausuras. Por outro lado, o escopo léxico torna o código-fonte mais fácil de ler. A maioria das linguagens inventadas desde o Algol tem escopo léxico. Uma exceção notável é o JavaScript, onde a variável especial `this` é confusa, pois pode ter escopo léxico ou dinâmico, https://fpy.li/9-21[dependendo da forma como o código for escrito] (EN).

Por muitos anos, o `lambda` de Python não ofereceu clausuras, contribuindo para a má fama deste recurso entre os fãs da programação funcional na blogosfera. Isso foi resolvido no Python 2.2 (de dezembro de 2001), mas a blogosfera tem uma memória muito boa. Desde então, `lambda` é embaraçoso apenas por sua sintaxe limitada.((("", startref="Scynamic09")))((("", startref="SSdynamic09")))

[role="soapbox-title"]
**Os decoradores de Python e o padrão de projeto Decorator**

Os decoradores de função((("Soapbox sidebars", "Python decorators and decorator design pattern"))) de Python se encaixam na descrição geral dos decoradores de Gamma et al. em _Padrões de Projeto_: "Acrescenta responsabilidades adicionais a um objeto de forma dinâmica. Decoradores fornecem uma alternativa flexível à criação de subclasses para estender funcionalidade."

Ao nível da implementação, os decoradores de Python não lembram o padrão de projeto decorador clássico, mas é possível fazer uma analogia.

No padrão de projeto, `Decorador` e `Componente` são classes abstratas. Uma instância de um decorador concreto envolve uma instância de um componente concreto para adicionar comportamentos a ela. Citando _Padrões de Projeto_:

[quote]
____
O decorador se adapta à interface do componente decorado, assim sua presença é transparente para os clientes do componente. O decorador encaminha requisições para o componente e pode executar ações adicionais (tal como desenhar uma borda) antes ou depois do encaminhamento. A transparência permite aninhar decoradores de forma recursiva, possibilitando assim um número ilimitado de responsabilidades adicionais. (p. 175 da edição em inglês)
____

No Python, a funcão decoradora faz o papel de uma subclasse concreta de `Decorador`, e a função interna que ela devolve é uma instância do decorador. A função devolvida envolve a função a ser decorada, que é análoga ao componente no padrão de projeto. A função devolvida é transparente, pois se adapta à interface do componente (ao aceitar os mesmos argumentos). Pegando emprestado da citação anterior, podemos adaptar a última frase para dizer que "A transparência permite empilhar decoradores, possibilitando assim um número ilimitado de comportamentos adicionais".

Veja que não estou sugerindo que decoradores de função devam ser usados para implementar o padrão decorador em programas Python. Apesar disso ser possível em situações específicas, em geral o padrão decorador é melhor implementado com classes representando o decorador e os componentes que ela vai envolver.((("", startref="DACsoap09")))
****
