Sou iniciante em python e acabei de aprender uma técnica envolvendo dicionários e funções. A sintaxe é fácil e parece uma coisa trivial, mas meus sentidos em python estão formigando. Algo me diz que esse é um conceito profundo e muito pitônico e não estou percebendo sua importância. Alguém pode colocar um nome nessa técnica e explicar como / por que é útil?
A técnica é quando você tem um dicionário python e uma função que pretende usar nele. Você insere um elemento extra no dict, cujo valor é o nome da função. Quando você estiver pronto para chamar a função, emita-a indiretamente consultando o elemento dict, não a função pelo nome.
O exemplo do qual estou trabalhando é de Learn Python the Hard Way, 2nd Ed. (Esta é a versão disponível quando você se inscreve no Udemy.com ; infelizmente, a versão HTML gratuita ao vivo é atualmente o Ed 3 e não inclui mais este exemplo).
Parafrasear:
# make a dictionary of US states and major cities
cities = {'San Diego':'CA', 'New York':'NY', 'Detroit':'MI'}
# define a function to use on such a dictionary
def find_city (map, city):
# does something, returns some value
if city in map:
return map[city]
else:
return "Not found"
# then add a final dict element that refers to the function
cities['_found'] = find_city
Em seguida, as seguintes expressões são equivalentes. Você pode chamar a função diretamente ou referenciando o elemento dict cujo valor é a função.
>>> find_city (cities, 'New York')
NY
>>> cities['_found'](cities, 'New York')
NY
Alguém pode explicar qual é o recurso de linguagem e talvez onde ele toca na programação "real"? Esse exercício de brinquedo foi suficiente para me ensinar a sintaxe, mas não me levou até lá.
fonte
Respostas:
Usando um dict, você pode traduzir a chave em uma chamada. A chave não precisa ser codificada, como no seu exemplo.
Geralmente, essa é uma forma de envio de chamadas, em que você usa o valor de uma variável para se conectar a uma função. Digamos que um processo de rede envie códigos de comando, um mapeamento de despacho permite traduzir facilmente os códigos de comando em código executável:
Observe que a função que chamamos agora depende inteiramente de qual é o valor
command
. A chave também não precisa corresponder; nem precisa ser uma string, você pode usar qualquer coisa que possa ser usada como chave e se adequar ao seu aplicativo específico.O uso de um método de despacho é mais seguro do que outras técnicas, como
eval()
, pois limita os comandos permitidos ao que você definiu anteriormente. Nenhum invasor furtará umals)"; DROP TABLE Students; --
injeção por uma tabela de despacho, por exemplo.fonte
dict
atos como o despachante (gerente de comando, invocador, etc.).@Martijn Pieters fez um bom trabalho ao explicar a técnica, mas queria esclarecer algo da sua pergunta.
O importante é saber que você NÃO está armazenando "o nome da função" no dicionário. Você está armazenando uma referência à própria função. Você pode ver isso usando um
print
na função.f
é apenas uma variável que referencia a função que você definiu. O uso de um dicionário permite agrupar coisas semelhantes, mas não é diferente de atribuir uma função a uma variável diferente.Da mesma forma, você pode passar uma função como argumento.
fonte
Observe que a classe Python é realmente apenas um açúcar de sintaxe para o dicionário. Quando você faz:
quando Você ligar
é realmente o mesmo que:
que, após a resolução do nome, é igual a:
Uma técnica útil é mapear a entrada do usuário para retornos de chamada. Por exemplo:
Como alternativa, isso pode ser escrito na classe:
a sintaxe de retorno de chamada melhor depende do aplicativo específico e do gosto do programador. O primeiro é um estilo mais funcional, o segundo é mais orientado a objetos. O primeiro pode parecer mais natural se você precisar modificar as entradas no dicionário de funções dinamicamente (talvez com base na entrada do usuário); o último pode parecer mais natural se você tiver um conjunto de mapeamentos de predefinições diferentes que podem ser escolhidos dinamicamente.
fonte
5 * x
para5x
(perdoe a analogia simples).Existem duas técnicas que vêm à minha mente às quais você pode estar se referindo, nenhuma das quais é pitônica, pois são mais amplas que uma língua.
1. A técnica de ocultação / encapsulamento e coesão de informações (elas geralmente andam de mãos dadas, então eu as estou juntando).
Você tem um objeto que possui dados e anexa um método (comportamento) que é altamente coeso com os dados. Se você precisar alterar a função, estender a funcionalidade ou fazer outras alterações, os chamadores não precisarão alterar (supondo que nenhum dado adicional precise ser passado).
2. Tabelas de expedição
Não é o caso clássico, porque há apenas uma entrada com uma função. No entanto, as tabelas de expedição são usadas para organizar comportamentos diferentes por uma chave, para que possam ser consultadas e chamadas dinamicamente. Não tenho certeza se você pensa nisso, pois não se refere à função de maneira dinâmica, mas mesmo assim você ainda ganha uma ligação tardia eficaz (a chamada "indireta").
Tradeoffs
Uma coisa a observar é que o que você fará funcionará bem com um namespace conhecido de chaves. No entanto, você corre o risco de colisão entre os dados e as funções com um espaço de nome desconhecido das chaves.
fonte
Publico esta solução que considero bastante genérica e que pode ser útil, pois é simples e fácil de adaptar a casos específicos:
também é possível definir uma lista em que cada elemento é um objeto de função e usar o
__call__
método incorporado. Créditos a todos pela inspiração e cooperação."O grande artista é o simplificador", Henri Frederic Amiel
fonte