SignificadoDoSelf

Significado de ''self'' em Python

Um dos aspectos mais incompreendidos de Python é a declaração do argumento self para métodos. Esse texto tentará apresentar uma explicação baseada em funções. Pressupomos que o leitor já conheça a linguagem e saiba como definir funções em Python.

Versão PDF

Classes, funções e métodos

Para compreender o sentido do parâmetro self, temos de entender o que é uma classe. Uma classe é um "modelo" para diversos valores, que são chamados objetos. Definir classes é bem simples, e nem precisamos fazer algo em sua definição. Por exemplo, a classe Person abaixo, que usaremos para representar pessoas, é definida sem nenhum comando significante dentro dela, exceto o comando pass, que informa que nada será feito além de definir a classe.

   1 class Person(object):
   2     pass

Definição simples de classe

A definição de classe não faz nada além de dizer que existe a classe Person. Para executarmos operações nessa classe, precisamos definir funções que atuem sobre ela. Por exemplo, funções que armazenem o nome da pessoa:

   1 class Person(object):
   2     pass
   3 
   4 def set_name(person, name):
   5     # Não aceita nomes com menos de duas letras
   6     if len(name) >= 2:
   7         person.name = name
   8 
   9 woman = Person()
  10 set_name(woman, 'Juliana')
  11 
  12 # Vai imprimir "Juliana"
  13 print woman.name
  14 
  15 # Não vai mudar o valor, pois len('J') < 2
  16 set_name(woman, 'J')
  17 
  18 # Vai imprimir "Juliana" de novo, pois não mudou o valor
  19 print woman.name

Definição de classe e função

Acima, definimos a função set_name que armazena o nome da pessoa num objeto da classe Person.

Por uma questão de praticidade, é tradição declarar as funções que operam sobre uma classe dentro da própria classe. Uma vez que a função foi declarada dentro da classe, toda vez que a função for chamada o nome da classe deve vir antes; isto é, chamar uma função declarada dentro de uma classe é como chamá-la de um módulo.

No código abaixo, declaramos a função dentro da classe, ao invés de ficar do lado de fora. A vantagem de fazer isso é que o código que altera a classe fica mais próximo da definição, ficando mais separado e legível. Depois, é só chamar o nome da classe seguido do nome da função que ele executa. É como se a função fosse um valor da classe.

   1 class Person(object):
   2     def set_name(person, name):
   3         if len(name) >= 2:
   4             person.name = name
   5 
   6 woman = Person()
   7 
   8 # Nome da classe deve vir antes do uso da função, pois
   9 # a função está dentro da classe.
  10 Person.set_name(woman, 'Juliana')
  11 
  12 # Vai imprimir "Juliana"
  13 print woman.name

Função dentro da classe

Entretanto, embora essa notação possa ser muito útil, ficar digitando o nome da classe pode ser bem entediante. Certamente é redundante, pois todo objeto sabe a qual classe pertence. Desse modo, tiveram a idéia de, ao invés de preceder o nome da função com o nome da classe, precedê-lo com o objeto que é o primeiro parâmetro. Obviamente, não faz sentido usar o nome do objeto antes do nome da função e depois como parâmetro, como woman.set_name(woman, 'Juliana') . Se o nome do objeto já está lá antes do nome da função, ele deve ser retirado da lista de parâmetros, como no código do objeto antes da função (abaixo).

Essas "funções dentro de classes" são chamadas de métodos. Para chamar métodos, tanto faz chamá-los como em Classe.metodo(objeto, parametros) quanto chamá-los como em objeto.metodo(parametros)

As formas são equivalentes, com apenas uma ressalva: objeto deve ser um objeto da classe Classe. Por sinal, mesmo a primeira notação Classe.metodo(objeto, parametros) resultaria em erro se objeto não fosse um objeto da classe Classe.

   1 class Person(object):
   2     def set_name(person, name):
   3         if len(name) >= 2:
   4             person.name = name
   5 
   6 woman = Person()
   7 woman.set_name('Juliana')
   8 print woman.name

Objeto antes da função

O nome ''self''

