14 de janeiro de 2013

Como as variáveis funcionam em Python

Python tem alguns conceitos muito interessantes, que nos fazem pensar diferente em muitos casos. Um deles é o conceito de variável.

A explicação mais didática que eu encontrei foi nesse artigo, de Fredrik Lundh: Python Objects. Eu achei o texto tão bom, que resolvi traduzí-lo na íntegra, abaixo.

Introdução

Esvazie seu cérebro.

Objetos

Todos os objetos Python têm isso:
  • uma identidade única (um valor inteiro, retornado por id(x))
  • um tipo (retornado por type(x))
  • algum conteúdo
Você não pode mudar a identidade.

Você não pode mudar o tipo.

Alguns objetos permitem que você mude seus conteúdos (sem mudar sua identidade, nem seu tipo).

O tipo é representado por um objeto type, que sabe mais sobre objetos do seu próprio tipo (quantos bytes eles normalmente ocupam na memória, quais métodos eles têm, etc.)

(Atualização: No CPython 2.2 ou mais atual, você pode mudar o tipo de um objeto sob algumas circunstâncias bem específicas.)

Mais sobre objetos

Objetos também podem ter:
  • zero ou mais métodos (fornecidos pelo objeto type)
  • zero ou mais nomes
Alguns objetos têm métodos que nos permitem modificar o seu conteúdo (no mesmo lugar que eles estão).

Alguns objetos têm métodos que nos permitem apenas acessar o conteúdo, sem modificá-lo.

Alguns objetos não têm nenhum método mesmo.

Mesmo em um objeto que tenha métodos, você não consegue mudar o tipo, nem a identidade.

Coisas como atribuição de valores e indexação de itens são embelezamento sintático (mais sobre isso, logo a seguir).

Nomes

Os nomes são um pouco diferentes -- eles não são exatamente propriedades do objeto, e os objetos nem sabem quais nomes receberam.

Um objeto pode ter vários nomes, ou nenhum nome.

Os nomes residem num namespace (como um namespace de um módulo, um namespace de instância ou um namespace local de uma function).

Os namespaces são uma coleção de pares (nome, referência para o objeto), implementados usando dicionários.

Quando você chama uma função ou um método, o namespace (da função/método) é inicializado com os argumentos que você usou para chamá-la(o) (os nomes são pegos da lista de argumentos da função, os objetos são os que você passou na chamada).

Atribuição

Instruções de atribuição modificam o namespace, não os objetos.

Em outras palavras,
name = 10
significa que você está adicionando o nome "name" ao seu namespace local e fazendo-o referenciar um objeto do tipo inteiro que contém o valor 10.

Se o nome já existir, a atribuição substitui o nome original:
name = 10
name = 20
significa que primeiro você está adicionando o nome "name" ao namespace local e fazendo-o referenciar um objeto do tipo inteiro que contém o valor 10. Depois, você está substituindo o nome, fazendo-o apontar para um objeto inteiro que contém o valor 20. O objeto "10" original não é afetado por essa operação, e nem se importa com isso.

[Nota do tradutor] Para comprovar essa afirmação, abra o shell do Python e escreva as linhas abaixo. Note que o id(a) será igual ao id(b):
>>> a = 10
>>> print id(a)
675432
>>> a = 20
>>> print id(a)
120987
>>> b = 10
>>> print id(b)
675432 

Em constraste, se você fizer:
name = []
name.append(1)
primeiro, você está adicionando o nome "name" ao namespace local e fazendo-o referenciar um objeto do tipo lista, que está vazio. Isso modifica o namespace. Então, você chama um método do objeto (append()), dizendo para acrescentar um objeto inteiro a ele, que tem o valor 1. Isso modifica o conteúdo do objeto lista, mas não toca no namespace, nem no objeto inteiro.

Coisas como name.attr e name[index] são apenas embelezamento sintático para chamadas de métodos. O primeiro corresponde aos __setattr__() / __getattr__(), e o segundo aos __setitem__() / __getitem__() (dependendo de que lado da atribuição eles aparecem).

É isso.

[Nota do tradutor] Para um exemplo de como listas e dicionários se comportam, leia Como copiar uma lista e um dicionário em Python.

Eu sou Vinicius Assef, um programador do século passado que gosta de Python, pratica Lean Development e acredita em Deus. Você pode me contactar por email ou twitter.

2 comentários:

Marcadores