2012-09-19 814 views
5

He estado buscando el código fuente de un paquete de código abierto que estoy usando. Casi todas las funciones usan * argumentos en lugar de argumentos con nombre. Me resulta difícil seguir y utilizar el código, porque cada vez que quiero llamar a una función, tengo que volver atrás, seleccionar el código fuente e identificar cuáles deberían ser los argumentos y en qué orden deberían estar. La pregunta que tengo es esta: ¿hay alguna razón convincente para usar * args en cada función, o es esto un abuso del concepto? Gracias , -bUso adecuado frente al uso excesivo de * args en Python

+0

Si hay * args, tiene que haber un docstring (¡exacto!). – James

+0

¿Qué paquete es? No jugar el juego de la culpa, pero pueden tener una razón válida. –

Respuesta

4

Esto podría ser un razonamiento personal, pero solo uso * args y ** kwargs cuando tengo muchos campos opcionales donde algunos campos solo se usan en un contexto determinado.

La única otra ocasión que utilicé args es cuando estaba construyendo un cliente XML RPC para una API en la nube. Como solo estaba pasando los parámetros a una capa subyacente y como la función se generó dinámicamente, no tuve más remedio que usar * args ya que no tenía manera de conocer todos los parámetros de antemano.

En la mayoría de los casos, ni siquiera lo necesitará. Considero que es mayormente pereza que cualquier otra cosa.

Algunas personas que provienen de Java y C# pueden usar esto como reemplazo de "params", pero hay tantas formas de pasar parámetros opcionales en python.

Y acepto que incluso si usa * args, debe tener una muy buena documentación.

+0

En dos años de codificación C# He usado 'params' dos veces. En un mes de Python, he visto '(* args, ** kwargs)' tantas veces que me sangran los ojos. Recomendaría usarlo con moderación; es una herramienta que debería usarse para resolver un problema muy específico. Y como sabemos, cuando le das a las personas una herramienta que es así de fácil de usar, abusarán de ella y abusarán de ella sin fin. – Dagrooms

3

Uso *args en cada función es una mala idea, ya que puede enmascarar errores en su código (llamar a una función con un número incorrecto de argumentos). Supongo que la regla de oro debería ser usar *args solo si necesita*args.

2

Cuando no hay una razón de peso para usar *args, es un abuso del concepto. Por lo general, hay buenos nombres para los argumentos, que ayudan a la comprensión. Incluso cuando no los hay, (x, y, z) le dice más de (*args).

Y más allá de hacer el código más legible, sino que también ayuda a detectar errores (por ejemplo, si se llama a una función (x, y, z) con (2, 3) obtendrá un error en la llamada, en lugar de en el interior de la función), por lo general es más concisa , e incluso puede ser más eficiente.

Pero a veces hay razones apremiantes para el uso generalizado de *args.

Por ejemplo, si está envolviendo un módulo de nivel inferior (C o de otro modo) y desea un reenvío perfecto, es más fácil con *args. Aún más si está generando automáticamente el código del contenedor en lugar de escribirlo manualmente. Por supuesto, esto sigue siendo una solución de compromiso, es mucho más fácil para el desarrollador del módulo envoltorio, pero más difícil para los usuarios, pero a veces vale la pena el intercambio.

Sin conocer el paquete específico al que se refiere, es imposible adivinar si se trata de un caso de uso convincente o un abuso.

3

En el Zen of Python, se nos dice que preferimos explícitamente más que implícita. Los argumentos explícitos deben usarse siempre que sea posible.

+1

+1, citando del Zen. – nneonneo

+1

@nneonneo Citar del Zen sin más comentarios es bastante inútil. Las pautas en el Zen de Python son geniales, pero no solo porque están en el Zen de Python, son buenas ideas para * buenas razones *. Memorizar el Zen de Python sin * entender * los motivos de esas pautas (para que pueda reconocer al partir de ellas) no lo ayuda a aplicarlas bien. – Ben

+0

@Ben, no pensé que era mi lugar para especular sobre por qué ese artículo en particular está en el Zen. En este caso, pensé que era bastante obvio: explícito es más fácil de entender y seguir. También descubrí que trabajar con los mismos principios que guían a tu diseñador de plataforma simplemente mejora las cosas en general, no solo en Python. –

2

Si está ajustando una función desconocida (las funciones devueltas por los decoradores suelen hacerlo), a menudo necesita utilizar (*args, **kwargs).

Algunas jerarquías de clases usan (*args, **kwargs) en métodos que pueden necesitar diferentes firmas en diferentes clases en las jerarquías (__init__ es uno de los principales culpables). Es realmente útil si puede evitar eso, pero puede ser necesario trabajar con múltiples jerarquías de herencia de una manera sensata (o tan cuerdo como sea posible con herencia múltiple, al menos).

A veces termino usando **kwargs cuando tengo una gran cantidad de argumentos opcionales, pero esto requiere mucha documentación.

En una función que está consumiendo el *args en sí (en lugar de pasarlos a alguna otra función con una firma desconocida, como en los casos de decorador o herencia de clases), a continuación, tiendo a pensar que *args casi nunca deben usarse con excepción de significa "cero o más del mismo tipo de cosas". Y en ese caso debería nombrarlo *websites o *spaceships o *watermelons, no *args. Un grupo de parámetros no relacionados no debe aplastarse en *args. Lo peor sería que la función use *args para tomar "an x, a y, z, o bien una x y una z", donde el segundo parámetro hace cosas diferentes dependiendo de cuántos parámetros se pasan. En ese punto, todos deberían tener nombres y valores predeterminados (incluso si es solo el estándar None predeterminado, luego ver en la función cuáles no son None patrón) y se pasan por palabra clave en lugar de por posición.

Cuestiones relacionadas