Valores de Retorno y Ámbito de las Funciones en Python

PythonBeginner
Practicar Ahora

Introducción

En este laboratorio, profundizarás en tu comprensión de las funciones en Python explorando sus valores de retorno y el concepto de ámbito (scope) de las variables. Comenzarás examinando funciones que no devuelven explícitamente un valor, observando cómo ejecutan acciones sin producir un resultado que pueda ser utilizado en otro lugar.

Posteriormente, aprenderás a añadir valores de retorno a las funciones, permitiéndoles producir una salida que puede ser capturada y utilizada en tus programas. Luego, el laboratorio te guiará a través de la diferenciación entre variables locales y globales, entendiendo sus respectivos ámbitos y cómo afectan la accesibilidad de las variables dentro y fuera de las funciones. También aprenderás a modificar variables globales desde dentro de las funciones utilizando la palabra clave global y explorarás el concepto de variables nonlocal en funciones anidadas.

Explorar Funciones Sin Valores de Retorno

En este paso, exploraremos funciones que no tienen una declaración explícita de return. Estas funciones realizan una acción, como imprimir en la consola, pero no envían un valor de vuelta a la parte del código que las llamó.

Primero, localiza el archivo no_return_function.py en el explorador de archivos del lado izquierdo del WebIDE. Haz doble clic en él para abrirlo en el editor.

Añade el siguiente código al archivo no_return_function.py:

def greet():
    print("Hello, welcome to the world of functions!")

## Call the function
greet()

Para ejecutar este script, abre la terminal integrada haciendo clic en Terminal > New Terminal en el menú superior. Luego, ejecuta el siguiente comando:

python ~/project/no_return_function.py

Verás la salida de la función impresa en la consola:

Hello, welcome to the world of functions!

La función greet() ejecuta la instrucción print(), pero no produce un valor que pueda almacenarse en una variable. Para ver qué sucede cuando intentas capturar el resultado, modifica el archivo no_return_function.py. Reemplaza el contenido existente con el siguiente código:

def greet():
    print("Hello, welcome to the world of functions!")

## Call the function and assign its result to a variable
result = greet()

## Print the value of the result
print(f"The result of calling greet() is: {result}")

Guarda el archivo y ejecútalo de nuevo desde la terminal:

python ~/project/no_return_function.py

La salida será ahora:

Hello, welcome to the world of functions!
The result of calling greet() is: None

Como puedes observar, el valor de la variable result es None. En Python, cualquier función que no tenga una declaración explícita de return devuelve automáticamente None. None es un valor especial que representa la ausencia de un valor. Esto confirma que tales funciones se utilizan por sus efectos secundarios (como imprimir) en lugar de producir datos.

Añadir Valores de Retorno a las Funciones

En contraste con el paso anterior, la mayoría de las funciones están diseñadas para calcular un valor y devolverlo al llamador. Esto se logra utilizando la palabra clave return. Una declaración return sale inmediatamente de la función y envía un valor especificado de vuelta.

Abre el archivo return_function.py desde el explorador de archivos en tu WebIDE.

Añade el siguiente código para definir una función que suma dos números y devuelve su suma:

def add_numbers(a, b):
    """This function adds two numbers and returns the sum."""
    sum_result = a + b
    return sum_result

## Call the function and store the returned value
total = add_numbers(5, 3)

## Print the returned value
print(f"The sum is: {total}")

## Use the returned value in another operation
another_total = add_numbers(10, 20) * 2
print(f"Another calculated value: {another_total}")

Guarda el archivo y ejecuta el script desde la terminal:

python ~/project/return_function.py

Deberías ver la siguiente salida, mostrando que los valores devueltos fueron capturados y utilizados exitosamente:

The sum is: 8
Another calculated value: 60

Una función puede devolver cualquier objeto de Python, incluyendo números, cadenas (strings), listas e incluso tuplas. Devolver una tupla es una forma común de devolver múltiples valores a la vez.

Añade el siguiente código al final de tu archivo return_function.py para ver esto en acción:

def get_user_info():
    """This function returns user information as a tuple."""
    name = "labex"
    age = 25
    city = "Virtual City"
    return name, age, city

## Call the function and unpack the returned tuple into separate variables
user_name, user_age, user_city = get_user_info()

## Print the unpacked values
print(f"Name: {user_name}, Age: {user_age}, City: {user_city}")

