Quando você começa a ler um pouquinho mais a fundo sobre linguagens de programação em geral, ou Python em específico, é comum encontrar referências dizendo que funções em python são objetos de primeira classe. Mas o que significa isso?
Dizer que funções são objetos de primeira classe em uma linguagem de programação significa que naquela linguagem uma função é um objeto como qualquer outro, podendo ser tratada da mesma forma que os demais objetos. Ou seja, podemos atribuir uma função a uma variável (ou melhor, dar um nome a uma função), passar uma função como parâmetro para outra função, além de outras operações. Como em Python as funções são objetos de primeira classe, vamos ver alguns exemplos:
def soma(x, y): return x + y >>> type(soma) function >>> s = soma >>> s(1, 2) 3 >>> soma(1, 2) 3
No exemplo acima, criamos uma função, que nada mais é do que um objeto do tipo function, e inicialmente referenciamos ela pelo nome soma. Como essa função é um objeto como qualquer outro, podemos então criar uma nova referência a ela (s no exemplo acima).
O mais legal de podermos tratar funções assim é que podemos passar funções como argumentos para outras funções. Como exemplo, vamos criar uma função semelhante à função builtin filter. Ela irá receber uma lista de elementos (de qualquer tipo) e uma função que determina se o elemento deve ser incluso na lista de resultados ou não.
def filtra(lista, aceita):
result = []
for elemento in lista:
if aceita(elemento):
result.append(elemento)
return result
No exemplo acima, aceita deve ser um objeto do tipo function, que verifique algo em um objeto qualquer e retorne True ou False (ou outros valores que podem ser avaliados como tal). Feito isso, agora vamos usar a função filtra recém definida.
def eh_positivo(valor):
return valor > 0
lista_de_int = [-10, 10, 2, -7, 3, 5, 1]
nova_lista = filtra(lista_de_int, eh_positivo)
print nova_lista # imprime [10, 2, 3, 5, 1]
No exemplo acima, passamos à função filtra uma lista de inteiros e uma função apropriada para aceitação de elementos do tipo int. O mais interessante de a função filtra receber uma função como parâmetro é que isso a deixa muito mais flexível, pois ela poderá funcionar para elementos de qualquer tipo e para as mais variadas semânticas de aceitação de valores, desde que seja fornecida uma função apropriada para isso. Abaixo, definimos uma função que aceita strings que contém espaços e rejeita as que não contém.
def tem_espacos(s):
return ' ' in s
lista_de_str = ["olá mundo", "hello", "testando 123"]
print filtra(lista_de_str, tem_espacos) # imprime ["olá mundo", "testando 123"]
Existem várias funções prontas que aceitam outras funções como argumentos. Anteriormente, aqui no blog, já vimos map, reduce e filter. Ao ordenar uma lista podemos passar uma função que será usada para comparar os elementos, e existem muitos outros exemplos.
Com a possibilidade de tratar funções como objetos, podemos escrever funções genéricas para lidar com dados independentemente do tipo.