Pular para o conteúdo

Como utilizar o passagem por referência no Python

[

Passagem de Referência em Python: Conceito e Melhores Práticas

Por Marius Mogyorosi

Depois de se familiarizar um pouco com o Python, você pode perceber casos em que suas funções não modificam os argumentos no lugar, como você poderia esperar, especialmente se estiver familiarizado com outras linguagens de programação. Algumas linguagens tratam os argumentos das funções como referências para variáveis existentes, o que é conhecido como passagem de referência. Outras linguagens tratam os argumentos como valores independentes, uma abordagem conhecida como passagem por valor.

Se você é um programador intermediário de Python que deseja entender a maneira peculiar do Python de lidar com os argumentos das funções, este tutorial é para você. Você implementará casos reais de construções de passagem por referência em Python e aprenderá várias melhores práticas para evitar problemas com os argumentos das suas funções.

O que significa passagem de referência em Python?

Antes de entrar nos detalhes técnicos da passagem por referência, é útil analisar mais de perto o próprio termo, dividindo-o em componentes:

  • Passagem significa fornecer um argumento para uma função.
  • Por referência significa que o argumento que você está passando para a função é uma referência a uma variável que já existe na memória, em vez de uma cópia independente dessa variável.

Como você está dando à função uma referência a uma variável existente, todas as operações realizadas nessa referência afetarão diretamente a variável à qual ela se refere. Vamos analisar alguns exemplos de como isso funciona na prática.

Abaixo, você verá como passar variáveis por referência em C#. Observe o uso da palavra-chave ref nas linhas destacadas:

C#

using System;
class Program
{
static void Main(string[] args)
{
int arg;
// Passagem por referência.
// O valor atribuído na função terá efeito na variável original.
SetToFive(ref arg);
Console.WriteLine(arg); // Output: 5
}
static void SetToFive(ref int number)
{
number = 5;
}
}

Neste exemplo em C#, a função SetToFive recebe uma referência para a variável arg e atribui o valor 5 a ela. Como a variável arg é uma referência, a modificação feita dentro da função altera diretamente o valor da variável original.

Diferença entre passagem por referência e passagem por valor

Agora que você entende o conceito de passagem por referência, vamos compará-lo com a passagem por valor, que é mais comumente usada em Python.

Quando você passa um argumento por valor, você está passando uma cópia do valor da variável original. Isso significa que qualquer modificação feita no argumento dentro da função não afeta a variável original. Veja a seguir um exemplo em Python que ilustra isso:

Python

def square(number):
number = number ** 2
num = 5
square(num)
print(num) # Output: 5

Neste exemplo, a função square recebe um argumento number, calcula o seu quadrado e atribui o resultado à variável number. No entanto, a modificação feita dentro da função não afeta o valor da variável original num, que permanece como 5.

Usando construções de passagem por referência em Python

Embora Python não suporte a passagem de argumentos por referência como algumas outras linguagens de programação, é possível replicar esse comportamento usando determinados tipos de dados mutáveis. A seguir, exploraremos algumas dessas construções de passagem por referência em Python.

Evitando objetos duplicados

Em alguns casos, ao passar um objeto mutável como argumento para uma função, você pode querer evitar criar uma nova cópia desse objeto. Em vez disso, você pode simplesmente passar uma referência para o objeto original, como no exemplo a seguir:

def modify_list(lst):
lst.append(4)
my_list = [1, 2, 3]
modify_list(my_list)
print(my_list) # Output: [1, 2, 3, 4]

Neste exemplo, a função modify_list recebe uma lista lst e adiciona o número 4 a ela. Como a lista é um objeto mutável, a modificação é feita no próprio objeto original. Portanto, ao imprimir a lista my_list depois de chamar a função, você verá que o número 4 foi adicionado a ela.

Retornando vários valores

Em algumas situações, você pode precisar retornar vários valores de uma função. Uma maneira de fazer isso em Python é retornar uma tupla contendo esses valores, como mostrado no exemplo a seguir:

def get_circle_properties(radius):
circumference = 2 * 3.14 * radius
area = 3.14 * radius ** 2
return circumference, area
r = 5
circle_props = get_circle_properties(r)
circumference, area = circle_props
print(circumference) # Output: 31.4
print(area) # Output: 78.5

Neste exemplo, a função get_circle_properties retorna a circunferência e a área de um círculo com base no seu raio. Os valores são retornados como uma tupla e podem ser atribuídos a variáveis separadas usando a técnica de desempacotamento de tupla. Essa abordagem permite que você retorne e use vários valores de uma função de maneira eficiente.

Criando funções com múltiplos retornos condicionais

Às vezes, você pode precisar de uma função que retorne diferentes conjuntos de valores com base em uma condição. Em Python, você pode usar a abordagem de múltiplos retornos com base em uma condição booleana, como mostrado abaixo:

def get_values(condition):
if condition:
return 1, 2
else:
return 3, 4
result1, result2 = get_values(True)
print(result1, result2) # Output: 1 2
result3, result4 = get_values(False)
print(result3, result4) # Output: 3 4

Neste exemplo, a função get_values retorna dois valores diferentes com base na condição booleana fornecida. Se a condição for True, a função retorna os valores 1 e 2. Caso contrário, ela retorna os valores 3 e 4. Assim, você pode ter diferentes conjuntos de valores retornados de uma mesma função, dependendo das condições desejadas.

Passando argumentos em Python

Agora que você entende melhor a passagem por referência e as construções associadas a ela, vamos explorar como os argumentos são passados em Python. Para isso, vamos analisar a atribuição em Python e os diferentes tipos de argumentos que você pode usar em suas funções.

Entendendo a atribuição em Python

Para compreender como os argumentos são passados em Python, é importante entender como a atribuição funciona. Em Python, uma atribuição cria uma associação entre o nome do objeto e o valor do objeto. Portanto, quando você atribui um objeto a uma variável, você está criando uma nova associação. Da mesma forma, quando você atribui um objeto a uma função, você está criando uma nova associação entre o nome do parâmetro da função e o valor do argumento.

Vamos ver um exemplo para esclarecer isso:

def update_value(num):
num = 10
value = 5
update_value(value)
print(value) # Output: 5

Neste exemplo, a função update_value recebe um argumento num e atribui o valor 10 a essa variável. No entanto, a variável value original não é afetada pela atribuição feita dentro da função. Isso ocorre porque a atribuição em Python cria uma nova associação entre o nome e o valor do objeto, sem afetar a associação original.

Explorando os argumentos das funções

Existem três tipos principais de argumentos que você pode usar ao definir suas funções em Python: argumentos posicionais, argumentos de palavra-chave e argumentos padrão.

  1. Argumentos posicionais: são os argumentos que você passa com base na posição em que eles são definidos na função. Eles são atribuídos aos parâmetros da função na mesma ordem em que são passados.

    Exemplo:

    def greet(first_name, last_name):
    print(f"Hello, {first_name} {last_name}!")
    greet("John", "Doe") # Output: Hello, John Doe!
  2. Argumentos de palavra-chave: são os argumentos que você passa com base no nome do parâmetro da função. Eles são atribuídos aos parâmetros correspondentes, independentemente da ordem em que são passados.

    Exemplo:

    def greet(first_name, last_name):
    print(f"Hello, {first_name} {last_name}!")
    greet(last_name="Doe", first_name="John") # Output: Hello, John Doe!
  3. Argumentos padrão: são os argumentos que têm um valor padrão atribuído a eles. Se você não passar um valor para esses argumentos, o valor padrão será usado.

    Exemplo:

    def greet(first_name, last_name="Doe"):
    print(f"Hello, {first_name} {last_name}!")
    greet("John") # Output: Hello, John Doe!
    greet("Jane", "Smith") # Output: Hello, Jane Smith!

Ao entender esses diferentes tipos de argumentos e como eles são tratados em Python, você pode escrever funções mais flexíveis e reutilizáveis.

Replicando a passagem por referência com Python

Embora Python não suporte a passagem de argumentos por referência diretamente como algumas outras linguagens de programação, é possível replicar esse comportamento usando algumas práticas recomendadas. A seguir, veremos algumas das melhores práticas para replicar a passagem por referência em Python.

Melhor prática: Retornar e reatribuir

Uma maneira comum de replicar a passagem por referência é retornar o objeto modificado de uma função e atribuí-lo novamente à variável original. Isso garante que a variável original seja atualizada com as mudanças feitas dentro da função.

Aqui está um exemplo que ilustra essa prática:

def update_list(lst):
lst.append(4)
return lst
my_list = [1, 2, 3]
my_list = update_list(my_list)
print(my_list) # Output: [1, 2, 3, 4]

Neste exemplo, a função update_list recebe uma lista lst, adiciona o número 4 a ela e retorna a lista modificada. Em seguida, a variável my_list é atribuída novamente ao valor retornado pela função. Como resultado, a variável original é atualizada com as alterações feitas dentro da função.

Melhor prática: Usar atributos de objetos

Outra maneira de replicar a passagem por referência em Python é usar atributos de objetos. Ao invés de modificar diretamente o objeto passado como argumento, você pode acessar e modificar os atributos desse objeto dentro da função.

Veja um exemplo que demonstra essa prática:

class Circle:
def __init__(self, radius):
self.radius = radius
def update_radius(circle, new_radius):
circle.radius = new_radius
my_circle = Circle(5)
update_radius(my_circle, 10)
print(my_circle.radius) # Output: 10

Neste exemplo, a função update_radius recebe um objeto circle e um novo raio. Em vez de modificar diretamente o objeto circle, a função atribui o novo raio ao atributo radius desse objeto. Assim, a variável original my_circle é atualizada porque ambas as variáveis fazem referência ao mesmo objeto.

Melhor prática: Usar dicionários e listas

Dicionários e listas são tipos de dados mutáveis em Python que podem ser usados para simular a passagem por referência. Ao passar um dicionário ou lista como argumento para uma função, você está passando uma referência ao objeto original, permitindo que alterações sejam feitas diretamente no objeto.

Veja um exemplo que utiliza uma lista:

def modify_list(lst):
lst.append(4)
my_list = [1, 2, 3]
modify_list(my_list)
print(my_list) # Output: [1, 2, 3, 4]

Neste exemplo, a função modify_list recebe uma lista lst e adiciona o número 4 a ela. Como a lista é um objeto mutável, a modificação é feita diretamente no objeto original. Portanto, ao imprimir a lista my_list depois de chamar a função, você verá que o número 4 foi adicionado a ela.

Conclusão

Embora Python não suporte a passagem de argumentos por referência como algumas outras linguagens de programação, é possível replicar esse comportamento usando práticas recomendadas. Neste tutorial, exploramos diferentes maneiras de passar argumentos por referência em Python, incluindo evitar objetos duplicados, retornar múltiplos valores, criar funções com múltiplos retornos condicionais e usar dicionários e listas. Com essas técnicas, você pode escrever funções mais flexíveis e reutilizáveis em Python.