Além do rótulo: como as variáveis ​​python realmente funcionam com a memória

Você dominou o básico: as variáveis ​​são rótulos, não caixas. Você conhece é vs. ==. Agora, vamos recuar a cortina ainda mais e ver o que acontece quando você lida com estruturas de dados mais complexas. Esse conhecimento é essencial para evitar alguns dos insetos mais comuns e frustrantes. 1. Tudo é um objeto (e tem um ID) em Python, tudo é um objeto. Inteiros, cordas, funções, módulos e até aulas – todos vivem na memória e têm três coisas: 1. Identidade: um número exclusivo e constante (sua identidade) que age como um endereço de memória no cpython. Você vê isso com a função id (). Este número é garantido para ser único para a vida útil do objeto. Tipo: que tipo de objeto é (por exemplo, int, str, lista) .3. Valor: os dados reais que ele possui. O id () é o “endereço residencial” do objeto. A palavra -chave IS simplesmente compara esses IDs. a = [1, 2, 3] # O Python cria um objeto de lista, fornece um ID e a marca `a` print (id (a)) # imprime um número longo, por exemplo, 139936863411456 b = a # Isso anexa uma nova tag` b` ao mesmo objeto (mesmo id) print (id (b)) # o mesmo número como acima! Imprimir (a é b) # verdadeiro, porque seus IDs são idênticos. Digite Modo de tela cheia de saída do modo de tela cheia, esse relacionamento pode ser visualizado simplesmente: a -> [1, 2, 3] <- b Digite o modo de saída de tela cheia do modo de tela cheia Ambas as variáveis ​​são referências (etiquetas) apontando para o mesmo objeto de lista única na memória. 2. Atribuição vs. cópia superficial vs. cópia profunda Este é o coração do assunto. A confusão entre essas três operações é um rito clássico de passagem. Atribuição (=): isso cria apenas um novo rótulo (variável) para o objeto existente. Nenhum novo objeto é criado. Agora você tem dois rótulos apontando para os mesmos dados. Altere os dados por meio de um rótulo e muda para o outro. Cópia rasa: cria um novo objeto externo, mas, em vez de criar cópias dos objetos internos, ele apenas copia as referências a eles. É como comprar um novo fichário (new_list) e colocar fotocópias do índice do antigo fichário dentro. Os capítulos (os objetos internos) ainda são os mesmos. Você pode criar uma cópia superficial com .copy (), list () ou fatiamento original_list[:]. Cópia profunda: cria um novo objeto externo e, em seguida, cria recursivamente novas cópias de todos os objetos encontrados no original. É uma duplicata completa, sem conexão com o original. Vamos ver a diferença crucial com uma lista que contém outra lista (uma estrutura aninhada): importar cópia original = [1, 2, [3, 4]]# Uma lista dentro de uma lista # atribuição atribuída = # original cópia rasa (usando .copy () – list (original) ou original[:] funcionar da mesma forma) shallow_copied = original.copy () # Deep copy Deep_copied = copy.deepCopy (original) agora, vamos alterar a lista interna do original original[2].Append (5) Print (“Original:”, Original) # [1, 2, [3, 4, 5]]Print (“Atribuído:”, atribuído) # [1, 2, [3, 4, 5]](alterado – mesmo objeto) print (“cópia rasa:”, shallow_copied) # [1, 2, [3, 4, 5]]😲 (alterado! A lista interna é compartilhada) Print (“cópia profunda:”, Deep_copied) # [1, 2, [3, 4]](inalterado – verdadeiramente independente) Digite o modo de tela cheia de tela cheia, o modo de cópia rasa surpresa: este é o principal argumento. A lista externa SHOULL_COPIED é nova, portanto, anexar a ela não afetaria o original. Mas a lista interna [3, 4] é o mesmo objeto nas duas listas. Modificar -o através de uma variável afeta o outro. 3. Os argumentos da função são “passados ​​pela referência do objeto”, esse conceito une tudo. As pessoas costumam perguntar: “O Python Pass-By-Reference ou Pass-By Value?” A resposta mais precisa é: é “referência passada por objeto”. Quando você chama uma função, um novo rótulo (o nome do parâmetro) é atribuído ao mesmo objeto que foi passado. As mesmas regras se aplicam. A chave é entender a diferença entre modificar um objeto e re-vincular um rótulo. A modificação de um objeto mutável no local (por exemplo, usando .Append (), .Update ()) será visível fora da função. DEF APEND_TO_LIST (Some_List): Some_List.Append (“OOPS”) # Isso modifica o próprio objeto original. print (“Função interna:”, alguma_list) my_list = [“hello”]
Append_to_List (my_list) # saída: função interna: [‘hello’, ‘oops’]
Print (“Função externa:”, my_list) # saída: função externa: [‘hello’, ‘oops’] 😲 Digite o modo de tela cheia de tela cheia de tela cheia re-vincular uma etiqueta dentro de uma função (usando =) altera apenas o que esse rótulo local aponta para. Não tem efeito na variável externa original. DEF reathsign_list (Some_List): Some_List = [“a”, “new”, “list”] # Re-vincula o rótulo local `algum_list` para um novo objeto. print (“Função interna (após reinicialização):”, alguma_list) my_list = [“hello”]
reathsign_list (my_list) # saída: função interna (após a reinicialização): [‘a’, ‘new’, ‘list’]
Print (“Função externa:”, my_list) # saída: função externa: [‘hello’] ✅ (UNNAFECTED!) Digite modo de tela cheia de tela cheia de tela cheia sua lista de verificação do modelo mental antes de escrever uma linha de código, pergunte a si mesmo: 1. Qual é o tipo de dados? É mutável (lista, dicto, conjunto) ou imutável (int, str, tupla)? 2. Que operação estou executando? Estou atribuindo (=), fazendo uma cópia rasa (.copy (), list (), [:]), ou uma cópia profunda (copy.deepcopy ())? 3. Se for uma função, o que acontecerá dentro? Ele modificará o objeto que passe (alteração no local) ou apenas transferindo o rótulo do parâmetro (sem efeito externo)? Compreender isso leva você a escrever código que funciona por acidente para escrever código que funciona por design. Você para de temer efeitos colaterais e começa a controlá -los. Aaron Rose é engenheiro de software e escritor de tecnologia do Tech-Reader.blog e autor de Think como um gênio.

Fonte

Você pode ter perdido