Entenda como o Python passa referência?
Passagem por Referência em Python: Conceito e Melhores Práticas
por Marius Mogyorosi
Após adquirir alguma familiaridade com Python, você pode notar casos em que suas funções não modificam os argumentos no lugar como você esperaria, especialmente se você está familiarizado com outras linguagens de programação. Algumas linguagens tratam os argumentos da função como referências a variáveis existentes, o que é conhecido como passagem por referência. Outras linguagens os tratam como valores independentes, uma abordagem conhecida como passagem por valor.
Se você é um programador Python intermediário que deseja entender a forma peculiar do Python de lidar com os argumentos de função, então este tutorial é para você. Você irá implementar casos de uso reais de construções de passagem por referência em Python e aprender várias melhores práticas para evitar problemas com seus argumentos de função.
Definindo Passagem por Referência
Antes de mergulhar nos detalhes técnicos da passagem por referência, é útil analisar mais de perto o próprio termo, que pode ser dividido 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, e não uma cópia independente dessa variável.
Uma vez que 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 ver alguns exemplos de como isso funciona na prática.
Aqui você verá como passar variáveis por referência em C#. Observe o uso da palavra-chave ref
nas linhas destacadas:
Nesse exemplo, a função PassByReference
recebe x
como um argumento por referência usando a palavra-chave ref
. A utilização da palavra-chave ref
indica que a variável arg
na função Main
será modificada diretamente e terá o valor de 10.
Agora vamos comparar a passagem por referência com a passagem por valor.
Comparando Passagem por Referência e Passagem por Valor
A principal diferença entre a passagem por referência e a passagem por valor está na forma como as variáveis são tratadas em relação às funções. Na passagem por referência, a função recebe uma referência à variável existente e todas as modificações afetam diretamente essa variável. Na passagem por valor, a função recebe uma cópia independente da variável e todas as modificações são feitas nessa cópia, não afetando a variável original.
Para entender melhor, vamos comparar os dois métodos de passagem com um exemplo prático em Python:
No exemplo acima, a função pass_by_value
recebe x
como um argumento e atribui o valor 10 a x
. No entanto, essa modificação não afeta a variável original x
fora da função, e o valor de x
impresso é 5.
Por outro lado, a função pass_by_reference
recebe um objeto obj
e chama o método set_value
para definir o valor como 10. Como a função recebe uma referência ao objeto original, a modificação realmente afeta o objeto original, e o valor de obj.value
impresso é 10.
É importante entender a diferença entre passagem por referência e passagem por valor, especialmente ao trabalhar com funções que modificam argumentos. No próximo tópico, exploraremos como os argumentos são passados em Python.
Passando Argumentos em Python
Em Python, é importante entender como a atribuição de variáveis funciona para compreender como os argumentos são passados para as funções.
Compreendendo a Atribuição em Python
Em Python, as variáveis são atribuídas a objetos. Essa atribuição cria uma referência entre a variável e o objeto. Quando uma variável é passada como argumento para uma função, uma cópia da referência é feita, mas não uma cópia do objeto em si. Isso significa que se o objeto for modificado dentro da função, essa modificação afetará a variável original fora da função.
Vamos ver um exemplo para ilustrar isso:
Neste exemplo, a função modify_list
recebe uma lista lst
e adiciona o número 10 a ela. Após chamar a função modify_list
com a lista my_list
, a lista original é modificada e o valor impresso é [1, 2, 3, 10]
.
Isso ocorre porque a função modify_list
recebe a referência à lista my_list
como argumento e modifica a lista diretamente. A atribuição em Python cria uma relação entre a variável lst
e a lista original, de modo que qualquer modificação na lista lst
é refletida na lista original.
Explorando os Argumentos de Função
Python suporta diferentes tipos de argumentos de função: argumentos posicionais, argumentos nomeados, argumentos posicionais padrão e argumentos de palavras-chave.
- Argumentos posicionais são passados por ordem e associados aos parâmetros da função.
- Argumentos nomeados são especificados explicitamente pelo nome ao chamar a função.
- Argumentos posicionais padrão possuem um valor padrão e podem ser omitidos ao chamar a função.
- Argumentos de palavras-chave são passados com uma sintaxe especial (
nome=valor
) e associados aos parâmetros da função pelo nome.
Vamos ver alguns exemplos desses tipos de argumentos:
No exemplo acima, a função greet
recebe dois argumentos: name
e message
. O argumento name
é um argumento posicional, enquanto o argumento message
é um argumento posicional padrão. Isso significa que name
deve ser o primeiro argumento passado, mas message
pode ser omitido, pois possui um valor padrão de "Hello"
. No segundo chamada da função, os argumentos são especificados explicitamente pelo nome (name="Bob"
, message="Hi"
), permitindo que sejam passados fora de ordem.
Ter uma compreensão clara de como os argumentos de função funcionam em Python é essencial para entender como a passagem por referência pode ser replicada em Python. Vamos explorar isso no próximo tópico.
Replicando Passagem por Referência em Python
Embora Python não suporte a passagem por referência no sentido estrito, é possível replicar esse comportamento com certos tipos de objetos mutáveis, como listas, dicionários e objetos personalizados com atributos mutáveis. Nesta seção, vamos discutir algumas práticas recomendadas para replicar a passagem por referência em Python.
Boas Práticas: Retornar e Reatribuir
Uma das maneiras mais comuns de replicar a passagem por referência em Python é retornar o objeto modificado de uma função e reatribuí-lo à variável original. Isso permite que as modificações feitas na função afetem diretamente o objeto original.
Vamos ver um exemplo:
Neste exemplo, a função modify_list
recebe uma lista lst
, adiciona o número 10 a ela e retorna a lista modificada. Ao chamar a função e reatribuir o resultado à variável my_list
, o objeto original é atualizado com as modificações feitas pela função.
Essa abordagem é particularmente útil quando você deseja modificar um objeto dentro de uma função e manter o valor de retorno da função.
Boas Práticas: Usar Atributos de Objeto
Outra maneira de replicar a passagem por referência em Python é usando atributos mutáveis de objetos. Quando você passa um objeto como argumento para uma função e modifica seus atributos mutáveis dentro da função, as modificações afetarão o objeto original.
Vamos ver um exemplo:
Neste exemplo, a função paint_car
recebe um objeto car
e uma cor, e atualiza o atributo color
do objeto. Ao chamar a função e passar o objeto my_car
, o atributo color
é atualizado com a nova cor.
Essa abordagem é especialmente útil quando você deseja modificar os atributos de um objeto, como no exemplo acima. No entanto, observe que isso funciona apenas para atributos mutáveis do objeto.
Boas Práticas: Usar Listas e Dicionários
Uma terceira maneira de replicar a passagem por referência em Python é usando listas ou dicionários para encapsular os valores que você deseja modificar. Ao passar a lista ou o dicionário como argumento para a função e modificar seus elementos ou valores dentro da função, as modificações afetarão o objeto original.
Vamos ver um exemplo:
Neste exemplo, as funções modify_list
e modify_dict
recebem uma lista lst
e um dicionário d
, respectivamente, e modificam os elementos ou valores dentro dos objetos. Ao chamar as funções e passar os objetos originais, as modificações afetam diretamente os objetos originais.
Essa abordagem é versátil, pois pode ser usada para modificar qualquer número de elementos ou valores dentro da lista ou do dicionário. Além disso, você também pode passar os objetos por referência dentro da lista ou dicionário, replicando assim a passagem por referência.
Conclusão
Python não suporta a passagem por referência no sentido estrito como algumas outras linguagens de programação, mas é possível replicar esse comportamento com certos tipos de objetos mutáveis. Neste tutorial, você aprendeu a diferença entre passagem por referência e passagem por valor, explorou como os argumentos de função são passados em Python e descobriu algumas práticas recomendadas para replicar a passagem por referência em Python.
Lembre-se de que, ao trabalhar com argumentos de função em Python, é importante entender como a atribuição e a passagem de objetos funcionam para evitar comportamentos indesejados em suas funções. Use as práticas recomendadas apresentadas neste tutorial para gerenciar e modificar seus argumentos adequadamente.
Artigo traduzido e adaptado por Marius Mogyorosi.