Python Language
Funciones
Buscar..
Introducción
Las funciones en Python proporcionan un código organizado, reutilizable y modular para realizar un conjunto de acciones específicas. Las funciones simplifican el proceso de codificación, evitan la lógica redundante y hacen que el código sea más fácil de seguir. Este tema describe la declaración y la utilización de funciones en Python.
Python tiene muchas funciones integradas como print()
, input()
, len()
. Además de las funciones integradas, también puede crear sus propias funciones para realizar trabajos más específicos, que se denominan funciones definidas por el usuario .
Sintaxis
- def function_name ( arg1, ... argN, * args, kw1, kw2 = predeterminado, ..., ** kwargs ): declaraciones
- lambda arg1, ... argN, * args, kw1, kw2 = predeterminado, ..., ** kwargs : expresión
Parámetros
Parámetro | Detalles |
---|---|
arg1 , ..., argN | Argumentos regulares |
* args | Argumentos posicionales sin nombre |
kw1 , ..., kwN | Argumentos solo de palabra clave |
** kwargs | El resto de argumentos de palabras clave. |
Observaciones
5 cosas básicas que puedes hacer con las funciones:
Asignar funciones a variables
def f(): print(20) y = f y() # Output: 20
Definir funciones dentro de otras funciones ( funciones anidadas )
def f(a, b, y): def inner_add(a, b): # inner_add is hidden from outer code return a + b return inner_add(a, b)**y
Las funciones pueden devolver otras funciones.
def f(y): def nth_power(x): return x ** y return nth_power # returns a function squareOf = f(2) # function that returns the square of a number cubeOf = f(3) # function that returns the cube of a number squareOf(3) # Output: 9 cubeOf(2) # Output: 8
Las funciones se pueden pasar como parámetros a otras funciones.
def a(x, y): print(x, y) def b(fun, str): # b has two arguments: a function and a string fun('Hello', str) b(a, 'Sophia') # Output: Hello Sophia
Las funciones internas tienen acceso al ámbito de cierre ( Cierre )
def outer_fun(name): def inner_fun(): # the variable name is available to the inner function return "Hello "+ name + "!" return inner_fun greet = outer_fun("Sophia") print(greet()) # Output: Hello Sophia!
Recursos adicionales
- Más sobre funciones y decoradores: https://www.thecodeship.com/patterns/guide-to-python-function-decorators/
Definiendo y llamando funciones simples.
Usar la instrucción def
es la forma más común de definir una función en python. Esta declaración es una declaración compuesta llamada cláusula única con la siguiente sintaxis:
def function_name(parameters):
statement(s)
function_name
se conoce como el identificador de la función. Dado que la definición de una función es una sentencia ejecutable, su ejecución vincula el nombre de la función con el objeto de la función que se puede llamar más adelante utilizando el identificador.
parameters
es una lista opcional de identificadores que se unen a los valores proporcionados como argumentos cuando se llama a la función. Una función puede tener un número arbitrario de argumentos separados por comas.
statement(s)
también conocidas como el cuerpo de la función ) son una secuencia no vacía de sentencias que se ejecutan cada vez que se llama a la función. Esto significa que el cuerpo de una función no puede estar vacío, como cualquier bloque con sangría .
Este es un ejemplo de una definición de función simple cuyo propósito es imprimir Hello
cada vez que se llama:
def greet():
print("Hello")
Ahora llamemos a la función de greet()
definida:
greet()
# Out: Hello
Ese es otro ejemplo de una definición de función que toma un solo argumento y muestra el valor pasado cada vez que se llama a la función:
def greet_two(greeting):
print(greeting)
Después de eso, la función greet_two()
debe llamarse con un argumento:
greet_two("Howdy")
# Out: Howdy
También puede dar un valor predeterminado a ese argumento de función:
def greet_two(greeting="Howdy"):
print(greeting)
Ahora puedes llamar a la función sin dar un valor:
greet_two()
# Out: Howdy
Notará que, a diferencia de muchos otros idiomas, no necesita declarar explícitamente un tipo de devolución de la función. Las funciones de Python pueden devolver valores de cualquier tipo a través de la palabra clave return
. ¡Una función puede devolver cualquier número de tipos diferentes!
def many_types(x):
if x < 0:
return "Hello!"
else:
return 0
print(many_types(1))
print(many_types(-1))
# Output:
0
Hello!
Mientras la persona que llama maneje esto correctamente, este es un código de Python perfectamente válido.
Una función que llega al final de la ejecución sin una declaración de retorno siempre devolverá None
:
def do_nothing():
pass
print(do_nothing())
# Out: None
Como se mencionó anteriormente, una definición de función debe tener un cuerpo de función, una secuencia de sentencias no vacía. Por lo tanto, la instrucción de pass
se utiliza como cuerpo de la función, que es una operación nula: cuando se ejecuta, no sucede nada. Hace lo que significa, salta. Es útil como marcador de posición cuando se requiere una declaración sintácticamente, pero no es necesario ejecutar ningún código.
Devolviendo valores desde funciones
Las funciones pueden return
un valor que puede utilizar directamente:
def give_me_five():
return 5
print(give_me_five()) # Print the returned value
# Out: 5
o guarda el valor para su uso posterior:
num = give_me_five()
print(num) # Print the saved returned value
# Out: 5
o use el valor para cualquier operación:
print(give_me_five() + 10)
# Out: 15
Si se encuentra return
en la función, la función se cerrará inmediatamente y las operaciones subsiguientes no se evaluarán:
def give_me_another_five():
return 5
print('This statement will not be printed. Ever.')
print(give_me_another_five())
# Out: 5
También puede return
varios valores (en forma de tupla):
def give_me_two_fives():
return 5, 5 # Returns two 5
first, second = give_me_two_fives()
print(first)
# Out: 5
print(second)
# Out: 5
Una función sin una declaración de return
devuelve implícitamente None
. De manera similar, una función con una declaración de return
, pero sin valor de retorno o variable devuelve None
.
Definiendo una función con argumentos.
Los argumentos se definen entre paréntesis después del nombre de la función:
def divide(dividend, divisor): # The names of the function and its arguments
# The arguments are available by name in the body of the function
print(dividend / divisor)
El nombre de la función y su lista de argumentos se denominan la firma de la función. Cada argumento nombrado es efectivamente una variable local de la función.
Al llamar a la función, dé valores para los argumentos enumerándolos en orden
divide(10, 2)
# output: 5
o especifíquelos en cualquier orden usando los nombres de la definición de función:
divide(divisor=2, dividend=10)
# output: 5
Definiendo una función con argumentos opcionales.
Los argumentos opcionales se pueden definir asignando (usando =
) un valor predeterminado al nombre de argumento:
def make(action='nothing'):
return action
Llamar a esta función es posible de 3 maneras diferentes:
make("fun")
# Out: fun
make(action="sleep")
# Out: sleep
# The argument is optional so the function will use the default value if the argument is
# not passed in.
make()
# Out: nothing
Advertencia
Los tipos mutables (
list
,dict
,set
, etc.) deben tratarse con cuidado cuando se dan como atributo predeterminado . Cualquier mutación del argumento por defecto lo cambiará permanentemente. Consulte Definir una función con argumentos mutables opcionales .
Definiendo una función con múltiples argumentos.
Uno puede dar a la función tantos argumentos como quiera, las únicas reglas fijas son que cada nombre de argumento debe ser único y que los argumentos opcionales deben estar después de los no opcionales:
def func(value1, value2, optionalvalue=10):
return '{0} {1} {2}'.format(value1, value2, optionalvalue1)
Al llamar a la función, puede dar cada palabra clave sin el nombre, pero el orden importa:
print(func(1, 'a', 100))
# Out: 1 a 100
print(func('abc', 14))
# abc 14 10
O combinar dando los argumentos con nombre y sin. Entonces los que tienen nombre deben seguir a los que no tienen, pero el orden de los que tienen nombre no importa:
print(func('This', optionalvalue='StackOverflow Documentation', value2='is'))
# Out: This is StackOverflow Documentation
Definiendo una función con un número arbitrario de argumentos.
Número arbitrario de argumentos posicionales:
La definición de una función capaz de tomar un número arbitrario de argumentos se puede hacer prefijando uno de los argumentos con un *
def func(*args):
# args will be a tuple containing all values that are passed in
for i in args:
print(i)
func(1, 2, 3) # Calling it with 3 arguments
# Out: 1
# 2
# 3
list_of_arg_values = [1, 2, 3]
func(*list_of_arg_values) # Calling it with list of values, * expands the list
# Out: 1
# 2
# 3
func() # Calling it without arguments
# No Output
No puede proporcionar un valor predeterminado para args
, por ejemplo func(*args=[1, 2, 3])
generará un error de sintaxis (ni siquiera compilará).
No puede proporcionarlos por nombre al llamar a la función, por ejemplo, func(*args=[1, 2, 3])
generará un TypeError
.
Pero si ya tiene sus argumentos en una matriz (o cualquier otro Iterable
), puede invocar su función así: func(*my_stuff)
.
Se puede acceder a estos argumentos ( *args
) por índice, por ejemplo, args[0]
devolverá el primer argumento
Número arbitrario de argumentos de palabras clave
Puede tomar un número arbitrario de argumentos con un nombre definiendo un argumento en la definición con dos *
delante:
def func(**kwargs):
# kwargs will be a dictionary containing the names as keys and the values as values
for name, value in kwargs.items():
print(name, value)
func(value1=1, value2=2, value3=3) # Calling it with 3 arguments
# Out: value1 1
# value2 2
# value3 3
func() # Calling it without arguments
# No Out put
my_dict = {'foo': 1, 'bar': 2}
func(**my_dict) # Calling it with a dictionary
# Out: foo 1
# bar 2
No puede proporcionarlos sin nombres, por ejemplo, func(1, 2, 3)
generará un TypeError
.
kwargs
es un simple diccionario nativo de python. Por ejemplo, args['value1']
dará el valor para el argumento value1
. Asegúrese de verificar de antemano que exista tal argumento o se KeyError
un KeyError
.
Advertencia
Puede combinar estos con otros argumentos opcionales y requeridos, pero el orden dentro de la definición es importante.
Los argumentos posicionales / palabras clave son lo primero. (Argumentos requeridos).
Luego vienen los argumentos arbitrarios *arg
. (Opcional).
Luego vienen los argumentos de palabra clave . (Necesario).
Finalmente la palabra clave arbitraria **kwargs
viene. (Opcional).
# |-positional-|-optional-|---keyword-only--|-optional-|
def func(arg1, arg2=10 , *args, kwarg1, kwarg2=2, **kwargs):
pass
-
arg1
debe darse, de lo contrario seTypeError
unTypeError
. Se puede dar como argumento posicional (func(10)
) o de palabra clave (func(arg1=10)
). -
kwarg1
debe proporcionarkwarg1
, pero solo se puede proporcionar como palabra clave-argumento:func(kwarg1=10)
. -
arg2
ykwarg2
son opcionales. Si se va a cambiar el valor, se aplican las mismas reglas que paraarg1
(posicional o palabra clave) ykwarg1
(solo palabra clave). -
*args
captura parámetros posicionales adicionales. Pero tenga en cuenta quearg1
yarg2
deben proporcionarse como argumentos posicionales para pasar argumentos a*args
:func(1, 1, 1, 1)
. -
**kwargs
captura todos los parámetros de palabras clave adicionales. En este caso, cualquier parámetro que no seaarg1
,arg2
,kwarg1
okwarg2
. Por ejemplo:func(kwarg3=10)
. - En Python 3, puede usar
*
solo para indicar que todos los argumentos posteriores deben especificarse como palabras clave. Por ejemplo, la funciónmath.isclose
en Python 3.5 y superior se define usandodef math.isclose (a, b, *, rel_tol=1e-09, abs_tol=0.0)
, lo que significa que los primeros dos argumentos se pueden suministrar de manera posicional pero el opcional Los parámetros tercero y cuarto solo se pueden suministrar como argumentos de palabras clave.
Python 2.x no admite parámetros de palabras clave solamente. Este comportamiento puede ser emulado con kwargs
:
def func(arg1, arg2=10, **kwargs):
try:
kwarg1 = kwargs.pop("kwarg1")
except KeyError:
raise TypeError("missing required keyword-only argument: 'kwarg1'")
kwarg2 = kwargs.pop("kwarg2", 2)
# function body ...
Nota sobre nombrar
La convención de nombrar argumentos opcionales posicionales args
y opcionales de palabras clave kwargs
es solo una convención que puede usar cualquier nombre que desee, pero es útil seguir la convención para que otros sepan lo que está haciendo, o incluso usted mismo más adelante, así que hágalo.
Nota sobre la singularidad
Cualquier función se puede definir con ninguno o un *args
y ninguno o uno **kwargs
pero no con más de uno de cada uno. También *args
debe ser el último argumento posicional y **kwargs
debe ser el último parámetro. El intento de utilizar más de uno de ambos dará lugar a una excepción de error de sintaxis.
Nota sobre funciones de anidamiento con argumentos opcionales
Es posible anidar dichas funciones y la convención habitual es eliminar los elementos que el código ya ha manejado, pero si está pasando los parámetros, debe pasar argumentos opcionales posicionales con un prefijo *
y argumentos de palabras clave opcionales con un prefijo **
, de lo contrario, los argumentos se pueden pasar como una lista o tupla y los kwargs como un solo diccionario. p.ej:
def fn(**kwargs):
print(kwargs)
f1(**kwargs)
def f1(**kwargs):
print(len(kwargs))
fn(a=1, b=2)
# Out:
# {'a': 1, 'b': 2}
# 2
Definiendo una función con argumentos mutables opcionales.
Existe un problema cuando se usan argumentos opcionales con un tipo predeterminado mutable (descrito en Definición de una función con argumentos opcionales ), lo que puede conducir a un comportamiento inesperado.
Explicación
Este problema surge porque los argumentos predeterminados de una función se inicializan una vez , en el momento en que se define la función y no (como en muchos otros idiomas) cuando se llama a la función. Los valores predeterminados se almacenan dentro de la variable miembro __defaults__
del objeto de __defaults__
.
def f(a, b=42, c=[]):
pass
print(f.__defaults__)
# Out: (42, [])
Para los tipos inmutables (ver Pasar argumento y mutabilidad ) esto no es un problema porque no hay manera de mutar la variable; solo se puede reasignar, sin cambiar el valor original. Por lo tanto, se garantiza que los subsiguientes tengan el mismo valor predeterminado. Sin embargo, para un tipo mutable , el valor original puede mutar, haciendo llamadas a sus diversas funciones miembro. Por lo tanto, no se garantiza que las llamadas sucesivas a la función tengan el valor predeterminado inicial.
def append(elem, to=[]):
to.append(elem) # This call to append() mutates the default variable "to"
return to
append(1)
# Out: [1]
append(2) # Appends it to the internally stored list
# Out: [1, 2]
append(3, []) # Using a new created list gives the expected result
# Out: [3]
# Calling it again without argument will append to the internally stored list again
append(4)
# Out: [1, 2, 4]
Nota: Algunos IDE como PyCharm emitirán una advertencia cuando se especifique un tipo mutable como atributo predeterminado.
Solución
Si desea asegurarse de que el argumento predeterminado sea siempre el que especifique en la definición de la función, entonces la solución es usar siempre un tipo inmutable como su argumento predeterminado.
Un modismo común para lograr esto cuando se necesita un tipo mutable como predeterminado, es utilizar None
(inmutable) como argumento predeterminado y luego asignar el valor predeterminado real a la variable de argumento si es igual a None
.
def append(elem, to=None):
if to is None:
to = []
to.append(elem)
return to
Funciones Lambda (Inline / Anónimo)
La palabra clave lambda
crea una función en línea que contiene una sola expresión. El valor de esta expresión es lo que la función devuelve cuando se invoca.
Considere la función:
def greeting():
return "Hello"
el cual, cuando es llamado como:
print(greeting())
huellas dactilares:
Hello
Esto se puede escribir como una función lambda de la siguiente manera:
greet_me = lambda: "Hello"
Vea la nota al final de esta sección con respecto a la asignación de lambdas a las variables. En general, no lo hagas.
Esto crea una función en línea con el nombre greet_me
que devuelve Hello
. Tenga en cuenta que no escribe return
cuando crea una función con lambda. El valor después de :
se devuelve automáticamente.
Una vez asignada a una variable, se puede usar como una función regular:
print(greet_me())
huellas dactilares:
Hello
lambda
s puede tomar argumentos, también:
strip_and_upper_case = lambda s: s.strip().upper()
strip_and_upper_case(" Hello ")
devuelve la cadena:
HELLO
También pueden tomar un número arbitrario de argumentos / argumentos de palabras clave, como las funciones normales.
greeting = lambda x, *args, **kwargs: print(x, args, kwargs)
greeting('hello', 'world', world='world')
huellas dactilares:
hello ('world',) {'world': 'world'}
lambda
se usan comúnmente para funciones cortas que son convenientes para definir en el punto donde se llaman (típicamente con sorted
, filter
y map
).
Por ejemplo, esta línea ordena una lista de cadenas que ignoran su caso e ignoran los espacios en blanco al principio y al final:
sorted( [" foo ", " bAR", "BaZ "], key=lambda s: s.strip().upper())
# Out:
# [' bAR', 'BaZ ', ' foo ']
Ordenar la lista simplemente ignorando espacios en blanco:
sorted( [" foo ", " bAR", "BaZ "], key=lambda s: s.strip())
# Out:
# ['BaZ ', ' bAR', ' foo ']
Ejemplos con map
:
sorted( map( lambda s: s.strip().upper(), [" foo ", " bAR", "BaZ "]))
# Out:
# ['BAR', 'BAZ', 'FOO']
sorted( map( lambda s: s.strip(), [" foo ", " bAR", "BaZ "]))
# Out:
# ['BaZ', 'bAR', 'foo']
Ejemplos con listas numéricas:
my_list = [3, -4, -2, 5, 1, 7]
sorted( my_list, key=lambda x: abs(x))
# Out:
# [1, -2, 3, -4, 5, 7]
list( filter( lambda x: x>0, my_list))
# Out:
# [3, 5, 1, 7]
list( map( lambda x: abs(x), my_list))
# Out:
[3, 4, 2, 5, 1, 7]
Uno puede llamar a otras funciones (con / sin argumentos) desde dentro de una función lambda.
def foo(msg):
print(msg)
greet = lambda x = "hello world": foo(x)
greet()
huellas dactilares:
hello world
Esto es útil porque lambda
puede contener solo una expresión y al usar una función subsidiaria se pueden ejecutar varias declaraciones.
NOTA
Tenga en cuenta que PEP-8 (la guía de estilo oficial de Python) no recomienda asignar lambdas a las variables (como hicimos en los dos primeros ejemplos):
Siempre use una instrucción def en lugar de una instrucción de asignación que vincule una expresión lambda directamente a un identificador.
Sí:
def f(x): return 2*x
No:
f = lambda x: 2*x
La primera forma significa que el nombre del objeto de función resultante es específicamente
f
lugar del genérico<lambda>
. Esto es más útil para las trazas y representaciones de cadenas en general. El uso de la declaración de asignación elimina el único beneficio que puede ofrecer una expresión lambda sobre una declaración explícita dedef
(es decir, que se puede incrustar dentro de una expresión más grande).
Argumento de paso y mutabilidad.
Primero, alguna terminología:
- argumento (parámetro real ): la variable real que se pasa a una función;
- parámetro (parámetro formal ): la variable de recepción que se utiliza en una función.
En Python, los argumentos se pasan por asignación (a diferencia de otros idiomas, donde los argumentos pueden pasarse por valor / referencia / puntero).
Mutar un parámetro mutará el argumento (si el tipo del argumento es mutable).
def foo(x): # here x is the parameter x[0] = 9 # This mutates the list labelled by both x and y print(x) y = [4, 5, 6] foo(y) # call foo with y as argument # Out: [9, 5, 6] # list labelled by x has been mutated print(y) # Out: [9, 5, 6] # list labelled by y has been mutated too
Reasignar el parámetro no reasignará el argumento.
def foo(x): # here x is the parameter, when we call foo(y) we assign y to x x[0] = 9 # This mutates the list labelled by both x and y x = [1, 2, 3] # x is now labeling a different list (y is unaffected) x[2] = 8 # This mutates x's list, not y's list y = [4, 5, 6] # y is the argument, x is the parameter foo(y) # Pretend that we wrote "x = y", then go to line 1 y # Out: [9, 5, 6]
En Python, realmente no asignamos valores a las variables, en lugar de eso, vinculamos (es decir, asignamos, adjuntamos) variables (consideradas como nombres ) a los objetos.
- Inmutable: enteros, cadenas, tuplas, etc. Todas las operaciones hacen copias.
- Mutable: listas, diccionarios, conjuntos, etc. Las operaciones pueden o no mutar.
x = [3, 1, 9]
y = x
x.append(5) # Mutates the list labelled by x and y, both x and y are bound to [3, 1, 9]
x.sort() # Mutates the list labelled by x and y (in-place sorting)
x = x + [4] # Does not mutate the list (makes a copy for x only, not y)
z = x # z is x ([1, 3, 9, 4])
x += [6] # Mutates the list labelled by both x and z (uses the extend function).
x = sorted(x) # Does not mutate the list (makes a copy for x only).
x
# Out: [1, 3, 4, 5, 6, 9]
y
# Out: [1, 3, 5, 9]
z
# Out: [1, 3, 5, 9, 4, 6]
Cierre
Los cierres en Python son creados por llamadas a funciones. Aquí, la llamada a makeInc
crea un enlace para x
que se hace referencia dentro de la función inc
. Cada llamada a makeInc
crea una nueva instancia de esta función, pero cada instancia tiene un enlace a un enlace diferente de x
.
def makeInc(x):
def inc(y):
# x is "attached" in the definition of inc
return y + x
return inc
incOne = makeInc(1)
incFive = makeInc(5)
incOne(5) # returns 6
incFive(5) # returns 10
Observe que, mientras que en un cierre regular, la función encerrada hereda completamente todas las variables de su entorno envolvente, en esta construcción, la función encerrada solo tiene acceso de lectura a las variables heredadas, pero no puede asignárselas.
def makeInc(x):
def inc(y):
# incrementing x is not allowed
x += y
return x
return inc
incOne = makeInc(1)
incOne(5) # UnboundLocalError: local variable 'x' referenced before assignment
Python 3 ofrece la declaración no nonlocal
( variables no locales ) para realizar un cierre completo con funciones anidadas.
def makeInc(x):
def inc(y):
nonlocal x
# now assigning a value to x is allowed
x += y
return x
return inc
incOne = makeInc(1)
incOne(5) # returns 6
Funciones recursivas
Una función recursiva es una función que se llama a sí misma en su definición. Por ejemplo, la función matemática, factorial, definida por factorial(n) = n*(n-1)*(n-2)*...*3*2*1
. se puede programar como
def factorial(n):
#n here should be an integer
if n == 0:
return 1
else:
return n*factorial(n-1)
Las salidas aquí son:
factorial(0)
#out 1
factorial(1)
#out 1
factorial(2)
#out 2
factorial(3)
#out 6
como se esperaba. Observe que esta función es recursiva porque el segundo return factorial(n-1)
, donde la función se llama a sí mismo en su definición.
Algunas funciones recursivas pueden implementarse usando lambda , la función factorial que usa lambda sería algo como esto:
factorial = lambda n: 1 if n == 0 else n*factorial(n-1)
La función produce la misma salida que la anterior.
Límite de recursión
Hay un límite a la profundidad de la posible recursión, que depende de la implementación de Python. Cuando se alcanza el límite, se genera una excepción RuntimeError:
def cursing(depth):
try:
cursing(depth + 1) # actually, re-cursing
except RuntimeError as RE:
print('I recursed {} times!'.format(depth))
cursing(0)
# Out: I recursed 1083 times!
Es posible cambiar el límite de profundidad de recursión usando sys.setrecursionlimit(limit)
y verificar este límite por sys.getrecursionlimit()
.
sys.setrecursionlimit(2000)
cursing(0)
# Out: I recursed 1997 times!
Desde Python 3.5, la excepción es un RecursionError
, que se deriva de RuntimeError
.
Funciones anidadas
Las funciones en python son objetos de primera clase. Se pueden definir en cualquier ámbito.
def fibonacci(n):
def step(a,b):
return b, a+b
a, b = 0, 1
for i in range(n):
a, b = step(a, b)
return a
Las funciones que capturan su ámbito de distribución pueden transmitirse como cualquier otro tipo de objeto
def make_adder(n):
def adder(x):
return n + x
return adder
add5 = make_adder(5)
add6 = make_adder(6)
add5(10)
#Out: 15
add6(10)
#Out: 16
def repeatedly_apply(func, n, x):
for i in range(n):
x = func(x)
return x
repeatedly_apply(add5, 5, 1)
#Out: 26
Iterable y desempaquetado del diccionario.
Las funciones le permiten especificar estos tipos de parámetros: posicionales, nombrados, variables posicionales, Argumentos de palabras clave (kwargs). Aquí hay un uso claro y conciso de cada tipo.
def unpacking(a, b, c=45, d=60, *args, **kwargs):
print(a, b, c, d, args, kwargs)
>>> unpacking(1, 2)
1 2 45 60 () {}
>>> unpacking(1, 2, 3, 4)
1 2 3 4 () {}
>>> unpacking(1, 2, c=3, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, c=3)
1 2 3 4 () {}
>>> pair = (3,)
>>> unpacking(1, 2, *pair, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, *pair)
1 2 3 4 () {}
>>> unpacking(1, 2, *pair, c=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> unpacking(1, 2, c=3, *pair)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> args_list = [3]
>>> unpacking(1, 2, *args_list, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, *args_list)
1 2 3 4 () {}
>>> unpacking(1, 2, c=3, *args_list)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> unpacking(1, 2, *args_list, c=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> pair = (3, 4)
>>> unpacking(1, 2, *pair)
1 2 3 4 () {}
>>> unpacking(1, 2, 3, 4, *pair)
1 2 3 4 (3, 4) {}
>>> unpacking(1, 2, d=4, *pair)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, *pair, d=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> args_list = [3, 4]
>>> unpacking(1, 2, *args_list)
1 2 3 4 () {}
>>> unpacking(1, 2, 3, 4, *args_list)
1 2 3 4 (3, 4) {}
>>> unpacking(1, 2, d=4, *args_list)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, *args_list, d=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> arg_dict = {'c':3, 'd':4}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {}
>>> arg_dict = {'d':4, 'c':3}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {}
>>> arg_dict = {'c':3, 'd':4, 'not_a_parameter': 75}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {'not_a_parameter': 75}
>>> unpacking(1, 2, *pair, **arg_dict)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, 3, 4, **arg_dict)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
# Positional arguments take priority over any other form of argument passing
>>> unpacking(1, 2, **arg_dict, c=3)
1 2 3 4 () {'not_a_parameter': 75}
>>> unpacking(1, 2, 3, **arg_dict, c=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
Forzando el uso de parámetros nombrados
Todos los parámetros especificados después del primer asterisco en la firma de función son solo palabras clave.
def f(*a, b):
pass
f(1, 2, 3)
# TypeError: f() missing 1 required keyword-only argument: 'b'
En Python 3 es posible poner un solo asterisco en la firma de la función para garantizar que los argumentos restantes solo puedan pasarse utilizando argumentos de palabras clave.
def f(a, b, *, c):
pass
f(1, 2, 3)
# TypeError: f() takes 2 positional arguments but 3 were given
f(1, 2, c=3)
# No error
Lambda recursiva utilizando variable asignada
Un método para crear funciones lambda recursivas implica asignar la función a una variable y luego hacer referencia a esa variable dentro de la misma función. Un ejemplo común de esto es el cálculo recursivo del factorial de un número, como se muestra en el siguiente código:
lambda_factorial = lambda i:1 if i==0 else i*lambda_factorial(i-1)
print(lambda_factorial(4)) # 4 * 3 * 2 * 1 = 12 * 2 = 24
Descripción del código
A la función lambda, a través de su asignación variable, se le pasa un valor (4) que evalúa y devuelve 1 si es 0 o, de lo contrario, devuelve el valor actual ( i
) * otro cálculo realizado por la función lambda del valor - 1 ( i-1
). Esto continúa hasta que el valor pasado se reduce a 0 ( return 1
). Un proceso que se puede visualizar como: