Funciones y sus argumentos. Valores de retorno de una función. declaración de devolución

Hay una gran cantidad de publicaciones dedicadas a la implementación de conceptos de programación funcional en Python, pero la mayoría de estos materiales están escritos por un autor: David Mertz. Además, muchos de estos artículos ya están desactualizados y se encuentran dispersos en varios recursos en línea. En este artículo intentaremos volver a visitar este tema para actualizar y organizar la información disponible, especialmente dadas las grandes diferencias que existen entre las versiones de la línea 2 y 3 de Python.

Funciones en Python

Las funciones en Python se definen de 2 maneras: mediante definición definición o mediante descripción anónima lambda. Ambos métodos de definición están disponibles, en distintos grados, en algunos otros lenguajes de programación. La peculiaridad de Python es que una función es un objeto con nombre, como cualquier otro objeto de algún tipo de datos, por ejemplo, como una variable entera. El Listado 1 muestra el ejemplo más simple (archivo func.py del archivo python_funcional.tgz

Listado 1. Definiciones de funciones
#!/usr/bin/python # -*- codificación: utf-8 -*- import sys def show(fun, arg): print("() : ()".format(type(fun), fun)) print("arg=() => fun(arg)=()".format(arg, fun(arg))) si len(sys.argv) > 1: n = float(sys.argv[ 1 ]) else : n = float(input("¿número?: ")) def pow3(n): # 1.ª definición de función return n * n * n show(pow3, n) pow3 = lambda n: n * n * n # 2 -th definición de una función con el mismo nombre show(pow3, n) show((lambda n: n * n * n), n) # 3.º, uso de la definición de función anónima

Cuando llamamos a los tres objetos de función, obtendremos el mismo resultado:

$ Python func.py 1.3 : arg=1.3 => diversión(arg)=2.197 : en 0xb7662bc4> arg=1.3 => diversión(arg)=2.197 : en 0xb7662844> arg=1.3 => diversión(arg)=2.197

Esto es aún más pronunciado en la versión 3 de Python, en la que todo es una clase (incluida una variable entera) y las funciones son objetos de programa que pertenecen a una clase. función:

$python3 func.py 1.3 : arg=1.3 => diversión(arg)=2.19700000000000005 : en 0xb745432c> arg=1.3 => diversión(arg)=2.1970000000000005 : en 0xb74542ec> arg=1.3 => diversión(arg)=2.1970000000000005

Nota. Hay 2 tipos más de objetos que permiten una llamada a una función: un método de clase funcional y un funtor, de los que hablaremos más adelante.

Si los objetos de función de Python son objetos como otros objetos de datos, entonces puedes hacer con ellos todo lo que puedes hacer con cualquier dato:

  • dinamicamente cambiar en curso;
  • integrar en estructuras de datos más complejas (colecciones);
  • pasar como parámetros y valores de retorno, etc.

En esto (manipulación con objetos funcionales como objetos de datos) es en lo que se basa la programación funcional. Python, por supuesto, no es un lenguaje de programación funcional real; por ejemplo, existen lenguajes especiales para una programación completamente funcional: Lisp, Planner y otros más recientes: Scala, Haskell. Ocaml, ... Pero en Python puede "incrustar" técnicas de programación funcional en el flujo general de código imperativo (comando), por ejemplo, utilizar métodos tomados de lenguajes funcionales completos. Aquellos. “doblar” fragmentos individuales de código imperativo (a veces bastante grandes) en expresiones funcionales.

A veces la gente pregunta: "¿Cuáles son las ventajas del estilo funcional de escribir fragmentos individuales para un programador?" La principal ventaja de la programación funcional es que después de depurar dicho fragmento una vez, el uso repetido posterior no causará errores debido a efectos secundarios asociados con asignaciones y conflictos de nombres.

Muy a menudo, cuando se programa en Python, se utilizan construcciones típicas del campo de la programación funcional, por ejemplo:

print ([ (x,y) para x en (1, 2, 3, 4, 5) \ para y en (20, 15, 10) \ si x * y > 25 y x + y< 25 ])

Como resultado de la ejecución obtenemos:

$ python funcp.py [(2,20), (2,15), (3,20), (3,15), (3,10), (4,20), (4,15), (4 ,10), (5,15), (5,10)]

Funciones como objetos

Al crear un objeto de función con un operador lambda, como se muestra en el Listado 1, puede vincular el objeto de función creado al nombre pow3 exactamente de la misma manera que se podría adjuntar un número a este nombre 123 o cuerda "¡Hola!". Este ejemplo confirma el estado de las funciones como objetos de primera clase en Python. Una función en Python es simplemente otro valor con el que puedes hacer algo.

La acción más común realizada con objetos de función de primera clase es pasarlos a funciones integradas de orden superior: mapa(), reducir() Y filtrar(). Cada una de estas funciones toma un objeto de función como primer argumento.

  • mapa() aplica la función pasada a cada elemento de la(s) lista(s) pasada(s) y devuelve una lista de resultados (la misma dimensión que la entrada);
  • reducir() aplica la función pasada a cada valor de la lista y al acumulador de resultados interno, p.e. reducir(lambda n,m: n * m, rango(1, 10)) medio 10! (factorial);
  • filtrar() aplica la función pasada a cada elemento de la lista y devuelve una lista de aquellos elementos de la lista original para los cuales la función pasada devolvió verdadero.

Al combinar estas tres funciones, puede implementar una gama sorprendentemente amplia de operaciones de flujo de control sin recurrir a declaraciones imperativas, sino utilizando sólo expresiones de estilo funcional, como se muestra en el Listado 2 (archivo funcH.py del archivo python_funcional.tgz

Listado 2. Funciones de orden superior de Python
#!/usr/bin/python # -*- codificación: utf-8 -*- import sys def input_arg(): global arg arg = (lambda: (len(sys.argv) > 1 and int(sys.argv[ 1 ])) o \ int(input("¿número?: ")))() return arg print("argumento = ()".format(input_arg())) print(list(map(lambda x: x + 1 , range(arg))) print(list(filter(lambda x: x > 4, range(arg)))) import functools print("()! = ()".format(arg, functools.reduce(lambda x , y: x * y, rango(1, arg))))

Nota. Este código es ligeramente más complejo que el ejemplo anterior debido a los siguientes problemas de compatibilidad entre las versiones 2 y 3 de Python:

  • Función reducir(), declarado como integrado en Python 2, se movió a un módulo en Python 3 herramientas funcionales y llamarlo directamente por su nombre generará una excepción NombreError, por lo que para que funcione correctamente la llamada debe tener el formato como en el ejemplo o incluir la línea: desde functools importar *
  • Funciones mapa() Y filtrar() en Python 3 no devuelven una lista (como ya se mostró cuando se discutieron las diferencias de versión), sino objetos iteradores de la forma:

Para obtener la lista completa de valores para ellos, se llama a la función lista().

Por tanto, este código podrá funcionar en ambas versiones de Python:

$python3 funcH.py 7 argumento = 7 7! = 720

Si no se requiere la portabilidad del código entre diferentes versiones, entonces se pueden excluir dichos fragmentos, lo que permitirá simplificar un poco el código.

recursividad

En programación funcional, la recursividad es un mecanismo fundamental, similar a los bucles en la programación iterativa.

En algunas discusiones sobre Python, me he encontrado repetidamente con afirmaciones de que en Python la profundidad de la recursividad está limitada por el "hardware" y, por lo tanto, algunas acciones no se pueden implementar en principio. Python tiene un límite de profundidad de recursividad predeterminado de 1000, pero esta es una configuración numérica que siempre se puede anular, como se muestra en el Listado 3 (para ver el código de ejemplo completo, consulte el archivo hecho2.py del archivo python_funcional.tgz

Listado 3. Calcular factorial con profundidad de recursividad arbitraria
#!/usr/bin/python # -*- codificación: utf-8 -*- import sys arg = lambda: (len(sys.argv) > 1 and int(sys.argv[ 1 ])) o \ int( input("¿número?: ")) factorial = lambda x: ((x == 1) y 1) o x * factorial(x - 1) n = arg() m = sys.getrecursionlimit() si n >= m - 1: sys.setrecursionlimit(n + 2) print("la profundidad de la recursión excede la establecida en el sistema (), restablecer a ()".\ format(m, sys.getrecursionlimit())) print("n=( ) => n!=()".format(n, factorial(n))) if sys.getrecursionlimit() > m: print("profundidad de recursión restaurada a ()".format(m)) sys.setrecursionlimit(m )

Así es como se ve la ejecución de este ejemplo en Python 3 y Python2 (aunque en realidad es poco probable que el número resultante quepa en una pantalla de terminal de consola):

$ python3 fact2.py 1001 la profundidad de recursividad excede la configuración del sistema 1000, se restablece a 1003 n=1001 => n!=4027......................... ........................0000000000000 profundidad de recursividad restaurada a 1000

Algunos ejemplos simples

Realicemos varias transformaciones simples del código imperativo habitual (comando, operador) para transformar sus fragmentos individuales en funcionales. Primero, reemplacemos los operadores de bifurcación con condiciones lógicas que, debido a cálculos "diferidos" (perezosos, perezosos), nos permiten controlar la ejecución o no ejecución de ramas de código individuales. Así, la construcción imperativa:

si<условие>: <выражение 1>demás:<выражение 2>

Completamente equivalente al siguiente fragmento funcional (debido a las capacidades "diferidas" de los operadores lógicos y Y o):

# función sin parámetros: lambda: (<условие>y<выражение 1>) o (<выражение 2>)

Usemos nuevamente el cálculo factorial como ejemplo. El Listado 4 muestra el código funcional para calcular el factorial (archivo hecho1.py en el archivo python_funcional.tgz en la sección "Descargar materiales"):

Listado 4. Definición del operador (imperativo) de factorial
#!/usr/bin/python # -*- codificación: utf-8 -*- import sys def factorial(n): si n == 1: devuelve 1 más: devuelve n * factorial(n - 1) si len( sys.argv) > 1: n = int(sys.argv[ 1 ]) else: n = int(input("¿número?: ")) print("n=() => n!=()".formato (n, factorial(n)))

El argumento a calcular se toma del valor del parámetro de la línea de comando (si está presente) o se ingresa desde la terminal. El primer cambio mostrado arriba ya se aplicó en el Listado 2, donde las expresiones de función se reemplazaron con:

  • Definición de la función factorial: factorial = lambda x: ((x == 1) y 1) o x * factorial(x - 1)
  • Solicitud para ingresar un valor de argumento desde la consola del terminal: arg = lambda: (len(sys.argv) > 1 y int(sys.argv[ 1 ])) o \ int(input("¿número?: ")) n = arg()

en archivo hecho3.py Aparece otra definición de función, hecha a través de una función de orden superior. reducir():

factorial = factorial = lambda z: reducir(lambda x, y: x * y, rango(1, z + 1))

Aquí también simplificaremos la expresión para norte, reduciéndolo a una única llamada a una función anónima (sin nombre):

n = (lambda: (len(sys.argv) > 1 y int(sys.argv[ 1 ])) o \ int(input("¿número?: ")))()

Finalmente, puedes notar que asignar un valor a una variable norte requerido sólo para su uso en una llamada imprimir() para generar este valor. Si abandonamos esta restricción, entonces toda la aplicación degenerará en un operador funcional (ver archivo fact4.py en el archivo python_funcional.tgz en la sección "Descargar materiales"):

from sys import * from functools import reduce print("factorial calculado = ()".format(\ (lambda z: reduce(lambda x, y: x * y, range(1, z + 1))) \ ((lambda : (len(argv) > 1 y int(argv[ 1 ])) o \ int(input("¿número?: ")))())))

Esta única llamada dentro de una función. imprimir() y representa la aplicación completa en su forma funcional:

$python3 fact4.py número?: 5 factorial calculado = 120

¿Este código (archivo fact4.py) se lee mejor que la notación imperativa (archivo fact1.py)? Es más probable que no que sí. ¿Cuál es entonces su mérito? El hecho es que cuando cualquier cambios en el código circundante, funcionamiento normal este El fragmento se conservará, ya que no existe riesgo de efectos secundarios por cambios en los valores de las variables utilizadas.

Funciones de orden superior

En un estilo de programación funcional, la práctica estándar es generación dinámica un objeto funcional durante la ejecución del código, con su posterior llamada en el mismo código. Hay varias áreas en las que una técnica como ésta podría resultar útil.

Cierre

Uno de los conceptos interesantes de la programación funcional es cierres(cierre). Esta idea resultó tan tentadora para muchos desarrolladores que incluso se implementó en algunos lenguajes de programación no funcionales (Perl). David Mertz da la siguiente definición de cierre: "Un cierre es un procedimiento junto con un conjunto de datos vinculados a él" (a diferencia de los objetos en la programación de objetos, como: "datos junto con un conjunto de procedimientos vinculados a él") .

El significado de un cierre es que la definición de una función "congela" el contexto circundante para momento de determinación. Esto se puede hacer de varias maneras, por ejemplo parametrizando la creación de la función, como se muestra en el Listado 5 (archivo cierre1.py en el archivo python_funcional.tgz en la sección "Descargar materiales"):

Listado 5. Creando un cierre
# -*- codificación: utf-8 -*- def multiplicador(n): # multiplicador devuelve una función que multiplica por n def mul(k): return n * k return mul mul3 = multiplicador(3) # mul3 es una función que se multiplica por 3 print(mul3(3), mul3(5))

Así es como funciona una función definida dinámicamente:

$ python clos1.py (9, 15) $ python3 clos1.py 9 15

Otra forma de crear un cierre es utilizar el valor del parámetro predeterminado en el punto de definición de la función, como se muestra en el Listado 6 (archivo cierre3.py del archivo python_funcional.tgz en la sección "Descargar materiales"):

Listado 6. Otra forma de crear un cierre
n = 3 def mult(k, mul = n): return mul * k n = 7 print(mult(3)) n = 13 print(mult(5)) n = 10 mult = lambda k, mul=n: mul * k imprimir(multi(3))

Ninguna asignación posterior al parámetro predeterminado cambiará la función definida previamente, pero la función en sí se puede anular:

$ python clos3.py 9 15 30

Aplicación de función parcial

La aplicación de función parcial asume según la función. norte Definición de variables de una nueva función con menos variables. METRO < norte, mientras que el resto NUEVO MÉJICO las variables reciben valores fijos "congelados" (el módulo se utiliza herramientas funcionales). Un ejemplo similar se discutirá a continuación.

Funtor

Un funtor no es una función, sino un objeto de clase en el que se llama un método. __llamar__(). En este caso, se puede aplicar una llamada a una instancia de dicho objeto, tal como ocurre con las funciones. En el Listado 7 (archivo parte.py del archivo python_funcional.tgz(consulte la sección Descargas) demuestra cómo utilizar un cierre, una definición de función parcial y un funtor para producir el mismo resultado.

Listado 7. Comparación de cierre, definición parcial y functor
# -*- codificación: utf-8 -*- def multiplicador(n): # cierre def mul(k): retorno n * k retorno mul mul3 = multiplicador(3) de functools importar def parcial mulPart(a, b): # aplicación parcial de la función return a * b par3 = parcial(mulPart, 3) class mulFunctor: # functor equivalente def __init__(self, val1): self.val1 = val1 def __call__(self, val2): return self.val1 * val2 fun3 = mulFunctor(3) print("() . () . ()".format(mul3(5), par3(5), fun3(5)))

Llamar a las tres construcciones para un argumento igual a 5 producirá el mismo resultado, aunque utilizarán mecanismos completamente diferentes:

$ python part.py 15. 15. 15

karring

Curring (o currying) es la transformación de una función de muchas variables en una función que toma sus argumentos uno a la vez.

Nota. Esta transformación fue introducida por M. Sheinfinkel y G. Frege y lleva el nombre del matemático Haskell Curry, de quien también lleva el nombre el lenguaje de programación Haskell.

Curring no es una característica única de la programación funcional; una transformación de curry se puede escribir, por ejemplo, en Perl o C++. El operador curry incluso está integrado en algunos lenguajes de programación (ML, Haskell), lo que permite que funciones de múltiples lugares den como resultado una representación curry. Pero todos los lenguajes que admiten cierres le permiten escribir funciones al curry, y Python no es una excepción en este sentido.

El Listado 8 muestra un ejemplo simple usando curry (archivo curry1.py en el archivo python_funcional.tgz en la sección "Descargar materiales"):

Listado 8. Curado
# -*- codificación: utf-8 -*- def spam(x, y): print("param1=(), param2=()".format(x, y)) spam1 = lambda x: lambda y: spam (x, y) def spam2(x) : def nuevo_spam(y) : devolver spam(x, y) devolver nuevo_spam spam1(2)(3) # curar spam2(2)(3)

Así es como se ve la ejecución de estas llamadas:

$ python curry1.py parámetro1=2, parámetro2=3 parámetro1=2, parámetro2=3

Conclusión

Este artículo presentó algunas de las características del lenguaje Python que le permiten usarlo para escribir programas usando el estilo de programación funcional. Entonces, describimos las técnicas básicas de programación funcional y mostramos ejemplos de su implementación en Python. Como en artículos anteriores, los ejemplos de código están escritos de tal manera que se puedan ejecutar con éxito en ambas versiones de Python.

En el próximo artículo discutiremos las cuestiones de organizar la ejecución paralela de código en el entorno Python.

Una función es un bloque de código aislado que está diseñado para realizar una tarea específica y puede reutilizarse. Las funciones hacen que el código del programa sea modular y más compacto.

Python ofrece muchas funciones integradas. Probablemente estés familiarizado con estos:

  • print() imprime el objeto en la terminal.
  • int() convierte cadenas o números en números enteros.
  • len() devuelve la longitud del objeto.

El nombre de la función contiene paréntesis y puede contener parámetros.

Este tutorial le enseñará cómo definir funciones personalizadas.

Definición de función

Primero, intente convertir un programa sencillo de "¡Hola, mundo!". en una función.

Cree un nuevo archivo de texto hello.py y luego defina una función.

Para definir una función, use la palabra clave def, luego especifique el nombre de la función y los paréntesis que pueden contener parámetros (si no hay parámetros, los paréntesis permanecen vacíos), seguido de dos puntos.

Para definir la función hello(), agregue lo siguiente a su archivo hello.py:

Esta es la definición original de la función.

definición hola():
print("¡Hola mundo!")

La función ahora está definida. Pero si ejecuta el programa en esta etapa, no sucederá nada: para que la función funcione, no solo debe definirse, sino también llamarse.

Después de definir una función, llámala:

definición hola():
print("¡Hola mundo!")
Hola()

Ahora ejecuta el programa:

Debería devolver:

La función hola() es un ejemplo bastante simple. Las funciones pueden ser mucho más complejas y contener bucles for, expresiones condicionales y otros componentes.

Cuando la función llega a la declaración de devolución, deja de ejecutarse.

# Archivo return_loop.py
def bucle_cinco():
para x en el rango (0, 25):
imprimir(x)
si x == 5:
# Detener la función en x == 5
devolver
print("Esta línea no se ejecutará.")
bucle_cinco()

La declaración de retorno en un bucle for deja de ejecutar la función, por lo que las líneas posteriores a la función no se ejecutarán. Si en su lugar se hubiera utilizado una instrucción break, el programa habría dejado de ejecutar el bucle en lugar de la función, y se habría procesado la última instrucción print().

función principal()

En Python, se puede llamar a una función al final de un programa y se ejecutará (como se muestra en los ejemplos anteriores), pero algunos lenguajes de programación (como C++ o Java) requieren una función principal. La función main() en Python es opcional, pero le permite estructurar lógicamente su programa Python y combinar sus componentes más importantes en una sola función. También hace que los programas Python sean más fáciles de leer para los programadores que trabajan en otros lenguajes.

Regrese al archivo hello.py y agregue la función main(), manteniendo la función hello().

definición hola():
print("¡Hola mundo!")
definición principal():

Agregue una declaración print() a la función main(). Luego llame a la función hola() dentro de la función principal().

definición hola():
print("¡Hola mundo!")
definición principal():
print("Esta es la función principal")
Hola()

Al final del archivo, llame a la función main().

definición hola():
print("¡Hola mundo!")
definición principal():
print("Esta es la función principal.")
Hola()
principal()

Ahora puedes ejecutar el programa:

python hola.py
Esta es la función principal.
¡Hola Mundo!

Ahora intenta usar varias funciones.

Recuerde que en matemáticas el factorial de un número n se define como n! = 1 ⋅ 2 ⋅ ... ⋅ norte. Por ejemplo, ¡5! = 1 ⋅ 2 ⋅ 3 ⋅ 4 ⋅ 5 = 120. Está claro que el factorial se puede calcular fácilmente usando un bucle for. Imaginemos que necesitamos calcular el factorial de diferentes números varias veces en nuestro programa (o en diferentes lugares del código). Por supuesto, puedes escribir el cálculo factorial una vez y luego usar Copiar y Pegar para pegarlo donde lo necesites.

# ¡Calculemos 3! res = 1 para i en el rango (1, 4): res *= i print(res) # ¡calcula 5! res = 1 para i en el rango(1, 6): res *= i print(res)

Sin embargo, si cometemos un error una vez en el código inicial, este error aparecerá en el código en todos los lugares donde copiamos el cálculo del factorial. Y, en general, el código ocupa más espacio del que podría. Para evitar escribir la misma lógica una y otra vez, los lenguajes de programación tienen funciones.

Las funciones son secciones de código que están aisladas del resto del programa y se ejecutan sólo cuando se llaman. Ya has visto las funciones sqrt(), len() y print(). Todos tienen una propiedad común: pueden tomar parámetros (cero, uno o más) y pueden devolver un valor (aunque es posible que no). Por ejemplo, la función sqrt() toma un parámetro y devuelve un valor (la raíz de un número). La función print() toma un número variable de parámetros y no devuelve nada.

Vamos a mostrar cómo escribir una función factorial() que toma un parámetro (un número) y devuelve un valor (el factorial de este número).

Def factorial(n): res = 1 para i en el rango(1, n + 1): res *= i devuelve res print(factorial(3)) print(factorial(5))

Demos algunas explicaciones. Primero, el código de la función debe colocarse al principio del programa, o mejor dicho, antes del lugar donde queremos usar la función factorial(). La primera línea de este ejemplo es una descripción de nuestra función. factorial es un identificador, es decir, el nombre de nuestra función. Después del identificador entre paréntesis hay una lista de parámetros que recibe nuestra función. La lista consta de identificadores de parámetros separados por comas. En nuestro caso, la lista consta de un valor n. Se colocan dos puntos al final de la línea.

Luego viene el cuerpo de la función, diseñado como un bloque, es decir, con sangría. Dentro de la función, el valor factorial de n se calcula y se almacena en la variable res. La función finaliza con la declaración return res, que finaliza la función y devuelve el valor de la variable res.

La instrucción de retorno puede aparecer en cualquier lugar de una función; su ejecución finaliza la función y devuelve el valor especificado al lugar donde fue llamada. Si la función no devuelve un valor, entonces la declaración de devolución se utiliza sin un valor de retorno. Es posible que las funciones que no necesitan devolver un valor no tengan una declaración de devolución.

Pongamos otro ejemplo. Escribamos una función max() que tome dos números y devuelva el máximo de ellos (de hecho, dicha función ya está integrada en Python).

10 20 def max(a, b): si a > b: devuelve a else: devuelve b print(max(3, 5)) print(max(5, 3)) print(max(int(input()), int(entrada())))

Ahora podemos escribir una función max3() que tome tres números y devuelva el máximo de ellos.

def max(a, b): si a > b: devuelve a else: devuelve b def max3(a, b, c): devuelve max(max(a, b), c) print(max3(3, 5, 4) ))

La función max() incorporada de Python puede tomar un número variable de argumentos y devolver el máximo de ellos. Demos un ejemplo de cómo se puede escribir una función de este tipo.

Def max(*a): res = a para val en a: si val > res: res = val return res print(max(3, 5, 4))

Todos los parámetros pasados ​​a esta función se recopilarán en una tupla denominada a, como lo indica el asterisco en la línea de declaración de la función.

2. Variables locales y globales

Puede utilizar variables dentro de una función que se declaran fuera de la función.

Def f(): imprimir(a) a = 1 f()

Aquí a la variable a se le asigna el valor 1, y la función f() imprime este valor, aunque la variable no se inicializa antes de declarar f. Cuando se llama a f(), a ya tiene asignado un valor, por lo que f() puede mostrarlo en la pantalla.

Estas variables (declaradas fuera de la función, pero accesibles dentro de la función) se llaman global.

Pero si inicializa una variable dentro de una función, no podrá usar esta variable fuera de la función. Por ejemplo:

Def f(): a = 1 f() imprimir(a)

Recibimos el error NameError: el nombre "a" no está definido. Estas variables declaradas dentro de una función se llaman local. Estas variables dejan de estar disponibles después de que sale la función.

El resultado será interesante si intentas cambiar el valor de una variable global dentro de una función:

Def f(): a = 1 imprimir(a) a = 0 f() imprimir(a)

Se imprimirán los números 1 y 0. Aunque el valor de la variable a ha cambiado dentro de la función, ¡fuera de la función permanece igual! Esto se hace para "proteger" las variables globales de cambios accidentales de la función. Por ejemplo, si se llama a una función desde un bucle usando la variable i, y en esta función la variable i también se usará para organizar el bucle, entonces estas variables deben ser diferentes. Si no comprende la última oración, eche un vistazo al siguiente código y piense cómo funcionaría si la variable i se cambiara dentro de la función.

Def factorial(n): res = 1 para i en el rango(1, n + 1): res *= devuelvo res para i en el rango(1, 6): print(i, "! = ", factorial(i) , septiembre="")

Si la variable global i se cambiara dentro de la función, obtendríamos esto:

5! = 1 5! = 2 5! = 6 5! = 24 5! = 120

Entonces, si el valor de alguna variable se modifica dentro de una función, entonces la variable con ese nombre se convierte en una variable local, y su modificación no cambiará la variable global con el mismo nombre.

Más formalmente: el intérprete de Python considera una variable local para una función determinada; si su código contiene al menos una instrucción que modifica el valor de la variable, entonces esta variable se considera local y no se puede utilizar antes de la inicialización. Las instrucciones que modifican el valor de una variable son los operadores = , += , además de utilizar la variable como parámetro de un bucle for. Además, incluso si la instrucción que modifica la variable nunca se ejecuta, el intérprete no puede verificar esto y la variable aún se considera local. Ejemplo:

Def f(): imprimir(a) si es falso: a = 0 a = 1 f()

Se produce un error: UnboundLocalError: variable local "a" a la que se hace referencia antes de la asignación. Es decir, en la función f() el identificador a se convierte en una variable local, porque la función contiene un comando que modifica la variable a , incluso si nunca se ejecuta (pero el intérprete no puede rastrear esto). Por lo tanto, imprimir la variable a da como resultado el acceso a una variable local no inicializada.

Para que una función cambie el valor de una variable global, es necesario declarar esta variable dentro de la función como global usando la palabra clave global:

Def f(): global a a = 1 imprimir(a) a = 0 f() imprimir(a)

En este ejemplo, se mostrará 1 1 en la pantalla, ya que la variable a está declarada como global y cambiarla dentro de la función conducirá al hecho de que la variable estará disponible fuera de la función.

Sin embargo, es mejor no cambiar los valores de las variables globales dentro de una función. Si su función debe cambiar alguna variable, sería mejor si devolviera este valor y usted mismo asignara explícitamente este valor a la variable al llamar a la función. Si sigues estas reglas, las funciones son independientes del código y se pueden copiar fácilmente de un programa a otro.

Por ejemplo, digamos que su programa necesita calcular el factorial de un número de entrada, que luego desea almacenar en la variable f. así es como es no vale la pena hacer:

5 def factorial(n): global f res = 1 para i in range(2, n + 1): res *= i f = res n = int(input()) factorial(n) # acciones adicionales con la variable f

Este código está mal escrito porque es difícil volver a usarlo. Si mañana necesita usar la función factorial en otro programa, no puede simplemente copiar esta función desde aquí y pegarla en su nuevo programa. Tendrás que cambiar la forma en que devuelve el valor calculado.

Es mucho mejor reescribir este ejemplo así:

5 # el comienzo de un fragmento de código que se puede copiar de un programa a otro def factorial(n): res = 1 for i in range(2, n + 1): res *= i return res # el final de un fragmento del código n = int(input( )) f = factorial(n) # además todo tipo de acciones con la variable f

Si necesita que una función devuelva no un valor, sino dos o más, entonces, para este propósito, la función puede devolver una lista de dos o más valores:

Entonces el resultado de la llamada a la función se puede utilizar en asignaciones múltiples:

3. recursividad

Def short_story(): print("El sacerdote tenía un perro, la amaba.") print("Ella comió un trozo de carne, él la mató") print("Lo enterró en la tierra y escribió la inscripción: ") historia_corta()

Como vimos arriba, una función puede llamar a otra función. ¡Pero una función también puede llamarse a sí misma! Veamos esto usando la función de cálculo factorial como ejemplo. Es bien sabido que 0!=1, 1!=1. ¡Cómo calcular el valor de n! para n grande? Si pudiéramos calcular el valor (n-1)!, entonces podemos calcular fácilmente n!, ya que n!=n⋅(n-1)!. ¿Pero cómo calcular (n-1)? Si calculamos (n-2)!, entonces también podemos calcular (n-1)!=(n-1)⋅(n-2)!. ¿Cómo calcular (n-2)? Si... Eventualmente llegaremos al valor 0!, que es igual a 1. Entonces, para calcular el factorial, podemos usar el valor del factorial del número menor. Esto también se puede hacer en un programa Python:

Def factorial(n): si n == 0: devuelve 1 en caso contrario: devuelve n * factorial(n - 1) print(factorial(5))

Esta técnica (una función que se llama a sí misma) se llama recursividad y la función en sí se llama recursiva.

Las funciones recursivas son un mecanismo poderoso en la programación. Desafortunadamente, no siempre son efectivos. Además, el uso de la recursividad suele provocar errores. El más común de estos errores es la recursividad infinita, donde una cadena de llamadas a funciones nunca termina y continúa hasta que la computadora se queda sin memoria libre. En el epígrafe de esta sección se da un ejemplo de recursividad infinita. Las dos razones más comunes para la recursividad infinita son:

  1. Salida incorrecta de la recursividad. Por ejemplo, si nos olvidamos de verificar si n == 0 en el programa de cálculo factorial, entonces factorial(0) llamará a factorial(-1), el cual llamará a factorial(-2), etc.
  2. Llamada recursiva con parámetros no válidos. Por ejemplo, si la función factorial(n) llama a factorial(n) , también dará como resultado una cadena infinita.

Por lo tanto, al desarrollar una función recursiva, primero debe formalizar las condiciones para la terminación de la recursividad y pensar por qué la recursividad terminará alguna vez.

Última actualización: 11/04/2018

Las funciones representan un bloque de código que realiza una tarea específica y que puede reutilizarse en otras partes del programa. Definición formal de una función:

def nombre_función ([parámetros]): instrucciones

La definición de una función comienza con una expresión def, que consta del nombre de la función, un conjunto de paréntesis con parámetros y dos puntos. Los parámetros entre paréntesis son opcionales. Y desde la siguiente línea hay un bloque de instrucciones que ejecuta la función. Todas las instrucciones de función tienen sangría desde el principio de la línea.

Por ejemplo, la definición de la función más simple:

Def decir_hola(): imprimir("Hola")

La función se llama decir_hola. No tiene parámetros y contiene una sola instrucción, que imprime la cadena "Hola" en la consola.

Para llamar a una función, especifique el nombre de la función, seguido de la transmisión de valores para todos sus parámetros entre paréntesis. Por ejemplo:

Def decir_hola(): imprimir("Hola") decir_hola() decir_hola() decir_hola()

Aquí la función say_hello se llama tres veces seguidas. Como resultado, recibiremos el siguiente resultado de consola:

hola hola hola

Ahora definamos y usemos una función con parámetros:

Def decir_hola(nombre): print("Hola,",nombre) decir_hola("Tom") decir_hola("Bob") decir_hola("Alice")

La función toma un parámetro de nombre y al llamar a la función podemos pasar un valor en lugar de un parámetro:

Hola, Tom Hola, Bob Hola, Alice

Valores predeterminados

Podemos hacer que algunos parámetros de función sean opcionales especificando valores predeterminados para ellos al definir la función. Por ejemplo:

Def decir_hola(nombre="Tom"): print("Hola", nombre) decir_hola() decir_hola("Bob")

Aquí el parámetro de nombre es opcional. Y si no le pasamos un valor al llamar a la función, entonces se aplica el valor predeterminado, es decir, la cadena "Tom".

Parámetros con nombre

Cuando se pasan valores, la función los relaciona con los parámetros en el orden en que se pasan. Por ejemplo, tengamos la siguiente función:

Def display_info(nombre, edad): print("Nombre:", nombre, "\t", "Edad:", edad) display_info("Tom", 22)

Al llamar a la función, el primer valor "Tom" se pasa al primer parámetro (el parámetro de nombre), el segundo valor (el número 22) se pasa al segundo parámetro: la edad. Y así sucesivamente en orden. El uso de parámetros con nombre le permite anular el orden de aprobación:

Def display_info(nombre, edad): print("Nombre:", nombre, "\t", "Edad:", edad) display_info(edad=22, nombre="Tom")

Los parámetros con nombre requieren especificar un nombre de parámetro y asignarle un valor al llamar a una función.

Número de parámetros no especificado

El símbolo de asterisco se puede utilizar para definir un número indefinido de parámetros:

Def suma(*params): resultado = 0 para n en params: resultado += n devuelve resultado sumaDeNúmeros1 = suma(1, 2, 3, 4, 5) # 15 sumaDeNúmeros2 = suma(3, 4, 5, 6) # 18 imprimir(sumaDeNúmeros1) imprimir(sumaDeNúmeros2)

En este caso, la función de suma toma un parámetro: *params, pero el asterisco antes del nombre del parámetro indica que, de hecho, en lugar de este parámetro podemos pasar un número indefinido de valores o un conjunto de valores. En la función misma, usando el bucle for, puede revisar este conjunto y realizar varias acciones con los valores pasados. Por ejemplo, en este caso se devuelve la suma de números.

Devolviendo el resultado

Una función puede devolver un resultado. Para hacer esto, la función usa la declaración de retorno, seguida del valor de retorno:

Def intercambio(usd_rate, dinero): resultado = ronda(dinero/usd_rate, 2) devuelve resultado resultado1 = intercambio(60, 30000) print(resultado1) resultado2 = intercambio(56, 30000) print(resultado2) resultado3 = intercambio(65, 30000) imprimir (resultado3)

Dado que la función devuelve un valor, podemos asignar este valor a alguna variable y luego usarlo: resultado2 = intercambio(56, 30000).

En Python, una función puede devolver varios valores a la vez:

Def create_default_user(): nombre = "Tom" edad = 33 return nombre, edad nombre_usuario, edad_usuario = create_default_user() print("Nombre:", nombre_usuario, "\t Edad:", edad_usuario)

Aquí la función create_default_user devuelve dos valores: nombre y edad. Cuando se llama a la función, estos valores se asignan en orden a las variables nombre_usuario y edad_usuario, y podemos usarlos.

función principal

Un programa puede definir muchas funciones. Y para poder organizarlas todas, es una buena práctica agregar una función principal especial, en la que luego se llaman otras funciones:

def main(): say_hello("Tom") usd_rate = 56 dinero = 30000 resultado = exchange(usd_rate, dinero) print("Para emitir", resultado, "dólares") def say_hello(nombre): print("Hola," , nombre) def exchange(usd_rate, dinero): resultado = round(money/usd_rate, 2) devolver resultado # Llamar a main main()

Cuando comencé a escribir el capítulo sobre programación orientada a objetos, me di cuenta de que me había olvidado por completo de cubrir una sección tan grande y necesaria de Python como las funciones. Este tema es amplio y extenso, así que para no alargar demasiado la pausa entre lecciones, decidí dividirlo en 2 partes. Primero, le contaré los conceptos básicos y luego las características detalladas de la ingeniería de funciones de Python.

Las funciones en Python no se declaran de forma sencilla, sino muy sencilla. A continuación se muestra un ejemplo del más sencillo:

def función_vacía(): pasar
La declaración comienza con la palabra clave def, que, como se puede imaginar, es una abreviatura de definir. Le sigue el nombre de la función. Después del nombre, entre paréntesis, se especifica una lista de parámetros que en este caso faltan.
El cuerpo de la función tiene sangría desde la línea siguiente. Tenga en cuenta que las funciones con un cuerpo vacío están prohibidas en Python, por lo que el pase "operador vacío" se utiliza como cuerpo de la función anterior.
Ahora veamos un ejemplo más serio.

Def safe_div(x, y): """Haz una división segura:-) para divertirte y obtener ganancias""" if y != 0: z = x / y print z return z else: print "Yippie-kay-yay, ¡hijo de puta!"
Hay varias innovaciones en este ejemplo. Lo primero que llama la atención es la línea de documentación (cadena de documentos) que viene inmediatamente después del cuerpo de la función.
Por lo general, esta línea ocupa más de una línea del texto fuente (perdón por el juego de palabras) y, por lo tanto, se especifica entre comillas triples. Se pretende describir la función, su finalidad, parámetros, etc. Todos los buenos IDE pueden funcionar con esta línea. También puedes acceder a él desde el propio programa, utilizando la propiedad __doc__:

Imprimir safe_div.__doc__
Esta propiedad (sí, sí, exactamente una propiedad, en Python incluso las funciones son en realidad clases) es conveniente de usar durante las sesiones de la consola interactiva.
>>> desde ftplib import FTP >>> print FTP.__doc__ Una clase de cliente FTP.
Para crear una conexión, llame a la clase usando estos argumentos: host, usuario, contraseña, cuenta. Todas estas son cadenas y tienen el valor predeterminado "".
Luego use self.connect() con el argumento opcional de host y puerto. # el resto lo hago yo :-)

Volvamos a nuestra función original. Su esencia es muy simple, se necesitan 2 parámetros: xey. Si y no es 0, divide x entre y, imprime el resultado en la pantalla y devuelve su cociente como resultado. El resultado de la función se devuelve mediante el comando de retorno. Gracias al mecanismo de tupla descrito en la última lección, las funciones en Python pueden devolver muchos objetos al mismo tiempo.

Si el divisor sigue siendo cero, la función muestra un mensaje de error. Sería un error suponer que en este caso la función no devolverá nada. Sería más correcto decir que la función devolverá "nada" :) En otras palabras, si la función no tiene una declaración de retorno o se llama sin parámetros, entonces la función devuelve el valor especial Ninguno. Puedes verificar esto fácilmente llamando a algo como print safe_div(10, 0).
Aquí hay un ejemplo un poco más complicado, tomado de un informe de presentación de Guido van Rossum.

En general, tenga en cuenta que los parámetros de las funciones de Python se pasan por referencia. Otro hecho, quizás no trivial, al que tendrás que acostumbrarte es el hecho de que las funciones en sí son un valor que se puede asignar. Si utilizamos nuestra función safe_div para más experimentos, podemos escribir el siguiente código.

Función_mística = div_seguro imprimir función_mística(10, 4)
Eso es todo por ahora, todavía quedan muchos aspectos de la definición de funciones en Python "por la borda" que se cubrirán la próxima vez.

Ejercicios para la prueba.
1. Basado en la función existente para encontrar el MCM, escribe una función para encontrar el MCM de dos números.
2. Escriba una rutina de tabulación para la función pasada como argumento. Los argumentos también especifican el valor inicial, final y el paso de tabulación.

PD: por cierto, ¿cuál es la duración óptima de una “lección”? ¿Qué es mejor: capítulos grandes publicados con menos frecuencia o “menos es mejor y más a menudo”?




Arriba