@@ -328,7 +328,7 @@ Dados esses requisitos básicos, podemos implementar `+__add__+` como no
328328====
329329[source, python]
330330----
331- # inside the Vector class
331+ # dentro da classe Vector
332332
333333 def __add__(self, other):
334334 pairs = itertools.zip_longest(self, other, fillvalue=0.0) # <1>
@@ -464,7 +464,7 @@ A implementação viável mais simples de `+__radd__+` aparece no <<ex_vector_ad
464464====
465465[source, python]
466466----
467- # inside the Vector class
467+ # dentro da classe Vector
468468
469469 def __add__(self, other): # <1>
470470 pairs = itertools.zip_longest(self, other, fillvalue=0.0)
@@ -605,11 +605,12 @@ Vector([11.0, 22.0, 33.0])
605605[NOTE]
606606====
607607
608- Outro tipo de multiplicação envolvendo operandos de `Vector` é o produto escalar
609- de dois vetores (_dot product_). O resultado de um produto escalar é um número
610- escalar, e não um vetor. É como uma multiplicação de matrizes, se tomarmos um
608+ Outro tipo de multiplicação envolvendo vetores é o produto escalar
609+ (_dot product_). Os operandos de um produto escalar são dois vetores,
610+ e o resultado é um número escalar (não um vetor).
611+ É como uma multiplicação de matrizes, considerando um
611612vetor como uma matriz de 1 × N e o outro como uma matriz de N × 1.
612- Vamos implementar este operador em nossa classe `Vector` na
613+ Implementaremos o produto escalar em `Vector` na
613614<<matmul_operator_sec>>.
614615
615616====
@@ -619,23 +620,23 @@ Voltando à nossa multiplicação por escalar, começamos novamente com os méto
619620
620621[source, python]
621622----
622- # inside the Vector class
623+ # dentro da classe Vector
623624
624625 def __mul__(self, scalar):
625626 return Vector(n * scalar for n in self)
626627
627- __rmul__(self, scalar):
628+ def __rmul__(self, scalar):
628629 return self * scalar
629630----
630631
631- Estes métodos funcionam, exceto quando recebem operandos incompatíveis. O
632- argumento `scalar` precisa ser um número que, quando multiplicado por um
633- `float`, produz outro `float` (porque nossa classe `Vector` usa, internamente,
634- um `array` de números de ponto flutuante). Então um número `complex` não serve,
635- mas o escalar pode ser um `int`, um `bool` (porque `bool` é subclasse de `int`)
636- ou mesmo uma instância de `fractions.Fraction`. No <<ex_vector_v7>>, o método
637- `+__mul__+` não faz qualquer checagem de tipos explícita com `scalar`. Em vez
638- disso, o converte em um `float`, e devolve `NotImplemented` se a conversão
632+ Estes métodos funcionam, exceto quando recebem operandos incompatíveis. +
633+ O argumento `scalar` precisa ser um número que, quando multiplicado por um
634+ `float`, produz outro `float` (porque nossa classe `Vector` armazena
635+ um `array` de números de ponto flutuante). Então um `complex` não serve,
636+ mas pode ser um `int`, um `bool` (`bool` é subclasse de `int`)
637+ ou até uma instância de `fractions.Fraction`. No <<ex_vector_v7>>, o método
638+ `+__mul__+` não faz nenhuma checagem de tipos explícita com `scalar`. Em vez
639+ disso, o converte para `float`, e devolve `NotImplemented` se a conversão
639640falhar. É mais um exemplo prático de tipagem pato.
640641
641642[[ex_vector_v7]]
@@ -738,7 +739,7 @@ na biblioteca padrão, mas são reconhecidos pelo interpretador desde o Python
738739`@` em nossas classes. O analisador sintático de Python foi modificado para
739740aceitar o novo operador, pois `a @ b` era um erro de sintaxe até o Python 3.4.
740741
741- Os testes simples abaixo mostram como `@` deve funcionar com instâncias de `Vector`:
742+ Estes testes simples mostram como `@` deve funcionar com instâncias de `Vector`:
742743
743744[source, python]
744745----
@@ -769,7 +770,7 @@ O <<ex_vector_v7_matmul>> mostra o código dos métodos especiais relevantes na
769770
770771
771772[[ex_vector_v7_matmul]]
772- .vector_v7.py: operator `@` methods
773+ .vector_v7.py: métodos para o operador `@`
773774====
774775[source, python]
775776----
@@ -799,15 +800,15 @@ class Vector:
799800[TIP]
800801====
801802
802- Desde o Python 3.10, a função embutida `zip` aceita um argumento opcional apenas
803- nomeado, `strict`. Quando `strict=True`, a função gera um `ValueError` se os
804- iteráveis têm tamanhos diferentes . O default é `False`. Esse novo comportamento
805- estrito se alinha à filosofia de https://fpy.li/16-8[_falhar rápido_ ] de Python.
803+ Desde o Python 3.10, a função `zip` aceita um argumento opcional apenas
804+ nomeado, `strict`. Quando `strict=True`, a função gera um `ValueError`
805+ se um iterável termina antes de outro . O default é `False`. Este comportamento
806+ se alinha à filosofia de https://fpy.li/16-8[«falhar rápido» ] de Python.
806807No <<ex_vector_v7_matmul>>, poderíamos trocar o `if` interno por um `try/except
807- ValueError` e acrescentar `strict=True` à invocação de `zip`. Neste caso específico,
808- como `self` e `other` suportam `+__len__+`,
809- considero o teste explícito com `if` melhor por ser mais claro .
810- O `strict` é mais valioso quando o `zip` vai lidar com iteradores,
808+ ValueError` e acrescentar `strict=True` à invocação de `zip`.
809+ Neste caso específico, como `self` e `other` suportam `+__len__+`,
810+ prefiro o teste explícito com `if`, por clareza .
811+ O `strict` é mais útil quando o `zip` vai lidar com iteradores,
811812que não têm `+__len__+`.
812813
813814====
@@ -873,15 +874,6 @@ não existem métodos reversos com o prefixo `+__r…__+`.
873874Os mesmos métodos são usados para invocações diretas ou reversas do
874875operador. As regras estão resumidas na <<reversed_rich_comp_op_tbl>>.
875876
876- Por exemplo, no caso de `==`, tanto a chamada direta quanto a reversa invocam
877- `+__eq__+`, apenas permutando os argumentos. Uma chamada direta a `+__gt__+`
878- pode ser seguida de uma chamada reversa a `+__lt__+`, com os argumentos
879- permutados.
880-
881- Nos casos de `==` e `!=`, se o método não existe no segundo operando,
882- ou devolve `NotImplemented`, os métodos correspondentes `+__eq__+` e `+__ne__+`
883- herdados da classe `object` comparam os IDs dos objetos, então não ocorre `TypeError`.
884-
885877[[reversed_rich_comp_op_tbl]]
886878.Comparação rica: a última coluna mostra o resultado quando as tentativas devolvem `NotImplemented` ou o operando não implementa o método.
887879[options="header"]
@@ -896,6 +888,15 @@ herdados da classe `object` comparam os IDs dos objetos, então não ocorre `Typ
896888| | `a {lte} b` | `+a.__le__(b)+` | `+b.__ge__(a)+` | Levanta `TypeError`
897889|=================================================================================================
898890
891+ Por exemplo, no caso de `==`, tanto a chamada direta quanto a reversa invocam
892+ `+__eq__+`, apenas permutando os argumentos. Uma chamada direta a `+__gt__+`
893+ pode ser seguida de uma chamada reversa a `+__lt__+`, com os argumentos
894+ permutados.
895+
896+ Nos casos de `==` e `!=`, se o método não existe no segundo operando,
897+ ou devolve `NotImplemented`, os métodos correspondentes `+__eq__+` e `+__ne__+`
898+ herdados da classe `object` comparam os IDs dos objetos, então não ocorre `TypeError`.
899+
899900Considerando estas regras, vamos revisar e aperfeiçoar o comportamento do método
900901`+Vector.__eq__+`, escrito assim no __vector_v5.py__ (<<ex_vector_v5>> do <<ch_seq_methods>>):
901902
@@ -1262,10 +1263,10 @@ Podemos resumir toda a ideia dos operadores de atribuição interna comparando
12621263as instruções `return` que devolvem os resultados em `+__add__+` e em
12631264`+__iadd__+` no <<ex_addable_bingo>>:
12641265
1265- `+__add__+`: : O resultado é computado chamando o construtor `AddableBingoCage`
1266+ ** `+__add__+`** : O resultado é computado chamando o construtor `AddableBingoCage`
12661267para criar uma nova instância.
12671268
1268- `+__iadd__+`: : O resultado é `self`, após ele ter sido modificado.
1269+ ** `+__iadd__+`** : O resultado é `self`, após ele ter sido modificado.
12691270
12701271Uma última observação sobre o <<ex_addable_bingo>>: não implementei `+__radd__+`
12711272em `AddableBingoCage`, porque não há necessidade. O método direto `+__add__+` só
@@ -1319,8 +1320,8 @@ usamos um teste `isinstance` explícito. Há prós e contras nas duas abordagens
13191320tipagem pato é mais flexível, mas a checagem explícita de tipo é mais
13201321previsível.
13211322
1322- De modo geral, bibliotecas deveriam tirar proveito da tipagem pato—abrindo a
1323- porta para objetos de outros tipos, desde que eles suportem as operações
1323+ De modo geral, bibliotecas devem aproveitar a tipagem pato para lidar objetos
1324+ de diferentes tipos, desde que eles suportem as operações
13241325necessárias. Entretanto, o algoritmo de despacho de operadores de Python pode
13251326produzir mensagens de erro enganosas ou resultados inesperados quando combinado
13261327com a tipagem pato. Por essa razão, a disciplina da checagem de tipos com
0 commit comments