Introdução
Esta seção introduz a ideia de usar funções para criar outras funções.
This tutorial is from open-source community. Access the source code
💡 Este tutorial foi traduzido do inglês com assistência de IA. Para ver o original, você pode mudar para a versão em inglês
Esta seção introduz a ideia de usar funções para criar outras funções.
Considere a seguinte função.
def add(x, y):
def do_add():
print('Adding', x, y)
return x + y
return do_add
Esta é uma função que retorna outra função.
>>> a = add(3,4)
>>> a
<function add.<locals>.do_add at 0x7f27d8a38790>
>>> a()
Adding 3 4
7
Observe como a função interna se refere a variáveis definidas pela função externa.
def add(x, y):
def do_add():
## `x` and `y` are defined above `add(x, y)`
print('Adding', x, y)
return x + y
return do_add
Observe ainda que essas variáveis são de alguma forma mantidas ativas após a conclusão de add()
.
>>> a = add(3,4)
>>> a
<function do_add at 0x6a670>
>>> a()
Adding 3 4 ## Where are these values coming from?
7
Quando uma função interna é retornada como resultado, essa função interna é conhecida como um closure (fechamento).
def add(x, y):
## `do_add` is a closure
def do_add():
print('Adding', x, y)
return x + y
return do_add
Característica essencial: Um closure retém os valores de todas as variáveis necessárias para que a função seja executada corretamente posteriormente. Pense em um closure como uma função mais um ambiente extra que contém os valores das variáveis das quais ela depende.
Closures (fechamentos) são uma característica essencial do Python. No entanto, seu uso é frequentemente sutil. Aplicações comuns:
Considere uma função como esta:
def after(seconds, func):
import time
time.sleep(seconds)
func()
Exemplo de uso:
def greeting():
print('Hello Guido')
after(30, greeting)
after
executa a função fornecida... mais tarde.
Closures (fechamentos) carregam informações extras.
def add(x, y):
def do_add():
print(f'Adding {x} + {y} -> {x+y}')
return do_add
def after(seconds, func):
import time
time.sleep(seconds)
func()
after(30, add(2, 3))
## `do_add` has the references x -> 2 and y -> 3
Closures (fechamentos) também podem ser usados como uma técnica para evitar repetição excessiva de código. Você pode escrever funções que criam código.
Uma das características mais poderosas dos closures (fechamentos) é seu uso na geração de código repetitivo. Se você voltar ao Exercício 5.7, lembre-se do código para definir uma propriedade com verificação de tipo.
class Stock:
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
...
@property
def shares(self):
return self._shares
@shares.setter
def shares(self, value):
if not isinstance(value, int):
raise TypeError('Expected int')
self._shares = value
...
Em vez de digitar repetidamente esse código, você pode criá-lo automaticamente usando um closure.
Crie um arquivo typedproperty.py
e coloque o seguinte código nele:
## typedproperty.py
def typedproperty(name, expected_type):
private_name = '_' + name
@property
def prop(self):
return getattr(self, private_name)
@prop.setter
def prop(self, value):
if not isinstance(value, expected_type):
raise TypeError(f'Expected {expected_type}')
setattr(self, private_name, value)
return prop
Agora, experimente definindo uma classe como esta:
from typedproperty import typedproperty
class Stock:
name = typedproperty('name', str)
shares = typedproperty('shares', int)
price = typedproperty('price', float)
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
Tente criar uma instância e verificar se a verificação de tipo funciona.
>>> s = Stock('IBM', 50, 91.1)
>>> s.name
'IBM'
>>> s.shares = '100'
... should get a TypeError ...
>>>
No exemplo acima, os usuários podem achar chamadas como typedproperty('shares', int)
um pouco verbosas para digitar - especialmente se forem repetidas muitas vezes. Adicione as seguintes definições ao arquivo typedproperty.py
:
String = lambda name: typedproperty(name, str)
Integer = lambda name: typedproperty(name, int)
Float = lambda name: typedproperty(name, float)
Agora, reescreva a classe Stock
para usar essas funções em vez disso:
class Stock:
name = String('name')
shares = Integer('shares')
price = Float('price')
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
Ah, isso é um pouco melhor. A principal conclusão aqui é que closures (fechamentos) e lambda
podem frequentemente ser usados para simplificar o código e eliminar repetições irritantes. Isso geralmente é bom.
Parabéns! Você concluiu o laboratório de Retorno de Funções. Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.