Valores de Retorno e Escopo de Funções em Python

PythonBeginner
Pratique Agora

Introdução

Neste laboratório, você aprofundará sua compreensão sobre funções em Python, explorando seus valores de retorno e o conceito de escopo de variáveis. Você começará examinando funções que não retornam explicitamente um valor, observando como elas executam ações sem produzir um resultado que possa ser usado em outro lugar.

Posteriormente, você aprenderá a adicionar valores de retorno às funções, permitindo que elas produzam uma saída que pode ser capturada e utilizada em seus programas. O laboratório então o guiará através da diferenciação entre variáveis locais e globais, compreendendo seus respectivos escopos e como eles afetam a acessibilidade das variáveis dentro e fora das funções. Você também aprenderá a modificar variáveis globais a partir de dentro das funções usando a palavra-chave global e explorará o conceito de variáveis nonlocal em funções aninhadas.

Explore Funções Sem Valores de Retorno

Nesta etapa, exploraremos funções que não possuem uma instrução explícita de return. Essas funções executam uma ação, como imprimir no console, mas não enviam um valor de volta para a parte do código que as chamou.

Primeiro, localize o arquivo no_return_function.py no explorador de arquivos no lado esquerdo do WebIDE. Dê um duplo clique nele para abri-lo no editor.

Adicione o seguinte código ao arquivo no_return_function.py:

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

## Call the function
greet()

Para executar este script, abra o terminal integrado clicando em Terminal > New Terminal no menu superior. Em seguida, execute o seguinte comando:

python ~/project/no_return_function.py

Você verá a saída da função impressa no console:

Hello, welcome to the world of functions!

A função greet() executa a instrução print(), mas não produz um valor que possa ser armazenado em uma variável. Para ver o que acontece quando você tenta capturar o resultado, modifique o arquivo no_return_function.py. Substitua o conteúdo existente pelo seguinte 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}")

Salve o arquivo e execute-o novamente a partir do terminal:

python ~/project/no_return_function.py

A saída será agora:

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

Como você pode ver, o valor da variável result é None. Em Python, qualquer função que não tenha uma instrução return explícita retorna None automaticamente. None é um valor especial que representa a ausência de um valor. Isso confirma que tais funções são usadas por seus efeitos colaterais (como imprimir) em vez de produzir dados.

Adicionar Valores de Retorno às Funções

Em contraste com a etapa anterior, a maioria das funções é projetada para calcular um valor e retorná-lo ao chamador. Isso é alcançado usando a palavra-chave return. Uma instrução return sai imediatamente da função e envia um valor especificado de volta.

Abra o arquivo return_function.py no explorador de arquivos do seu WebIDE.

Adicione o seguinte código para definir uma função que soma dois números e retorna a soma deles:

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}")

Salve o arquivo e execute o script a partir do terminal:

python ~/project/return_function.py

Você deverá ver a seguinte saída, mostrando que os valores retornados foram capturados e utilizados com sucesso:

The sum is: 8
Another calculated value: 60

Uma função pode retornar qualquer objeto Python, incluindo números, strings, listas e até mesmo tuplas (tuples). Retornar uma tupla é uma maneira comum de retornar múltiplos valores de uma só vez.

Adicione o seguinte código ao final do seu arquivo return_function.py para ver isso em ação:

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}")

Salve o arquivo e execute-o novamente:

python ~/project/return_function.py

A saída completa será agora:

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

Aqui, get_user_info() retorna três valores empacotados como uma tupla. O código chamador então desempacota essa tupla em três variáveis separadas, facilitando o trabalho com múltiplos valores de retorno.

Diferenciar Variáveis Locais e Globais

Compreender o escopo (scope) das variáveis é essencial para escrever código sem bugs. O escopo determina onde no seu programa uma variável pode ser acessada.

  • Escopo Global (Global Scope): Variáveis definidas fora de qualquer função são globais. Elas podem ser acessadas de qualquer lugar no seu script.
  • Escopo Local (Local Scope): Variáveis definidas dentro de uma função são locais. Elas só podem ser acessadas de dentro dessa função.

