Commits

Francisco Souza committed d7af94e

Conclusão da tradução do Capítulo 14.

Comments (0)

Files changed (1)

edicao_1.1/capitulo_14.rst

       indice = indice + 1
     return -1
     
-Esta é a nova versão, melhorada:
+Esta é a nova versão, melhorada::
 
   def find(palavra, ch, inicio = 0):
     indice = inicio
       indice = indice + 1
     return -1
 
-O terceiro parâmetro, chamado ``inicio``, é opcional por possuir um valor padrão ``0``. Se invocarmos a nossa função ``find`` com apenas dois parâmetros, o valor padrão ``0`` será atribuído à variável ``inicio``, fazendo com que a busca inicie do começo da string informada.
+O terceiro parâmetro, chamado ``inicio``, é opcional por possuir um valor padrão ``0``. Se invocarmos a nossa função ``find`` com apenas dois parâmetros, o valor padrão ``0`` será atribuído à variável ``inicio``, fazendo com que a busca inicie do começo da string informada:
+
+  >>> find("banana", "n")
+  2
+
+Se passarmos o terceiro parâmetro, o valor padrão (``0``) será sobrescrito pelo valor informado:
+
+  >>> find("banana", "n", 3)
+  4
+  >>> find("banana", "n", 5)
+  -1
+  >>> find("banana", "n", 4)
+  4
+
+Observe de onde temos começado e como a função se desempenha.
+  
+  Como exercício, adicione um quarto parâmetro à função ``find`` chamado ``fim``. Este parâmetro deverá indicar onde a busca termina.
+
+  Atenção: Este exercício é um pouco complicado. O valor padrão de ``fim`` deve ser ``len(palavra)``, mas isso não funciona. Os valores padrão são atribuídos quando a função é declarada, não quando ela é chamada. Quando declaramos ``find``, ``palavra`` ainda não existe, então você não consegue encontrar o seu tamanho.
+
+------------------------------
+14.6 O método de inicialização
+------------------------------
+
+O **método de inicialização** é um método especial que é invocado quando um objeto é criado. O nome deste método é ``__init__`` (dois caracteres de *underscore*, seguidos por ``init``, e mais dois caracteres de *underscore*). Um método de inicialização para a classe ``Horario`` seria semelhante ao seguinte::
+
+  class Horario:
+    def __init__(self, horas = 0, minutos = 0, segundos = 0):
+      self.horas = horas
+      self.minutos = minutos
+      self.segundos = segundos
+      
+Não há conflitos entre o atributo ``self.horas`` e o parâmetro ``horas``. A notação do ponto especifica a qual variável estamos nos referindo.
+
+Quando chamamos o construtor de ``Horario``, os argumentos informados são passados para o método ``__init__``:
+
+  >>> horaAtual = Horario(9, 14, 30)
+  >>> horaAtual.imprimirHorario()
+  9:14:30
+  
+Como os parâmetros são opcionais, nós podemos omití-los:
+
+  >>> horaAtual = Horario()
+  >>> horaAtual.imprimirHorario()
+  0:0:0
+  
+Ou passarmos apenas o primeiro argumento:
+
+  >>> horaAtual = Horario(9)
+  >>> horaAtual.imprimirHorario()
+  9:0:0
+
+Ou os dois primeiros...
+
+  >>> horaAtual = Horario(9, 14)
+  >>> horaAtual.imprimirHorario()
+  9:14:0
+  
+Por fim, podemos fazer atribuições a um subconjunto de parâmetros informando-os explicitamente:
+
+  >>> horaAtual = Horario(segundos = 30, horas = 9)
+  >>> horaAtual.imprimirHorario()
+  9:0:30
+
+-----------------------------------
+14.7 Redefinindo a classe ``Ponto``
+-----------------------------------
+
+Vamos reescrever a classe ``Ponto`` da seção 12.1 em um estilo mais orientado a objetos::
+
+  class Ponto:
+    def __init__(self, x = 0, y = 0):
+      self.x = x
+      self.y = y
+    
+    def __str__(self):
+      return '(' + str(self.x) + ', ' + str(self.y) + ')'
+      
+O método de inicialização possui os parâmetros opcionais ``x`` e ``y``. O valor padrão para ambos é ``0``.
+
+O método seguinte, chamado ``__str__``, retorna uma string com a representação matemática de um ``Ponto``. Se uma classe implementa o método ``__str__``, este sobrescreve o comportamento padrão da função ``str`` provida pelo Python.
+
+  >>> p = Ponto(3, 4)
+  >>> str(p)
+  '(3, 4)'
+  
+Quando imprimimos um objeto ``Ponto``, o Python chama implicitamente o método ``__str__`` no objeto, então ao definirmos ``__str__``, mudamos também o comportamento do ``print``::
+
+  >>> p = Ponto(3, 4)
+  >>> print p
+  (3, 4)
+  
+Quando escrevemos uma nova classe, quase sempre começamos com o método ``__init__``, pois este facilita a instanciação de objetos, e o método ``__str__``, que quase sempre é muito útil para depuração.
+
+-----------------------------
+14.8 Sobrecarga de operadores
+-----------------------------
+
+Algumas linguagens de programação permitem que mudemos o comportamento de operadores comuns (\+, \-, \*, etc.) quando eles são aplicados a tipos definidos pelo usuário. Este recurso é chamado de **sobrecarga de operadores**. É algo extremamente vantajoso principalmente quando estamos definindo novos tipos matemáticos.
+
+Por exemplo, para sobrescrever o operadores de soma ``+``, devemos implementar um método chamado ``__add__``::
+
+  class Ponto:
+    # Métodos definidos previamente devem estar aqui!
+    
+    def __add__(self, other):
+      return Ponto(self.x + other.x, self.y + other.y)
+      
+Como já vimos anteriormente, o primeiro parâmetro é o objeto no qual o método foi invocado. O segundo parâmetro é chamado ``other`` por convenção, para distingui-lo de ``self``. Para somar dois objetos do tipo ``Ponto``, nós criamos e retornamos um novo ``Ponto`` que contém a soma das coordenadas ``x`` e a soma das coordenadas ``y``.
+
+Agora, quando aplicamos o operador de soma (``+``) para objetos do tipo ``Ponto``, o Python invoca o método ``__add__``:
+
+  >>> p1 = Ponto(3, 4)
+  >>> p2 = Ponto(5, 7)
+  >>> p3 = p1 + p2
+  >>> print p3
+  (8, 11)
+  
+A expressão ``p1 + p2`` é equivalente à expressão ``p1.__add__(p2)``, mas é muito mais elegante.
+
+  Como exercício, crie o método ``__sub__`` na classe ``Ponto``. Este método representa o operador de subtração. Após criar o método, teste-o.
+  
+Há algumas formas de substituir o comportamento do operador de multiplicação: implementando um método chamado ``__mul__``, ou ``__rmul__``, ou ambos os métodos.
+
+Se o membro da esquerda da multiplicação é um ``Ponto``, o método ``__mul__`` é invocado, que assumo que o outro membro da multiplicação também é um ``Ponto``. Este método calcula o **produto dos pontos**, definido de acordo com as regras da álgebra linear::
+
+  def __mul__(self, other):
+    return self.x * other.x + self.y * other.y
+
+Se o membro da esquerda da multiplicação é um tipo primitivo e o membro da direita é um ``Ponto``, o método ``__rmul__`` é invocado. Este método calcula a **multiplicação escalar**::
+
+  def __rmul__(self, other):
+    return Ponto(other * self.x, other * self.y)
+
+O resultado é um novo ``Ponto`` onde as coordenadas são múltiplos das coordenadas originais. Se o parâmetro ``other`` pertencer a um tipo que não pode ser multiplicado por um número de ponto flutuante (``float``), o método ``__rmul__`` produzirá um erro.
+
+O exemplo a seguir demonstra os dois tipos de multiplicação:
+
+  >>> p1 = Ponto(3, 4)
+  >>> p2 = Ponto(5, 7)
+  >>> print p1 * p2
+  43
+  >>> print 2 * p2
+  (10, 14)
+  
+O que acontece se tentarmos executar a expressão ``p2 * 2``? Como o primeiro operador é um ``Ponto``, o método ``__mul__`` será invocado, o programa tentará acessar a coordenada ``x`` do objeto ``other``, mas esta operação falhará por que um inteiro não tem atributos:
+
+  >>> print p2 * 2
+  AttributeError: 'int' object has no attribute 'x'
+  
+Infelizmente, a mensagem de erro é um pouco sombria. Este exemplo apresentou uma das dificuldades da programação orientada a objetos. Às vezes é difícil até para descobrirmos o que está acontecendo no código executado.
+
+Se você deseja um exemplo mais completo de sobrecarga de operadores, dê uma conferida no **Apêndice B**.
+
+-----------------
+14.9 Polimorfismo
+-----------------
+
+Muitos dos métodos que escrevemos tratam apenas um tipo específico de dados para cada parâmetro. Quando você cria um novo objeto, você cria métodos que trabalham com estes tipos.
+
+Mas existem algumas operações onde você vai querer usar vários tipos, como as operações aritméticas da seção anterior. Se vários tipos dão suporte a um mesmo conjunto de operações, você pode escrever funções que trabalham com qualquer um desses tipos.
+
+Por exemplo, a função ``multiplicaSoma`` (que é muito comum na álgebra linear) recebe três argumentos: ela multiplica os dois primeiros argumentos e soma o terceiro ao resultado da multiplicação. Podemos escrever isso em Python da seguinte forma::
+
+  def multiplicaSoma(x, y, z):
+    return x * y + z
+
+Esta função funcionará com qualquer valores de ``x`` e ``y`` que possam ser multiplicados entre si e com qualquer valor de ``z`` que possa ser somado ao produto.
+
+Podemos chamar a função com valores numéricos:
+
+  >>> multiplicaSoma(3, 2, 1)
+  7
+  
+Ou com objetos do tipo ``Ponto``:
+
+  >>> p1 = Ponto(3, 4)
+  >>> p2 = Ponto(5, 7)
+  >>> print multiplicaSoma(2, p1, p2)
+  (11, 15)
+  >>> print multiplicaSoma(p1, p2, 1)
+  44
+  
+No primeiro caso, o ``Ponto`` é multiplicado de forma escalar e somado a outro ``Ponto``. No segundo caso, o produtos dos pontos gera um valor numérico, então o terceiro parâmetro também tem que ser um valor numérico.
+
+Uma função como esta que pode tratar argumentos de diferentes tipos é chamada de **função polimórfica**.
+
+Como outro exemplo, considere o método ``normalInvertida``, que imprime uma lista duas vezes: do início ao fim e do fim ao início::
+
+  def normalInvertida(normal):
+    import copy
+    invertida = copy.copy(normal)
+    invertida.reverse()
+    print str(normal) + str(invertida)
+
+Dado o fato que o método ``reverse`` é um modificador, criamos uma cópia da lista antes de invertê-la. Desta forma, o método não modifica a lista passada por parâmetro.
+
+Segue um exemplo que usa ``normalInvertida`` em uma lista:
+
+  >>> minhaLista = [1, 2, 3, 4]
+  >>> normalInvertida(minhaLista)
+  [1, 2, 3, 4][4, 3, 2, 1]
+  
+Como projetamos a função pensando em usá-la com listas, não há surpresas em ver que ela funciona normalmente com listas. Ficaríamos surpresos ao descobrirmos que a função funciona também com objetos do tipo ``Ponto``.
+
+Para determinarmos se uma função pode ser aplicada a um tipo qualquer, nós verificamos a regra fundamental do polimorfismo:
+
+  **Se todas as operações internas da função podem ser aplicados ao tipo, a função pode ser aplicada ao tipo.**
+
+As operações na função ``normalInvertida`` são ``copy``, ``reverse`` e ``print``.
+
+A função ``copy`` funciona em qualquer objeto, e nós já definimos o método ``__str__`` que permite que o ``print`` funcione sobre o objeto ``Ponto``. Então precisamos escrever apenas o método ``reverse`` na nossa classe ``Ponto``:
+
+  class Ponto:
+    # Métodos definidos previamente devem estar aqui!
+    
+    def reverse(self):
+      self.x, self.y = self.y, self.x
+      
+Agora podemos passar um ``Ponto`` para a função ``normalInvertida``:
+
+  >>> p = Ponto(3, 4)
+  >>> normalInvertida(p)
+  (3, 4)(4, 3)
+  
+A melhor parte do polimorfismo é a parte sem intenção, onde você descobre que uma função que você já escreveu pode ser aplicada a um tipo sem que você tenha planejado isso.
 
 ----------------
 14.10 Glossário
 ----------------
 
