¿Alguna razón para NO usar siempre argumentos de palabras clave?

Antes de saltar a python, comencé con algunos libros de Objective-C / Cocoa. Como recuerdo, la mayoría de las funciones requieren que los argumentos de las palabras clave estén explícitamente establecidos. Hasta hace poco olvidé todo esto, y solo usé argumentos posicionales en Python. Pero últimamente, me he topado con algunos errores que resultaron de posiciones impropias, pequeñas cosas disimuladas que eran.

Me hizo pensar, en general, a menos que exista una circunstancia que requiera específicamente argumentos que no sean de palabras clave, ¿hay alguna buena razón para NO usar argumentos de palabras clave? ¿Se considera un estilo malo usarlos siempre, incluso para funciones simples?

Siento que como la mayoría de mis progtwigs de 50 líneas se han escalado a 500 o más líneas regularmente, si me acostumbro a usar siempre argumentos de palabras clave, el código será más fácil de leer y mantener a medida que crezca. ¿Alguna razón por la que esto no sea así?

ACTUALIZAR:

La impresión general que estoy obteniendo es que es una preferencia de estilo, con muchos argumentos buenos que generalmente no deberían usarse para argumentos muy simples, pero que por lo demás son consistentes con un buen estilo. Sin embargo, antes de aceptar, solo quiero aclarar: ¿hay algún problema específico que no sea de estilo que surja de este método, por ejemplo, impactos significativos en el rendimiento?

No hay ninguna razón para no usar argumentos de palabras clave aparte de la claridad y legibilidad del código. La elección de usar palabras clave debe basarse en si la palabra clave agrega información útil adicional al leer el código o no.

Sigo la siguiente regla general:

  1. Si es difícil inferir la función (nombre) del argumento del nombre de la función, text.splitlines(True) por palabra clave (por ejemplo, no querría tener text.splitlines(True) en mi código).
  2. Si es difícil inferir el orden de los argumentos, por ejemplo, si tiene demasiados argumentos, o cuando tiene argumentos opcionales independientes, funkyplot(x, y, None, None, None, None, None, None, 'red') por palabra clave (por ejemplo, funkyplot(x, y, None, None, None, None, None, None, 'red') no parece particularmente agradable).
  3. Nunca pase los primeros argumentos por palabra clave si el propósito del argumento es obvio. Verás, sin(2*pi) es mejor que sin(value=2*pi) , lo mismo es cierto para la plot(x, y, z) .

En la mayoría de los casos, los argumentos obligatorios estables serían posicionales, y los argumentos opcionales serían palabras clave.

También hay una posible diferencia en el rendimiento, porque en cada implementación los argumentos de las palabras clave serían un poco más lentos, pero considerando que esto sería generalmente una optimización prematura y los resultados no serían significativos, no creo que sea crucial para la decisión .

ACTUALIZACIÓN: Preocupaciones no estilísticas.

Los argumentos de palabras clave pueden hacer todo lo que los argumentos posicionales pueden hacer, y si está definiendo una nueva API, no hay desventajas técnicas aparte de posibles problemas de rendimiento. Sin embargo, es posible que tenga pequeños problemas si combina su código con elementos existentes.

Considera lo siguiente:

  • Si hace que su función tome argumentos de palabras clave, eso se convierte en parte de su interfaz. No puede reemplazar su función con otra que tenga una firma similar pero una palabra clave diferente para el mismo argumento.
  • Es posible que desee utilizar un decorador u otra utilidad en su función que asum que su función toma un argumento posicional. Los métodos sin límites son un ejemplo de dicha utilidad porque siempre pasan el primer argumento como posicional después de leerlo como posicional, por lo que cls.method(self=cls_instance) no funciona incluso si hay un self en la definición.

Ninguno de estos sería un problema real si diseña bien su API y documenta el uso de argumentos de palabras clave, especialmente si no está diseñando algo que debería ser intercambiable con algo que ya existe.

Si su consideración es mejorar la legibilidad de las llamadas a funciones, ¿por qué no simplemente declarar las funciones como normales, por ejemplo?

 def test(x, y): print "x:", x print "y:", y 

Y simplemente llame a las funciones declarando los nombres explícitamente, así:

 test(y=4, x=1) 

Lo que obviamente te da la salida:

 x: 1 y: 4 

o este ejercicio sería inútil.

