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

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 se TypeError un TypeError . Se puede dar como argumento posicional ( func(10) ) o de palabra clave ( func(arg1=10) ).
  • kwarg1 debe proporcionar kwarg1 , pero solo se puede proporcionar como palabra clave-argumento: func(kwarg1=10) .
  • arg2 y kwarg2 son opcionales. Si se va a cambiar el valor, se aplican las mismas reglas que para arg1 (posicional o palabra clave) y kwarg1 (solo palabra clave).
  • *args captura parámetros posicionales adicionales. Pero tenga en cuenta que arg1 y arg2 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 sea arg1 , arg2 , kwarg1 o kwarg2 . 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ón math.isclose en Python 3.5 y superior se define usando def 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 de def (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.

Python 3.x 3.0
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:

recursive_lambda_path



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow