Distinção entre variáveis de classe e instância explicada.
Variáveis são essencialmente símbolos que representam um valor que estamos usando em um programa. A programação orientada a objetos permite que variáveis sejam usadas no nível de classe ou no nível de instância. O objectivo deste artigo é ter uma distinção clara entre os tipos de variáveis oferecidas pelo modelo de objectos Python e continuar a discutir um comportamento peculiar que pode levar a alguns resultados surpreendentes, se negligenciados. Então vamos cavar em!
Como por modelo objeto Python, há dois tipos de atributos de dados em objetos Python: variáveis de classe e variáveis de instância.
Class Variables – Declaradas dentro da definição de classe (mas fora de qualquer um dos métodos de instância). Elas não estão vinculadas a nenhum objeto em particular da classe, portanto compartilhadas entre todos os objetos da classe. Modificar uma variável de classe afeta todos os objetos da instância ao mesmo tempo.
Instance Variable – Declarada dentro do método construtor da classe (o método __init__
). Elas estão ligadas à instância de objeto particular da classe, portanto o conteúdo de uma variável de instância é completamente independente de uma instância de objeto para a outra.
Vamos começar com um exemplo curto e fácil de digerir:
class Car:
wheels = 4 # <- Class variable def __init__(self, name):
self.name = name # <- Instance variable
Acima está a classe Car Basic, no-frills definida. Cada instância dela terá rodas de variável de classe junto com o nome da variável de instância. Vamos instanciar a classe para acessar as variáveis.
>>> jag = Car('jaguar')
>>> fer = Car('ferrari')>>> jag.name, fer.name
('jaguar', 'ferrari')>>> jag.wheels, fer.wheels
(4, 4)>>> Car.wheels
4
Acessar o nome da variável da instância é bem direto. Entretanto, há um pouco mais de flexibilidade quando se trata de acessar a variável de classe. Como acima, podemos acessar wheels através da instância objeto ou da própria Classe.
Tambem tentar acessar o nome através da classe resultará em um AttributeError já que as variáveis da instância são específicas do objeto e são criadas quando __init__
construtor é invocado. Esta é a distinção central entre a classe e as variáveis da instância.
>>> Car.name
AttributeError: type object 'Car' has no attribute 'name'
Agora, vamos assumir por enquanto que o nosso carro Jaguar tem 3 rodas. (sim, é estúpido, mas aguenta!! 😅). Para representar isso no nosso código, podemos modificar a variável das rodas.
>>> Car.wheels = 3
O que fizemos acima irá fazer todos os carros com 3 rodas desde que modificamos uma variável de classe, que se aplicará a todas as instâncias da classe Car.
>>> jag.wheels, fer.wheels
(3, 3)
Por isso modificar uma variável de classe no namespace da classe afecta todas as instâncias da classe. Vamos reverter a alteração e modificar a variável wheels usando o objeto jag.
>>> Car.wheels = 4
>>> jag.wheels = 3
Isto nos dará a saída que desejamos.
>>> jag.wheels, fer.wheels, Car.wheels
(3, 4, 4)
Apesar de termos o resultado que queríamos, mas o que aconteceu nos bastidores é uma nova variável wheels que foi adicionada ao objeto jag e esta nova variável sombreia a variável de classe com o mesmo nome, sobrepondo-a e escondendo-a. Podemos aceder a ambas as variáveis do desdobramento como abaixo.
>>> jag.wheels, jag.__class__.wheels
(3, 4)
Hence podemos concluir que jag.wheels = 3
criou uma nova variável de instância com o mesmo nome da variável de classe (desdobramentos). Este é um conceito importante a ter em conta.
Fazer uso de variáveis específicas de classe e instância pode garantir que nosso código adere ao princípio DRY para reduzir a repetição dentro do código.
Saber isto pode ser muito útil e poupar muitas horas de depuração um dia. 😇
Refer a este post para ler mais sobre vários tipos de métodos (instância, classe & estática) em Python.
Conclusões
- Variáveis de classe são compartilhadas entre todos os objetos enquanto variáveis de instância são para dados únicos para cada instância.
- Variável de instância substitui as variáveis de classe com o mesmo nome, que podem acidentalmente introduzir bugs ou comportamento surpreendente em nosso código.