Esto evita que los argumentos sean opcionales y que necesiten valores predeterminados (a menos que desee que lo sean, en cuyo caso, ¡siga adelante con los argumentos de palabras clave! 🙂 y le ofrece toda la versatilidad y legibilidad mejorada de los argumentos con nombre que no están limitados por orden.

Bueno, hay algunas razones por las que no haría eso.

Si todos sus argumentos son argumentos de palabras clave, aumenta el ruido en el código y podría eliminar la claridad sobre qué argumentos son necesarios y cuáles son opcionales.

Además, si tengo que usar tu código, ¡tal vez quiera matarte! (Solo bromeo), pero tener que escribir el nombre de todos los parámetros cada vez … no es tan divertido.

Recuerdo haber leído una muy buena explicación de “opciones” en los progtwigs UNIX: “Las opciones son opcionales, un progtwig debería poder ejecutarse sin ninguna opción”.

El mismo principio podría aplicarse a los argumentos de palabras clave en Python. Este tipo de argumentos debería permitir que un usuario “personalice” la llamada a la función, pero una función debería poder llamarse sin ningún par de argumentos implícitos de palabra clave-valor.

Solo para ofrecer un argumento diferente, creo que hay algunos casos en los que los parámetros nombrados pueden mejorar la legibilidad. Por ejemplo, imagine una función que crea un usuario en su sistema:

 create_user("George", "Martin", "gm@example.com", "payments@example.com", "1", "Radius Circle") 

A partir de esa definición, no está del todo claro qué significan estos valores, aunque todos son necesarios, sin embargo, con los parámetros con nombre siempre es obvio:

 create_user( first_name="George", last_name="Martin", contact_email="gm@example.com", billing_email="payments@example.com", street_number="1", street_name="Radius Circle") 

A veces, las cosas deben ser simples porque son simples.

Si siempre le obliga a usar argumentos de palabras clave en cada llamada a una función, pronto su código será ilegible.

Cuando las funciones compile() e __import__() integradas de Python obtienen apoyo de argumentos de palabras clave , se hizo el mismo argumento en favor de la claridad. No parece haber un impacto significativo en el rendimiento, si lo hay.

Ahora, si hace que sus funciones solo acepten argumentos de palabras clave (en lugar de pasar los parámetros posicionales utilizando palabras clave al llamarlas, lo que está permitido), entonces sí, sería molesto.

No veo el propósito de usar argumentos de palabras clave cuando el significado de los argumentos es obvio

Los argumentos de palabras clave son buenos cuando tienes listas de parámetros largas sin un orden bien definido (que no puedes crear fácilmente con un esquema claro); sin embargo, hay muchas situaciones en las que su uso es excesivo o hace que el progtwig sea menos claro.

En primer lugar, a veces es mucho más fácil recordar el orden de las palabras clave que los nombres de los argumentos de palabras clave, y especificar los nombres de los argumentos podría hacerlo menos claro. Toma randint de scipy.random con la siguiente cadena de documentación:

 randint(low, high=None, size=None) Return random integers x such that low <= x < high. If high is None, then 0 <= x < low. 

Al querer generar un int aleatorio de [0,10) es más claro escribir randint(10) que randint(low=10) en mi opinión. Si necesita generar una matriz con 100 números en [0,10), probablemente pueda recordar el orden de los argumentos y escribir randint(0, 10, 100) . Sin embargo, es posible que no recuerde los nombres de las variables (por ejemplo, es el primer parámetro low, lower, start, min, minimum) y una vez que tenga que buscar los nombres de los parámetros, es mejor que no los use (como acaba de buscar) el orden correcto).

También considere las funciones variables (aquellas con un número variable de parámetros que son anónimos). Por ejemplo, es posible que desee escribir algo como:

 def square_sum(*params): sq_sum = 0 for p in params: sq_sum += p*p return sq_sum 

que se puede aplicar un montón de parámetros pelados ( square_sum(1,2,3,4,5) # gives 55 ). Seguro que podrías haber escrito la función para tomar una palabra clave nombrada iterable def square_sum(params): y la square_sum([1,2,3,4,5]) como square_sum([1,2,3,4,5]) pero eso puede ser menos intuitivo, especialmente cuando no hay una posible confusión sobre el nombre del argumento o su contenido.

Un inconveniente que pude ver es que tendría que pensar en un valor predeterminado razonable para todo, y en muchos casos es posible que no haya ningún valor predeterminado razonable (incluido None ). Entonces se sentiría obligado a escribir una gran cantidad de códigos de manejo de errores para los casos en que un kwarg que lógicamente debería ser un argumento posicional no se especificó.

Imagina escribir cosas como esta cada vez ..

 def logarithm(x=None): if x is None: raise TypeError("You can't do log(None), sorry!") 

Un error que a menudo hago es olvidar que los argumentos posicionales deben especificarse antes que los argumentos de palabras clave, al llamar a una función. Si la testing es una función, entonces:

 testing(arg = 20, 56) 

da un mensaje SyntaxError ; algo como:

 SyntaxError: non-keyword arg after keyword arg 

Es fácil de arreglar, por supuesto, es simplemente molesto. Por lo tanto, en el caso de progtwigs de pocas líneas como los que mencionas, es probable que simplemente vaya con argumentos posicionales después de dar nombres descriptivos a los parámetros de la función. Sin embargo, no sé si lo que menciono es un problema tan grande.