Guarda el archivo y ejecútalo de nuevo:

python ~/project/return_function.py

La salida completa será ahora:

The sum is: 8
Another calculated value: 60
Name: labex, Age: 25, City: Virtual City

Aquí, get_user_info() devuelve tres valores empaquetados como una tupla. El código que llama desempaqueta luego esta tupla en tres variables separadas, facilitando el trabajo con múltiples valores de retorno.

Diferenciar Variables Locales y Globales

Comprender el ámbito (scope) de las variables es esencial para escribir código libre de errores (bug-free). El ámbito determina dónde en tu programa se puede acceder a una variable.

  • Ámbito Global (Global Scope): Las variables definidas fuera de cualquier función son globales. Se puede acceder a ellas desde cualquier parte de tu script.
  • Ámbito Local (Local Scope): Las variables definidas dentro de una función son locales. Solo se puede acceder a ellas desde dentro de esa función.

Exploremos este concepto. Abre el archivo variable_scope.py en el WebIDE.

Añade el siguiente código al archivo:

## Global variable
global_variable = "I am a global variable"

def my_function():
    ## Local variable
    local_variable = "I am a local variable"
    print(f"Inside the function:")
    print(f"  Accessing global_variable: {global_variable}")
    print(f"  Accessing local_variable: {local_variable}")

## Call the function
my_function()

## Try to access variables outside the function
print(f"\nOutside the function:")
print(f"  Accessing global_variable: {global_variable}")

## Attempting to access local_variable here would cause a NameError
## print(f"  Accessing local_variable: {local_variable}")

Guarda el archivo y ejecútalo desde la terminal:

python ~/project/variable_scope.py

La salida demuestra la accesibilidad de cada variable:

Inside the function:
  Accessing global_variable: I am a global variable
  Accessing local_variable: I am a local variable

Outside the function:
  Accessing global_variable: I am a global variable

La variable global es accesible en todas partes, pero la variable local está confinada a su función. Si descomentaras la última línea, el script fallaría con un NameError.

Ahora, ¿qué sucede si una variable local tiene el mismo nombre que una global? La variable local "oculta" (shadows) a la global, lo que significa que dentro de la función, el nombre se referirá a la variable local.

Añade el siguiente código al final de tu archivo variable_scope.py para observar este efecto de ocultamiento (shadowing):

## Global variable
my_variable = "I am the global version"

def another_function():
    ## This local variable shadows the global one
    my_variable = "I am the local version"
    print(f"\nInside another_function(): {my_variable}")

## Call the function
another_function()

## The global variable remains unchanged
print(f"Outside another_function(): {my_variable}")

Guarda y ejecuta el script de nuevo:

python ~/project/variable_scope.py

La salida completa será:

Inside the function:
  Accessing global_variable: I am a global variable
  Accessing local_variable: I am a local variable

Outside the function:
  Accessing global_variable: I am a global variable

Inside another_function(): I am the local version
Outside another_function(): I am the global version

Dentro de another_function(), my_variable se refiere a la versión local. Fuera, se refiere a la versión global. La asignación dentro de la función no afectó a la variable global.

Modificar Variables Globales Usando la Palabra Clave global

Por defecto, no se puede cambiar el valor de una variable global desde dentro de una función. Una sentencia de asignación dentro de una función crea una nueva variable local. Para modificar explícitamente una variable global, debes usar la palabra clave global.

Abre el archivo modify_global.py en el WebIDE.

Añade el siguiente código, que define un contador global y una función para incrementarlo:

## Global variable
counter = 0

def increment_counter():
    ## Declare that we intend to modify the global counter
    global counter
    counter += 1
    print(f"Inside function: counter is {counter}")

## Print the initial value
print(f"Before calling function: counter is {counter}")

## Call the function to modify the global variable
increment_counter()

## Print the value after the function call
print(f"After calling function: counter is {counter}")

Guarda el archivo y ejecútalo desde la terminal:

python ~/project/modify_global.py

La salida muestra que la variable global fue modificada exitosamente:

Before calling function: counter is 0
Inside function: counter is 1
After calling function: counter is 1

La declaración global counter le indica a Python que cualquier operación sobre counter dentro de esta función debe afectar a la variable global, no a una nueva local.

Para contrastar esto, añadamos otra función que no use la palabra clave global. Añade el siguiente código al final de modify_global.py:

