Função de Python altera variável fora de seu escopo

A função inverterRec está alterando o valor da variável vet que é do escopo da função main.
recursividade.py (2,3 KB)

A função não está alterando a variável, mas sim o objeto para o qual a variável aponta. Não tem problema nenhum nisso.

Listas são passadas por referência para argumentos. Quando você altera uma lista dentro de uma função, todas as variáveis que tem uma referência àquela lista veem as mudanças, independente do escopo. O que importa é a referência!

A maioria das linguagens funcionam desse jeito, passando por copia de valor tipos primitivos (e às vezes structs), e passando por cópia de referência os objetos.

Se você não quer que a lista original seja alterada, passe uma cópia dela como argumento da função. Pode fazer um slice completo ([:]) ou utilizar as funções de cópia do Python.

Mas por que isso não acontece com váriaveis normais?

Acho que quando você diz “variáveis normais”, você se refere a tipos primitivos. É uma decisão de design, quando os caras criam a linguagem. Essa decisão geralmente é a mais comum. A regra é essa que eu te falei:

  1. Tipos primitivos (ou variáveis normais, como você diz) como int, float, double, string, por exemplo, são passados por cópia.

    Quando você chama uma função passando uma variável que tem um valor desse tipo, o interpretador vai copiar o valor da variável e atribuir ao argumento da função. É literalmente uma cópia de valor.

     def foo(a):
         a = 3 // não altera x, pois são lugares diferentes da memória, apesar de ambos terem o mesmo valor 1 antes da atribuição.
         // agora A vale 3, e X continua valendo 1
    
     x = 1
     foo(x) // nesse momento, uma nova variavel chamada de "a" é criada, com o valor copiado de X, dentro do escopo dessa chamada. 
    
  2. Quando uma variável não tem um tipo primitivo dentro dela, ela vai ter um endereço para um objeto. Tipos como lista, conjunto, dicionário, e até mesmo classes definidas pelo programador são exemplos de tipos não primitivos. Quando você faz:

     x = [1, 2, 3]
     y = x
    

    Existe uma lista na memória, com o conteúdo [1, 2, 3]. X, a primeira variável, possui uma referência para essa lista, um endereço de memória. Quando você faz x = y, o que é copiado de X para Y não é a lista em si, mas a referência.

    Por isso, se você fizer:

     y[0] = 1000
     print x[0]
    

    O que é impresso é o valor 1000, pois o objeto para o qual Y aponta é o mesmo que X aponta. É exatamente isso que acontece quando você passa um tipo não primitivo por argumento. A referência é copiada para a variável da função (o parâmetro), e não o objeto para o qual a referência aponta.

Agora entendi!! Valeu mesmo.