Um programador PHP entendendo Pyhton

Pro resto do mundo, Python é uma linguagem fácil de assimilar. Pro resto do mundo. Pra mim é algo muito novo, bem distante do C++, e tenho tido certa dificuldade. Por isso decidi começar a escrever mais sobre o Python e aprender a usar isso aí.

Uma classe pra chamar de minha

Uma classe é basicamente um um conjunto de métodos e propriedades. A classe costuma representar algo no mundo real, como, por exemplo, um interruptor. Se eu quiser criar, em PHP, uma classe para tratar um interruptor, vai ficar semelhante a isso:

<?php
  class Interruptor {
    $estado;
    function __construct($estadoInicial = 'desligado') {
      $this->estado = $estadoInicial;
    }
    function lerEstado() {
      return $this->estado;
    }
    function alterarEstado() {
      if($this->estado == 'desligado') {
        $this->estado = 'ligado';
      } else {
        $this->estado = 'desligado';
      }
    }

Agora eu posso criar um interruptor:

<?php
  include "Interruptor.class.php"
  $rup = new Interruptor();

... ler o seu estado...
echo $rup->lerEstado();

... e alterá-lo...
$rup->alterarEstado();

Pois bem. Agora preciso criar um interruptor desses em Python. Vai ficar assim:

class Interruptor:
  def __init__(self, estado_inicial = 'desligado'):
    self.estado = estado_inicial 
  def lerEstado(self):
    return self.estado 
  def alterarEstado(self):
    if self.estado == 'desligado':
      self.estado = 'ligado'
    else:
      self.estado = 'desligado'

Para usar a classe (perceba que ">>>" indica que dei o comando diretamente no shell do Python):

>>> from Interruptor import Interruptor
>>> rup = Interruptor()
>>> print(rup.lerEstado())
Desligado
>>> rup.alterarEstado()
>>> print(rup.lerEstado())
Ligado

Diferenças

- A primeira diferença, de cara, é o "self". No PHP, "self" já é subentendido, não precisa ser declarado. Ele será acessado sempre que for necessário usando "$this", para propriedades, ou "self::", para métodos.
- O método construtor de uma classe Python é o __init__.
- Mesmo que um método não receba parâmetro algum, é preciso que o "self" esteja lá.
- Os blocos são separados pela indentação do código. Em PHP, independente do código estar bem indentado ou não, os blocos ficam entre chaves. Note a diferença:

//PHP
if(true) {
  echo 'ok';
} else {
  echo 'not ok';
}

//Python
if True:
  print("ok")
else:
  print("not ok")

É uma maneira efetiva de forçar o aluno a escrever um código bem indentado, sob pena do programa não funcionar.
- Usar parênteses no teste lógico do "if" é opcional;
- Assim como a indentação determina um bloco de código, a mudança de linha indica o fim de uma sentença e o início da outra. Em PHP usamos o ponto-e-vírgula pra isso.
- Os métodos são identificados pela palavra "def", de definição. Em PHP usamos "function". Usar "def" economiza digitação. Somando todas as outras coisas que desaparece (';', '(', ')', '{', '}', etc.), acaba que fica menos custoso digitar um código Python, mas discordo com a maioria quando dizem que o código é mais legível.

Além do __init__

Em PHP temos os chamados "métodos mágicos". Alguns deles são o próprio __construct(), __get, __set, __toString(). O que se assemelha a isso em Python são os chamados "métodos especiais". O __init__ é equivalente ao __construct; o __str__ é equivalente ao __toString(), e por aí vai.

Equivalência entre PHP e Python: métodos especiais
Preciso...PHPPython
Inicializar o objeto__construct([$param(s)])__init__(self[,param(s)])
Transformar o objeto em texto__toString()__str__(self[,param(s)])
Tratar a chamada a um atributo__get($atributo)__getattr__(self, name)
Alterar o valor de um atributo__set($atributo, valor)__setattr__(self, name, value)

Entre outros. Na verdade existe uma infinidade de métodos especiais, e, honestamente, de todos os que conheço, nenhum é inútil. Python possui um número muito maior de "métodos mágicos" e o objetivo deles é fazer uma classe se comportar de modo extremamente compatível com o sistema. Por exemplo, veja a classe Interruptor com a adição de uma documentação básica.

class Interruptor(object):
  """Ativa/Desativa um interruptor qualquer"""
  def __init__(self, estado_inicial = 'desligado'):
    self.estado = estado_inicial   def lerEstado(self):
    return self.estado   def alterarEstado(self):
    if self.estado == 'desligado':
      self.estado = 'ligado'
    else:
      self.estado = 'desligado'

Agora se, após instanciado, eu chamar...

>>> rup.__doc__
'Ativa/Desativa um interruptor qualquer'

Obterei o texto da documentação da classe. Isso é bom. Posso documentar toda a classe usando esse recurso, o que livra qualquer um do trabalho de descobrir o que fiz quando a criei, quais métodos e propriedades existem, etc.

Conclusão

Estava com o pé atrás quando comecei a escrever esse artigo. Acontece que minhas classes nunca funcionavam e fiquei extremamente frustrado com isso. Também procurei aprender Python através de um livro que não teve a melhor tradução do mundo (Programação em Python 3 - Uma Introdução Completa à Linguagem Python. Não compre. Sério, não compre.). Depois eu aprendi que o problema estava na maneira como invoquei a classe. Assim não funciona:

>>> import Interruptor
>>> rup = Interruptor()
>>> rup.lerEstado()

Mas assim funciona:

>>> from Interruptor import Interruptor
>>> rup = Interruptor()
>>> rup.lerEstado()
'desligado'

E assim também:

>>> import Interruptor
>>> rup = Interruptor.Interruptor()
>>> rup.lerEstado()
'desligado'

Pois, no primeiro e no terceiro caso, import Interruptor importa apenas o arquivo, daí tenho que dizer qual classe desse arquivo quero instanciar. Posso fazer isso com Interruptor.Interruptor ou, quando importar o arquivo, pegar só a classe que quero: from Interruptor import Interruptor.

Dessa maneira, passei a olhar o Python de um jeito mais interessado. Ele entrega muita coisa interessante, e, por isso talvez, ignorá-lo não seja mais uma opção.

Comentários

Postagens mais visitadas deste blog

Tá na hora de piscar LEDs de maneira melhorada

LEDs on/off com PHP, Python e RPi

PagSeguro e PHP - Usando a tela do PagSeguro (checkout redirect)