Objetos em Python

Classes em Python

O código a seguir ilustra uma classe muito simples representada em Python:

class Pessoa:
    pass

A sintaxe para a definição de uma classe é: class <classe>: onde:

  • class é a palavra do Python que indica a definição de uma classe
  • <classe> é o nome da classe
  • : representa o terminador

Simples assim: o código cria a definição da classe Pessoa.

O conteúdo da classe é representado na sequência, como um código Python convencional, usando "tab" para indentação. Como essa classe não faz coisa alguma usamos apenas a palavra pass.

Instanciação

Para criar um objeto a partir da classe usamos o processo de instanciação, que significa a criação de um objeto a partir de uma classe. O trecho de código a seguir ilustra esse processo, considerando a classe Pessoa.

jose = Pessoa()
maria = Pessoa()

A sintaxe para instanciação é: <identificador> = <classe>() onde:

  • <identificador> é o nome do objeto, como o nome de uma variável (ex.: jose)
  • =
  • <classe> é o nome da classe (ex.: Pessoa)
  • ()

Parece com a chamada de uma função, mas o nome é de uma classe, por isso o Python entende o que deve fazer. O exemplo mostra como são criados dois objetos, jose e maria, ambos instâncias da classe Pessoa.

Como o Python representa objetos? Quando um código imprime um valor str vemos os caracteres. Quando imprime um objeto vemos um endereço de memória. Veja:

>>> print(jose)
<__main__.Pessoa object at 0x00000246389AB048>
>>> print(maria)
<__main__.Pessoa object at 0x00000246389AB198>

A saída da execução desse código (no terminal interativo do Python) demonstra que os endereços de memória são representados como números hexadecimais.

Trabalhando com atributos

A classe Pessoa não representa muita coisa até agora, ela não contém dados ou comportamentos. Como adicionamos dados ao objeto? Em Python não é necessário definir um atributo na classe para que ele esteja disponível no objeto. Na verdade, podemos definir atributos diretamente em um objeto (sem definir na classe) usando a notação ponto, como demonstra o código a seguir:

class Pessoa():
    pass

jose = Pessoa()
maria = Pessoa()

jose.nome = 'José'
maria.nome = 'Maria'
maria.idade = 20

print('jose.nome =', jose.nome)
print('maria.nome =', maria.nome)
print('maria.idade =', maria.idade)

A saída da execução do código seria:

jose.nome = José
maria.nome = Maria
maria.idade = 20

A sintaxe para criar um atributo em um objeto e definir seu valor usando a notação ponto é: <objeto>.<atributo> = <valor> onde:

  • <objeto> é o identificador, nome do objeto
  • .
  • <atributo> é o identificador, nome do atributo
  • =
  • <valor> é o valor armazenado no atributo

Entretanto, essa não é uma boa prática de projeto orientado a objeto. Como já vimos, a classe é quem determina as características de um objeto, então os atributos devem ser declarados na classe, não no objeto, caso contrário podemos ter objetos da mesma classe, mas com estruturas diferentes. Vamos ver como resolver isso daqui a pouco ao tratar sobre o método construtor.

Trabalhando com métodos

Já sabemos que enquanto os atributos definem dados os métodos definem comportamentos. Para representar métodos em Python usamos uma sintaxe semelhante à de uma função, com algumas diferenças:

  • o método deve ser declarado no contexto da classe
  • o método deve ter, obrigatoriamente, o parâmetro self

Para ilustrar isso, vamos declarar o método falar na classe Pessoa:

class Pessoa:
    def falar(self):
        pass

A sintaxe é: def <método>(<parâmetros>): onde:

  • def é a palavra Python para declarar o método
  • <método> é o nome do método
  • (
  • <parâmetros> é uma lista de parâmetros (mais sobre isso daqui a pouco)
  • )
  • :

O conteúdo do método vem logo na sequência, como uma função. No caso do exemplo, o método é inútil (seu conteúdo é apenas pass).

Uma das coisas mais legais de trabalhar com métodos é que isso permite entender melhor o conceito de mensagens, visto anteriormente. Veja o código a seguir:

jose = Pessoa()
maria = Pessoa()

jose.falar()
maria.falar()

O código declara duas instâncias de Pessoa. Por fim, usando notação ponto, indica que deve passada uma mensagem para cada objeto. Para isso, usa a sintaxe: <objeto>.<método>() onde:

  • <objeto> é o identificador do objeto
  • .
  • <método> é o identificador do método
  • ()

