Que funcionalidade functools.partial
oferece e que você não consegue passar pelas lambdas?
Não há muito em termos de funcionalidade extra (mas, veja mais adiante) - e a legibilidade está nos olhos de quem vê.
A maioria das pessoas que estão familiarizadas com linguagens de programação funcionais (aquelas da família Lisp / Scheme em particular) parece gostar lambda
muito bem - eu digo "a maioria", definitivamente não todas, porque Guido e eu certamente estamos entre os "familiarizados" (etc ) ainda pense lambda
como uma anomalia desagradável em Python ...
Ele se arrependeu de ter aceitado o Python, enquanto planejava removê-lo do Python 3, como uma das "falhas do Python".
Eu o apoiei totalmente nisso. (Adoro lambda
no Scheme ... enquanto suas limitações em Python e a maneira estranha como ele simplesmente não faz ' com o resto do idioma, faça minha pele arrepiar).
Não é assim, no entanto, para as hordas de lambda
amantes - que encenaram uma das coisas mais próximas de uma rebelião já vista na história de Python, até Guido voltar atrás e decidir sair lambda
.
Várias adições possíveis a functools
(para fazer funções retornarem constantes, identidade, etc) não aconteceu (para evitar duplicar explicitamente mais lambda
funcionalidades), embora partial
tenha permanecido, é claro (não é uma duplicação total , nem é uma desagradável).
Lembre-se de que lambda
o corpo é limitado para ser uma expressão , por isso tem limitações. Por exemplo...:
>>> import functools
>>> f = functools.partial(int, base=2)
>>> f.args
()
>>> f.func
<type 'int'>
>>> f.keywords
{'base': 2}
>>>
functools.partial
A função retornada é decorada com atributos úteis para introspecção - a função que está agrupando e quais argumentos posicionais e nomeados ela fixa nela. Além disso, os argumentos nomeados podem ser substituídos de volta (a "correção" é, em certo sentido, a configuração dos padrões):
>>> f('23', base=10)
23
Então, como você vê, definitivamente não é tão simplista quanto lambda s: int(s, base=2)
! -)
Sim, você pode contorcer seu lambda para fornecer um pouco disso, por exemplo, para a substituição de palavras-chave,
>>> f = lambda s, **k: int(s, **dict({'base': 2}, **k))
mas espero sinceramente que mesmo o lambda
amante mais ardente não considere esse horror mais legível do que a partial
ligação! -). A parte "configuração do atributo" é ainda mais difícil, devido à limitação "do corpo como uma única expressão" do Python lambda
(além do fato de que a atribuição nunca poder fazer parte de uma expressão do Python) ... você acaba "fingindo atribuições dentro de uma expressão" estendendo a compreensão da lista muito além dos limites de design ...:
>>> f = [f for f in (lambda f: int(s, base=2),)
if setattr(f, 'keywords', {'base': 2}) is None][0]
Agora combine a substituibilidade dos argumentos nomeados, mais a configuração de três atributos, em uma única expressão e me diga o quão legível isso será ...!
functools.partial
mencionada o torna superior ao lambda. Talvez este seja o tópico de outro post, mas o que é que em um nível de design o incomoda tantolambda
?def
elambda
palavras-chave: crie os doisfunction
(uma escolha de nome Javascript ficou realmente certa) e pelo menos 1/3 das minhas objeções desapareceriam ! -). Como eu disse, não tenho nenhuma objeção a lambda no Lisp ...!)def
qualquer maneira. Nosso líder benevolente falou!Bem, aqui está um exemplo que mostra uma diferença:
Essas postagens de Ivan Moore expandem as "limitações do lambda" e os fechamentos em python:
fonte
lambda y, n=n: ...
. A ligação tardia (de nomes que aparecem apenas no corpo de uma função, não em seudef
equivalente ou em outralambda
) é apenas um bug, como já mostrei detalhadamente em longas respostas de SO no passado: você vincula explicitamente quando é isso que deseja, use o padrão de ligação tardia quando é isso que você deseja, e essa é exatamente a escolha certa para o design, dado o contexto do restante do design do Python.Nas versões mais recentes do Python (> = 2.7), você pode
pickle
apartial
, mas não alambda
:fonte
multiprocessing.Pool.map()
. stackoverflow.com/a/3637905/195139partial
é selecionável no Python 2.7.Como resposta parcial a isso, decidi testar o desempenho. Aqui está o meu exemplo:
no Python 3.3, ele fornece:
O que significa que o parcial precisa de um pouco mais de tempo para criação, mas consideravelmente menos tempo para a execução. Isso pode muito bem ser o efeito da ligação antecipada e tardia, discutida na resposta de ars .
fonte
partial
é escrito em C, em vez de puro Python, o que significa que pode produzir uma chamada mais eficiente do que simplesmente criar uma função que chama outra função.Além da funcionalidade extra mencionada por Alex, outra vantagem do functools.partial é a velocidade. Com parcial, você pode evitar construir (e destruir) outro quadro de pilha.
Nem a função gerada por parciais nem por lambdas possui documentos por padrão (embora você possa definir o documento para qualquer objeto via
__doc__
).Você pode encontrar mais detalhes neste blog: Aplicativo de Função Parcial em Python
fonte
Entendo a intenção mais rapidamente no terceiro exemplo.
Quando analiso lambdas, espero mais complexidade / singularidade do que a oferecida pela biblioteca padrão diretamente.
Além disso, você notará que o terceiro exemplo é o único que não depende da assinatura completa de
sum2
; tornando-o assim um pouco mais frouxamente acoplado.fonte
functools.partial
ligação, enquanto as lambdas são evidentes.