Vamos explorar este conceito. Abra o arquivo variable_scope.py no WebIDE.

Adicione o seguinte código ao arquivo:

## 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}")

Salve o arquivo e execute-o a partir do terminal:

python ~/project/variable_scope.py

A saída demonstra a acessibilidade de cada variável:

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

A variável global é acessível em todos os lugares, mas a variável local está restrita à sua função. Se você descomentasse a última linha, o script falharia com um NameError.

Agora, o que acontece se uma variável local tiver o mesmo nome que uma global? A variável local "sombreia" (shadows) a global, o que significa que, dentro da função, o nome se referirá à variável local.

Adicione o seguinte código ao final do seu arquivo variable_scope.py para observar este efeito de sombreamento:

## 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}")

Salve e execute o script novamente:

python ~/project/variable_scope.py

A saída 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 refere-se à versão local. Fora dela, refere-se à versão global. A atribuição dentro da função não afetou a variável global.

Modificar Variáveis Globais Usando a Palavra-chave global

Por padrão, você não pode alterar o valor de uma variável global de dentro de uma função. Uma instrução de atribuição dentro de uma função cria uma nova variável local. Para modificar explicitamente uma variável global, você deve usar a palavra-chave global.

Abra o arquivo modify_global.py no WebIDE.

Adicione o seguinte código, que define um contador global e uma função para incrementá-lo:

## 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}")

Salve o arquivo e execute-o a partir do terminal:

python ~/project/modify_global.py

A saída mostra que a variável global foi modificada com sucesso:

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

A instrução global counter informa ao Python que qualquer operação em counter dentro desta função deve afetar a variável global, e não uma nova variável local.

Para contrastar, vamos adicionar outra função que não usa a palavra-chave global. Adicione o seguinte código ao 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}")

Salve e execute o script novamente:

python ~/project/modify_global.py

A saída completa demonstra a diferença 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

No segundo teste, a atribuição counter = 100 afetou apenas uma variável local dentro de increment_counter_local(). O counter global manteve seu valor de 1.

Compreender Variáveis nonlocal em Funções Aninhadas

As regras de escopo do Python também se aplicam a funções aninhadas (uma função definida dentro de outra função). Uma variável que não é local à função interna, mas é local à função externa, é chamada de variável "nonlocal".

Para modificar tal variável a partir da função interna, você deve usar a palavra-chave nonlocal. Isso é semelhante a como global funciona, mas aplica-se a escopos aninhados em vez do escopo global.

Abra o arquivo nonlocal_variable.py no WebIDE.

Adicione o seguinte código para demonstrar o 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()

Salve o arquivo e execute-o a partir do terminal:

python ~/project/nonlocal_variable.py

A saída mostra que a função interna modificou com sucesso a variável da função 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

A instrução nonlocal outer_variable permite que inner_function reatribua a outer_variable de outer_function.

Agora, vamos ver o que acontece sem a palavra-chave nonlocal. Adicione o seguinte código ao 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()

Salve e execute o script novamente:

python ~/project/nonlocal_variable.py

A saída completa destaca a diferença:

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)

No segundo exemplo, a atribuição dentro de inner_function_local_test() criou uma nova variável local, deixando a outer_variable no escopo envolvente inalterada.

Resumo

Neste laboratório, você explorou vários conceitos chave relacionados a funções em Python. Você começou aprendendo que funções sem uma instrução return explícita retornam implicitamente None. Em seguida, praticou o uso da palavra-chave return para enviar valores de volta de uma função, incluindo o retorno de múltiplos valores como uma tupla (tuple).

Você também se aprofundou no escopo de variáveis, distinguindo entre variáveis locais (acessíveis apenas dentro de uma função) e variáveis globais (acessíveis em todo o script). Você aprendeu como funciona o sombreamento de variáveis (variable shadowing) e como usar a palavra-chave global para modificar uma variável global de dentro de uma função. Finalmente, você examinou funções aninhadas e usou a palavra-chave nonlocal para modificar variáveis em um escopo envolvente, não global.