def increment_counter_local():
    ## This assignment creates a new local variable named 'counter'
    counter = 100
    print(f"\nInside function (local): counter is {counter}")

## Print the global counter's value before the test
print(f"Before calling function (local test): counter is {counter}")

## Call the function
increment_counter_local()

## The global counter's value is unaffected
print(f"After calling function (local test): counter is {counter}")

Guarda y ejecuta el script de nuevo:

python ~/project/modify_global.py

La salida completa demuestra la diferencia claramente:

Before calling function: counter is 0
Inside function: counter is 1
After calling function: counter is 1
Before calling function (local test): counter is 1
Inside function (local): counter is 100
After calling function (local test): counter is 1

En la segunda prueba, la asignación counter = 100 solo afectó a una variable local dentro de increment_counter_local(). El counter global conservó su valor de 1.

Comprender las Variables nonlocal en Funciones Anidadas

Las reglas de ámbito (scope) de Python también se aplican a las funciones anidadas (una función definida dentro de otra función). Una variable que no es local a la función interna pero sí es local a la función externa se denomina variable "no local" (nonlocal).

Para modificar dicha variable desde la función interna, debes usar la palabra clave nonlocal. Esto es similar a cómo funciona global, pero se aplica a ámbitos anidados en lugar del ámbito global.

Abre el archivo nonlocal_variable.py en el WebIDE.

Añade el siguiente código para demostrar el uso de nonlocal:

def outer_function():
    outer_variable = "I am in the outer function"

    def inner_function():
        ## Declare that we are modifying the variable from the enclosing scope
        nonlocal outer_variable
        outer_variable = "I have been modified by the inner function"
        print(f"Inside inner_function(): {outer_variable}")

    print(f"Before calling inner_function(): {outer_variable}")
    inner_function()
    print(f"After calling inner_function(): {outer_variable}")

## Call the outer function
outer_function()

Guarda el archivo y ejecútalo desde la terminal:

python ~/project/nonlocal_variable.py

La salida muestra que la función interna modificó exitosamente la variable de la función externa:

Before calling inner_function(): I am in the outer function
Inside inner_function(): I have been modified by the inner function
After calling inner_function(): I have been modified by the inner function

La declaración nonlocal outer_variable permite que inner_function reasigne (rebind) la outer_variable de outer_function.

Ahora, veamos qué sucede sin la palabra clave nonlocal. Añade el siguiente código al final de nonlocal_variable.py:

def outer_function_local_test():
    outer_variable = "I am in the outer function (local test)"

    def inner_function_local_test():
        ## This assignment creates a new local variable
        outer_variable = "I am a local variable in inner_function"
        print(f"\nInside inner_function_local_test(): {outer_variable}")

    print(f"\nBefore calling inner_function_local_test(): {outer_variable}")
    inner_function_local_test()
    print(f"After calling inner_function_local_test(): {outer_variable}")

## Call the outer function for the local test
outer_function_local_test()

Guarda y ejecuta el script de nuevo:

python ~/project/nonlocal_variable.py

La salida completa resalta la diferencia:

Before calling inner_function(): I am in the outer function
Inside inner_function(): I have been modified by the inner function
After calling inner_function(): I have been modified by the inner function

Before calling inner_function_local_test(): I am in the outer function (local test)
Inside inner_function_local_test(): I am a local variable in inner_function
After calling inner_function_local_test(): I am in the outer function (local test)

En el segundo ejemplo, la asignación dentro de inner_function_local_test() creó una nueva variable local, dejando inalterada la outer_variable en el ámbito envolvente (enclosing scope).

Resumen

En este laboratorio, has explorado varios conceptos clave relacionados con las funciones de Python. Comenzaste aprendiendo que las funciones sin una declaración return explícita devuelven implícitamente None. Luego practicaste el uso de la palabra clave return para enviar valores de vuelta desde una función, incluyendo la devolución de múltiples valores como una tupla (tuple).

También profundizaste en el ámbito de las variables (variable scope), distinguiendo entre variables locales (accesibles solo dentro de una función) y variables globales (accesibles en todo el script). Aprendiste cómo funciona el sombreado de variables (variable shadowing) y cómo usar la palabra clave global para modificar una variable global desde dentro de una función. Finalmente, examinaste las funciones anidadas y utilizaste la palabra clave nonlocal para modificar variables en un ámbito envolvente (enclosing scope) que no es el global.