¿Hay alguna manera de pasar parámetros opcionales a una función?

133

¿Hay alguna manera en Python para pasar parámetros opcionales a una función mientras la llama y en la definición de la función tiene algún código basado en "solo si se pasa el parámetro opcional"?

usuario1795998
fuente

Respuestas:

115

La documentación de Python 2, 7.6. Las definiciones de funciones le brindan un par de formas de detectar si una persona que llama proporcionó un parámetro opcional.

Primero, puede usar la sintaxis especial de parámetros formales *. Si la definición de la función tiene un parámetro formal precedido por un solo *, entonces Python llena ese parámetro con cualquier parámetro posicional que no coincida con los parámetros formales anteriores (como una tupla). Si la definición de la función tiene un parámetro formal precedido por** , entonces Python rellena ese parámetro con cualquier parámetro de palabra clave que no coincida con los parámetros formales anteriores (como un dict). La implementación de la función puede verificar el contenido de estos parámetros para cualquier "parámetro opcional" del tipo que desee.

Por ejemplo, aquí es una función opt_funque toma dos parámetros de posición x1y x2, y busca otro parámetro de palabra clave denominada "opcional".

>>> def opt_fun(x1, x2, *positional_parameters, **keyword_parameters):
...     if ('optional' in keyword_parameters):
...         print 'optional parameter found, it is ', keyword_parameters['optional']
...     else:
...         print 'no optional parameter, sorry'
... 
>>> opt_fun(1, 2)
no optional parameter, sorry
>>> opt_fun(1,2, optional="yes")
optional parameter found, it is  yes
>>> opt_fun(1,2, another="yes")
no optional parameter, sorry

En segundo lugar, puede proporcionar un valor de parámetro predeterminado de algún valor como None que una persona que llama nunca usaría. Si el parámetro tiene este valor predeterminado, sabe que la persona que llamó no especificó el parámetro. Si el parámetro tiene un valor no predeterminado, sabe que proviene del llamador.

Jim DeLaHunt
fuente
77
positional_parameterses una tupla y keyword_parametersun diccionario.
Cees Timmerman
¿Cómo distingue python formal parameters preceded by * (¿cómo se llama esto?) De a keyword parameter? Tal como lo entendí, los parámetros de palabras clave se especifican utilizando el =operador en la llamada a la función (por lo que opt_fun(1,2, optional="yes")proporciona un argumento de palabra clave "sí" para una función que anticipa, pero no necesariamente, el parámetro option).
Minh Tran
Por otro lado, entendí formal parameters preceded by * simplemente "los argumentos proporcionados por la persona que llama que no se corresponden con los argumentos posicionales que van antes que cualquier argumento de palabras clave". Por ejemplo, in opt_fun(1,2, "blah", 3.14, mykey="yes", myyear="2018"), "blah"y 3.14are forma arguments preceded by *porque está entre los dos argumentos posicionales y el argumento que usa el =signo. La tupla resultante positional_parametersería el binario: ("blah", 3.14). ¿Es esto correcto?
Minh Tran
@MinhTran, las preguntas en los comentarios no son la mejor manera de obtener una respuesta en Stack Overflow. Es mucho mejor hacer clic en el botón azul grande "Preguntar" y escribir su solicitud como "Pregunta" que otros pueden "Responder". Pero para ayudarlo, a) tenga en cuenta que escribí " parameter" no " parameters" para " preceded by *". El idioma permite solo uno *identifieren la lista de parámetros. b) lea docs.python.org/2/reference/… , c) lea docs.python.org/2/reference/expressions.html#calls . Lo sentimos, quedando sin caracteres permitidos en este comentario.
Jim DeLaHunt
81
def my_func(mandatory_arg, optional_arg=100):
    print(mandatory_arg, optional_arg)

http://docs.python.org/2/tutorial/controlflow.html#default-argument-values

Esto me parece más legible que usarlo **kwargs.

Para determinar si se pasó un argumento, utilizo un objeto de utilidad personalizado como valor predeterminado:

MISSING = object()

def func(arg=MISSING):
    if arg is MISSING:
        ...
warvariuc
fuente
-Gracias, ¿hay alguna manera de especificar el valor predeterminado de este parámetro como otra variable en el código?
usuario1795998
si. default_value=100; def my_func(mandatory_argument, optional_argument_with_default_value=default_value): ...
warvariuc
Esto parece mostrar cómo usar parámetros opcionales, pero no cómo probar si se pasa uno, que es lo que el OP está pidiendo.
Mawg dice que reinstalar a Monica el
44
En la mayoría de los casos, esta es la solución más simple y directa que la de Jim. Si establece el valor predeterminado en Ninguno, puede verificar si se pasó el parámetro o no. El único caso en el que la solución de Jim es mejor es si es importante distinguir entre pasar Ninguno como argumento y no pasar un argumento en absoluto.
Arnon Axelrod
19
def op(a=4,b=6):
    add = a+b
    print add

i)op() [o/p: will be (4+6)=10]
ii)op(99) [o/p: will be (99+6)=105]
iii)op(1,1) [o/p: will be (1+1)=2]
Note:
 If none or one parameter is passed the default passed parameter will be considered for the function. 
Sanyal
fuente
1
¿Hay alguna manera de pasar solo el segundo parámetro (b) y no el primero (a)?
Djidiouf
44
@Djidiouf Sí, hayop(b=2)
Jürg Merlin Spaak
7

Si desea dar un valor predeterminado a un parámetro, asigne un valor en (). como (x = 10). Pero lo importante es primero debe argumento obligatorio luego valor predeterminado.

p.ej.

(y, x = 10)

pero

(x = 10, y) está mal

sumitir
fuente
Gracias, ¿hay alguna manera de especificar el valor predeterminado de este parámetro como otra variable en el código?
user1795998
Sí, puede usar algo llamado *arg **kargcomo argumentos de función. buscar en Google.
sumitir
Esto parece mostrar cómo usar parámetros opcionales, pero no cómo probar si se pasa uno, que es lo que el OP está pidiendo.
Mawg dice que reinstalar a Monica el
2

Puede especificar un valor predeterminado para el argumento opcional con algo que nunca pasaría a la función y verificarlo con el isoperador:

class _NO_DEFAULT:
    def __repr__(self):return "<no default>"
_NO_DEFAULT = _NO_DEFAULT()

def func(optional= _NO_DEFAULT):
    if optional is _NO_DEFAULT:
        print("the optional argument was not passed")
    else:
        print("the optional argument was:",optional)

entonces, siempre que no lo haga func(_NO_DEFAULT), puede detectar con precisión si el argumento fue aprobado o no, y a diferencia de la respuesta aceptada, no tiene que preocuparse por los efectos secundarios de la notación **:

# these two work the same as using **
func()
func(optional=1)

# the optional argument can be positional or keyword unlike using **
func(1) 

#this correctly raises an error where as it would need to be explicitly checked when using **
func(invalid_arg=7)
Tadhg McDonald-Jensen
fuente
Solo hazlo _NO_DEFAULT = object().
Aran-Fey
Vale la pena 2 líneas adicionales para dar una mejor introspección. Con esto, si ejecuta help(func), obtiene una idea más clara de cómo se interpreta el argumento si no se pasa explícitamente.
Tadhg McDonald-Jensen