4.2 Objetos, classes e instâncias

Objetos são a unidade fundamental de qualquer sistema orientado a objetos. Em Python, como introduzido na seção 2.3.2, tudo é um objeto -- tipos, valores, classes, funções, métodos e, é claro, instâncias: todos possuem atributos e métodos associados. Nesta seção serão descritas as estruturas da linguagem para suportar objetos definidos pelo programador.

4.2.0.1 Classes

Em Python, a estrutura fundamental para definir novos objetos é a classe. Uma classe é definida em código-fonte, e possui nome, um conjunto de atributos e métodos.

Por exemplo, em um programa que manipula formas geométricas, seria possível conceber uma classe denominada Retangulo:

Um exemplo de uma implementação possível desta classe está no módulo retangulo.py a seguir:

    class Retangulo:
        lado_a = None
        lado_b = None

        def __init__(self, lado_a, lado_b):
            self.lado_a = lado_a
            self.lado_b = lado_b
            print "Criando nova instância Retangulo"

        def calcula_area(self):
            return self.lado_a * self.lado_b

        def calcula perímetro(self):
            return 2 * self.lado_a + 2 * self.lado_b

Esta classe define os dois atributos descritos acima, e três métodos. Os três métodos definidos incluem sempre, como primeiro argumento, uma variável denominada self, que é manipulada no interior do método. Este é um ponto fundamental da sintaxe Python para métodos: o primeiro argumento é especial, e convenciona-se utilizar o nome self para ele; logo a seguir será discutido para que existe.

Dois dos métodos codificados correspondem às operações descritas inicialmente, e há um método especial incluído: __init__(). O nome deste método tem significância particular em Python: é o método construtor, um método opcional invocado quando a classe é instanciada, que é o nome dado à ação de criar objetos a partir de uma classe.

4.2.0.2 Instâncias

A instância é objeto criado com base em uma classe definida. Este conceito é peculiar, e leva algum tempo para se fixar. Uma descrição abstrata da dualidade classe-instância: a classe é apenas uma matriz, que especifica objetos, mas que não pode ser utilizada diretamente; a instância representa o objeto concretizado a partir de uma classe. Eu costumo dizer que a classe é `morta', existindo apenas no código-fonte, e que a instância é `viva', porque durante a execução do programa são as instâncias que de fato `funcionam' através da invocação de métodos e manipulação de atributos.

Conceitualmente, a instância possui duas propriedades fundamentais: a classe a partir da qual foi criada, que define suas propriedades e métodos padrão, e um estado, que representa o conjunto de valores das propriedades e métodos definidos naquela instância específica. A instância possui um ciclo de vida: é criada (e neste momento seu construtor é invocado), manipulada conforme necessário, e destruída quando não for mais útil para o programa. O estado da instância evolui ao longo do seu ciclo de vida: seus atributos são definidos e têm seu valor alterado através de seus métodos e de manipulação realizada por outros objetos.

O que Python chama de `instância' é freqüentemente denominado `objeto' em outras linguagens, o que cria alguma confusão uma vez que qualquer dado em Python pode ser considerado um `objeto'. Em Python, instâncias são objetos criados a partir de uma classe definida pelo programador.

Retomando o nosso exemplo acima: a partir da classe Retangulo que foi definida, poderíamos instanciar objetos retângulo específicos: um com lados de comprimento 1 e 2, e outro com lados de comprimento 2 e 3:

    >>> from retangulo import Retangulo
    >>> r1 = Retangulo(1, 2)
    Criando nova instância Retângulo
    >>> r2 = Retangulo(2, 3)
    Criando nova instância Retângulo

Observe que ao instanciar o retângulo:

Aqui cabe uma pausa para revelar o propósito da variável self, definida como primeiro argumento dos métodos. Esta variável representa a instância sobre a qual aquele método foi invocado. Esta propriedade é de importância fundamental para OO em Python, porque através desta variável é que atributos e métodos desta instância podem ser manipulados no código dos seus métodos.

Continuando com a análise do bloco de código acima:

Uma vez instanciados os retângulos, podemos acessar seus métodos. De maneira idêntica aos métodos da lista apresentados na seção 2.3.2, a sintaxe utiliza um ponto seguido do nome do método acompanhado de parênteses:

    >>> print r1.calcula_area()
    2
    >>> print r2.calcula_perimetro()
    10

Conforme esperado, as funções retornaram os valores apropriados para cada instância. Fazendo mais uma demonstração do uso do argumento self, vamos observar o código de um dos métodos:

    def calcula_area(self):
        return self.lado_a * self.lado_b

O onipresente argumento self aqui é utilizado como meio de acesso aos atributos lado_a e lado_b. Este código permite visualizar o funcionamento pleno deste mecanismo: ao ser invocado o método calcula_area sobre a instância r1, o argumento self assume como valor esta mesma instância; portanto, acessar atributos de self internamente ao método equivale, na prática, a acessar atributos de r1 externamente.

Em Python é possível, inclusive, acessar os atributos da instância diretamente, sem a necessidade de usar um método:

    >>> print r1.lado_a
    1
    >>> print r1.lado_b
    2

Os valores, logicamente, correspondem aos inicialmente fornecidos à instância por meio do seu construtor.

4.2.0.3 Atributos Privados e Protegidos

Algumas linguagens permitem restringir acesso aos atributos de uma instância, oferecendo o conceito de variável privada. Python não possui uma construção sintática literalmente equivalente, mas existem duas formas de indicar que um atributo não deve ser acessado externamente:


Subsecções