No método Person.set_name acima, o nome do primeiro parâmetro do método era person. Entretanto, é tradição chamar esse primeiro parâmetro de self. Por quê?

Bem, não há nenhuma obrigatoriedade de se fazer assim -- tanto o é que em nosso método usamos outro nome para o parâmetro. Costuma-se chamar o primeiro parâmetro de self porque a maioria dos programadores Python já reconhece esse nome como o nome do objeto a ser invocado no método; ademais, esse é o padrão especificado pela PEP-8. Por isso mesmo, via de regra é melhor utilizar self como o nome do primeiro parâmetro dos métodos.

   1 class Person(object):
   2     def set_name(self, name):
   3         if len(name) >= 2:
   4             self.name = name
   5 
   6 woman = Person()
   7 woman.set_name('Juliana')
   8 print woman.name

Uso do nome self

Em outras linguagens orientadas a objetos, o parâmetro correspondente ao self geralmente não é declarado na lista de parâmetros, mas sim passado implicitamente. Nessas linguagens, a assinatura do método set_name seria mais como

   1 def set_name(nome)

que como

   1 def set_name(self, nome)

Aplicações

O self explícito é uma característica polêmica da linguagem Python, mas há diversas razões em favor do seu uso.

O argumento mais comum -- e provavelmente o mais subjetivo -- é que o self explícito está mais de acordo com o espírito da linguagem que um self implícito, já que, como diria o Zen of Python, explícito é melhor que implícito. Também argumenta-se que a declaração explícita do self é, hoje em dia, tão intrínseca à linguagem que seria praticamente inviável abandoná-la.

O self explícito tem, também, várias vantagens na prática quotidiana. Uma das mais notáveis é a habilidade de chamar métodos de classes ancestrais sobre objetos de classes herdadas. Por exemplo, voltando ao nosso exemplo com pessoas, suponhamos que definamos uma nova classe CapitalizedPerson, herdeira de Person, na qual o nome da pessoa deve começar com uma letra maiúscula. Nessa classe, também queremos que todas as restrições que o método set_name da classe Person ainda sejam seguidas. Como fazer?

   1 import string
   2 
   3 class CapitalizedPerson(Person):
   4     def set_name(self, name):
   5         if name[0] in string.uppercase:
   6             Person.set_name(self, name)
   7 
   8 woman = Person()
   9 woman.set_name('Juliana')
  10 print woman.name

Chamando métodos de classes ancestrais

Em Python, é bem simples: basta usar a notação de chamada de método na forma Classe.metodo(self, parametros) ou, mais especificamente, Person.set_name(self, name), conforme demostrado no código acima. Note que, se fizermos uma outra classe herdando de CapitalizedPerson e não queiramos usar o método set_name de CapitalizedPerson, podemos chamar diretamente o método set_name da classe Person. Essa é, provavelmente, uma solução bem mais elegante que o famoso objeto super de várias linguagens; certamente, é mais explícita e flexível.

Como Python suporta herança múltipla, essa funcionalidade pode se tornar indispensável. Suponha uma classe que herde, ao mesmo tempo, de duas classes. Para inicializar essa classe com o método inicializador de cada uma de suas classes-mães, basta chamar o método init de cada uma das classes, como no código:

   1 class ButtonPerson(Button, Person):
   2     """Uma pessoa que é um botão(?!)"""
   3     def __init__(self, name):
   4         Person.__init__(self)
   5         Button.__init__(self, "Pessoa: " + name)
   6         self.set_name(name)

Múltipla inicialização

Conclusão

O self explícito de Python é uma decisão de projeto polêmica. Entretanto, há inúmeras vantagens oriundas dela, como o caráter explícito da decisão e a maior flexibilidade na chamada de métodos. Suspeito até que o self explícito torne mais fácil a apreensão do conceito dos objetos self/this: se, por um lado, programadores oriundos de linguagens nas quais os objetos self ou this são implícitos sentem-se confusos com o self explícito, programadores que não estão acostumados com esse conceito parecem apreender melhor a idéia quando apresentados à "maneira pythônica" de se tratar do conceito.

SignificadoDoSelf (editada pela última vez em 2008-12-19 12:20:50 por AdamVictorNazarethBrandizzi)