2009-09-23 21 views
6

esto es del código fuente de csv2rec en matplotlib¿Cómo funciona este código de función python?

¿cómo puede funcionar esta función, si sus únicos parámetros son 'func, default'?

def with_default_value(func, default): 
    def newfunc(name, val): 
     if ismissing(name, val): 
      return default 
     else: 
      return func(val) 
    return newfunc 

IsMissing toma un nombre y un valor y determina si la fila debe ser enmascarada en una matriz numpy.

func será str, int, float o dateparser ... convierte datos. Tal vez no es importante. Me pregunto cómo puede obtener un 'nombre' y un 'valor'

Soy un principiante. Gracias por cualquier 2cents! ¡Espero ser lo suficientemente bueno para ayudar a otros!

+1

¿No debería haber un espacio como "si IsMissing"? – recursive

Respuesta

8

Esta función with_default_value es lo que se refiere a menudo (imprecisa) como "un cierre" (técnicamente, el cierre es más bien el interior función que es devuelto, aquí newfunc - véase, por ejemplo here). De forma más genérica, with_default_value es una función de orden superior ("HOF"): toma una función (func) como argumento, también devuelve una función (newfunc) como resultado.

que he visto respuestas confusas esto con el decorador concepto y construir en Python, que es definitivamente no el caso - especialmente desde que mencionas func tan a menudo ser incorporada como int. Los decoradores son también funciones de orden superior, pero más específicas: las que devuelven un decorado, es decir"enriquecido", versión de su argumento de función (que debe ser el único argumento - "decoradores con argumentos" se obtienen a través de un nivel más de función/anidación de cierre, no dando al decorador HOF más de un argumento) , que se reasigna a exactamente el mismo nombre que el argumento de la función (y por lo general tiene la misma firma - con ayuda de un decorador de otra forma sería muy peculiar, no-idiomática, ilegibles, etc).

Así que olvidemos decoradores, que no tienen absolutamente nada que ver con el caso, y se centran en el cierre newfunc. Una función anidada léxicamente puede referirse (aunque no reenlazar) a todos los nombres de variables locales (incluidos los nombres de los argumentos, ya que los argumentos son variables locales) de la (s) función (es) adjunta (s), es por eso que se conoce como cierre: está "cerrado". "variables libres". Aquí, newfunc puede hacer referencia a func y default - y lo hace.

Las funciones de orden superior son muy naturales en Python, especialmente porque las funciones son objetos de primera clase (por lo que no hay nada especial que hacer para pasarlos como argumentos, devolverlos como valores de función o incluso almacenarlos en listas u otros contenedores, etc.), y no hay distinción de espacio de nombres entre funciones y otros tipos de objetos, no hay llamadas automáticas de funciones solo porque se mencionan, etc., etc. (Es más difícil, un poco más difícil o MUCHO más difícil, dependiendo - en otros idiomas que atraen muchas distinciones de este tipo). En Python, mencionar una función es solo eso, una mención; la llamada solo se produce si y cuando el objeto de función (al que se hace referencia por nombre o de otro modo) va seguido de paréntesis.

Eso es todo lo que hay a este ejemplo - por favor no dude en corregir su pregunta, comentar aquí, etc, si hay algún otro aspecto específico que usted permanece en duda acerca!

Editar: por lo que el OP comentó cortésmente pidiendo más ejemplos de "fábricas de cierre". Aquí hay uno - imaginar alguna clase abstracta de herramientas GUI, y que está tratando de hacer:

for i in range(len(buttons)): 
    buttons[i].onclick(lambda: mainwin.settitle("button %d click!" % i)) 

pero esto no funciona bien - i dentro del lambda es enlazada en tiempo, de manera que cuando uno se hace clic i 's valor siempre va a ser el índice del último botón , no importa donde se ha hecho una. Hay varias soluciones factibles, pero una fábrica de cierre es una posibilidad elegante:

def makeOnclick(message): 
    return lambda: mainwin.settitle(message) 

for i in range(len(buttons)): 
    buttons[i].onclick(makeOnClick("button %d click!" % i)) 

Aquí, estamos utilizando la fábrica de cierre para ajustar el tiempo de unión de las variables -) En una forma específica u otra, se trata de una caso de uso bastante común para las fábricas de cierre.

+0

Creo que estoy corregido. Gracias por hacer la distinción. ¿Cómo podría llamarse este HOF, entonces? – dcrosta

+0

@dcrosta, que no tienen un nombre formal de este idioma - al igual que para la mayoría de Höfs regresar cierres, sólo pienso en ello como una forma práctica de aplicar una fábrica de funciones. –

+0

gran respuesta, fue una batalla, primero pensé que el otro tipo la tenía, ¡y luego vienes para el touchdown! ¡Gracias, creo que todos aprendimos algo! Me preguntaba si tienes otros ejemplos de esto. Sólo curioso. No se preocupe si es muy difícil encontrar uno/hacer uno. – Pete

0

Esta es una función que devuelve otra función. name y value son los parámetros de la función devuelta.

6

Este es un decorador de Python, básicamente un contenedor de funciones. (Lea todo sobre decoradores en PEP 318 - http://www.python.org/dev/peps/pep-0318/)

Si se mira a través del código, es probable que encontrar algo como esto:

def some_func(name, val): 
    # ... 
some_func = with_default_value(some_func, 'the_default_value') 

La intención de este decorador parece proporcionar un valor por defecto si o bien el nombre o los argumentos val faltan (presumiblemente, si están configurados como Ninguno).

+0

Exactamente, excepto que habría nuevo código comúnmente se parecen más a: @with_default_value (some_func, 'the_default_value') def some_func (nombre, val): # ... –

+0

Creo que si se utiliza la sintaxis @ (antes de la definición de función), debe tener una fábrica decoradora (mientras que este es un desolador puro - 2 niveles de profundidad). La fábrica decoradora puede aceptar argumentos, pero no es necesario. A menos que esto haya cambiado en 3.x – dcrosta

+0

@dcrosta: No lo creo. He estado usando ambas sintaxis con decoradores indistintamente sin efectos negativos en 2.X – priestc

1

En cuanto a por qué funciona:

with_default_value devuelve un objeto función, que es básicamente va a ser una copia de ese newfunc anidada, con el 'func' llamar y el valor por defecto substited con lo que se pasó a with_default_value

Si alguien hace 'foo = with_default_value (bar, 3)', el valor de retorno es, básicamente, va a ser una función nueva:

def foo(name, val): 
    ifismissing(name, val): 
     return 3 
    else: 
     return bar(val) 

modo que lo pueda tomar ese valor de retorno, y lo llaman.

Cuestiones relacionadas