Pronto. Passar uma mensagem para um objeto significa chamar um método dele. O código ilustra a passagem de mensagem para dois objetos, jose e maria. Perceba que sempre é necessário indicar para qual objeto deve ser passada a mensagem. Em outras palavras, sempre é necessário indicar o objeto e o método a ser chamado.

A UML fornece o Diagrama de Sequência, uma forma gráfica de demonstrar a interação entre usuário do sistema e objetos ou camadas. A figura a seguir demonstra a utilização do Diagrama de Sequência nesse contexto.

O Diagrama de Sequência demonstra os passos:

  • o Usuário interage com Main (o programa principal)
  • Main interage com o objeto jose, do tipo Pessoa, enviando a mensagem falar('oi')
  • o objeto jose trata, executa a mensagem e retorna para Main
  • Main apresenta a mensagem para o Usuário

Esse procedimento se repete para o objeto maria.

Métodos com parâmetros

O método falar, como já vimos, é bem inútil. Para adicionar algo mais significativo considere que o objetivo do método é implementar o requisito:

Uma pessoa deve falar uma mensagem.

Para implementar isso vamos utilizar parâmetros. Veja o código:

class Pessoa:
    def falar(self, mensagem):
        print(mensagem)

A sintaxe para definição do método não muda, mas agora ele possui dois parâmetros:

  • self (obrigatório por causa da sintaxe de definição de método em Python)
  • mensagem: a mensagem que será impressa

De fato, porque self é obrigatório, daqui para frente não vamos ficar falando isso, ou seja, é implícito.

A definição do método falar faz com que a passagem de mensagem, a chamada do método seja diferente. Veja:

jose = Pessoa()
maria = Pessoa()

jose.falar('Oi, eu sou o José')
maria.falar('Oieee! Eu sou a Maria :*')

A saída da execução mostra a mensagem falada por cada pessoa.

Método construtor

Para declarar atributos na classe podemos utilizar um construtor, um método especial que inicializa o objeto e define a sua estrutura (seus atributos) durante o processo de instanciação. No Python o construtor é chamado __init__ e podemos utilizá-lo como ilustra o código a seguir.

class Pessoa:
    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

Os parâmetros do construtor são:

  • nome: representa o nome da pessoa
  • idade: representa a idade da pessoa

Perceba que o código do construtor utiliza uma estrutura importante: self.nome = nome onde self é a palavra Python que representa uma referência para o objeto atual e a instrução significa, especificamente, armazenar o valor do parâmetro nome no atributo nome do objeto. Por "objeto atual" quero dizer aquele que está no contexto da execução do código. Veja o código a seguir:

jose = Pessoa('jose', 1)

Neste momento é chamado o construtor e self é uma referência para o objeto jose, ou seja, outro identificador utilizado para acessar o mesmo objeto. Lembra do endereço de memória? Olha só:

jose = Pessoa()
maria = jose

print(jose)
print(maria)

A saída da execução do código seria algo como:

>>> print(jose)
<__main__.Pessoa object at 0x000002B0F101B080>
>>> print(maria)
<__main__.Pessoa object at 0x000002B0F101B080>

Percebeu que os endereços de memória são os mesmos? Por isso podemos entender que a atribuição maria = jose não pode ser entendida como armazena o valor de jose em maria, mas armazena em maria o mesmo endereço de memória de jose.

O que acontece com a saída do código a seguir?

jose = Pessoa()
jose.nome = 'José'
maria = jose
maria.nome = 'Maria'

print(jose.nome)
print(maria.nome)

Referências são utilizadas em linguagens de programação orientadas a objetos para muito mais coisas que construtores. Vamos continuar vendo sobre esse assunto mais adiante.

A utilização do construtor dessa forma modifica a instanciação. Veja:

jose = Pessoa('José', 21)
maria = Pessoa('Maria', 19)

Assim, temos uma nova leitura para sintaxe da instanciação: <identificador> = <classe>(<argumentos>) onde:

  • <identificador> é o nome do objeto, como o nome de uma variável (ex.: jose)
  • =
  • <classe> é o nome da classe (ex.: Pessoa)
  • (
  • <argumentos>: representa a lista de argumentos, conforme a definição do construtor
  • )

results matching ""

    No results matching ""