+função polimórfica
+    Uma função que pode operar com mais de um tipo. Se todas as operações de uma função pode ser aplicadas a um certo tipo, então a função pode ser aplicada a este tipo.
+
 linguagem orientada a objetos
     Uma linguagem que provê características tais como classes definidas pelo usuário e herança, que facilitam a programação orientada a objetos.
 
+método
+    Uma função que é definida dentro de uma definição de classe e é chamada em instâncias desta classe.
+
+método de inicialização (tambem chamado de construtor)
+    Um método especial que é invocado automaticamente quando um novo objeto é criado e que inicializa os atributos deste objeto.
+
+multiplicação escalar
+    Operação definida na álgebra linear que multiplica cada uma das coordenadas de um ponto por um valor numérico.
+
+*override*
+    Substituir uma definição já pronta. Exemplos incluem substituir um parâmetro padrão por um argumento particular e substituir um método padrão, fornecendo um novo método com o mesmo nome.
+
+produto de pontos
+    Operação definida na álgebra linear que multiplica dois pontos (com coordenadas (x,y)) e retorna um valor            numérico.
+
 programação orientada a objetos
     Um estilo de programação na qual os dados e as operações que os manipulam estão organizados em classes e métodos.
 
-método
-    Uma função que é definida dentro de uma definição de classe e é chamada em instâncias desta classe.
-
-override (sem traducao; termo consagrado)
-    Substituir uma definição já pronta. Exemplos incluem substituir um parâmetro padrão por um argumento particular e substituir um método padrão, fornecendo um novo método com o mesmo nome.
-
-método de inicialização (tambem chamado de construtor)
-    Um método especial que é invocado automaticamente quando um novo objeto é criado e que inicializa os atributos deste objeto.
-
 sobrecarga de operador
     Estender a funcionalidade dos operadores nativos (\+, \-, \*, \>, \<, etc.) de forma que eles funcionem também com tipos definidos pelo usuário.
-
-produto escalar
-    Operação definida na álgebra linear que multiplica dois pontos (com coordenadas (x,y,z)) e retorna um valor            numérico.
-
-multiplicação por escalar
-    Operação definida na álgebra linear que multiplica cada uma das coordenadas de um ponto por um valor numérico.
-
-polimórfica
-    Uma função que pode operar com mais de um tipo. Se todas as operações de uma função pode ser aplicadas a um certo tipo, então a função pode ser aplicada a este tipo.
-    
-