{ "metadata": { "name": "Capitulo22_Sobrecarga_de_operadores" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "[Python para Desenvolvedores](http://ricardoduarte.github.io/python-para-desenvolvedores/#conteudo)\n", "===================================\n", "2ª edi\u00e7\u00e3o, revisada e ampliada\n", "-----------------------------------\n", "\n", "Cap\u00edtulo 22: Sobrecarga de operadores\n", "=============================\n", "_____________________________\n", "No Python, o comportamento dos operadores \u00e9 definido por m\u00e9todos especiais, por\u00e9m tais m\u00e9todos s\u00f3 podem ser alterados nas classes abertas. Por conven\u00e7\u00e3o, os m\u00e9todos especiais t\u00eam nomes que come\u00e7am e terminam com \"`__`\".\n", "\n", "Lista de operadores e os m\u00e9todos correspondentes:\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
OperadorM\u00e9todoOpera\u00e7\u00e3o
+__add__adi\u00e7\u00e3o
-__sub__subtra\u00e7\u00e3o
*__mul__multiplica\u00e7\u00e3o
/__div__divis\u00e3o
//__floordiv__divis\u00e3o inteira
%__mod__m\u00f3dulo
**__pow__pot\u00eancia
+__pos__positivo
-__neg__negativo
<__lt__menor que
>__gt__maior que
<=__le__menor ou igual a
>=__ge__maior ou igual a
==__eq__igual a
!=__ne__diferente de
<<__lshift__deslocamento para esquerda
>>__rshift__deslocamento para direita
&__and__e bit-a-bit
|__or__ou bit-a-bit
^__xor__ou exclusivo bit-a-bit
~__inv__invers\u00e3o
\n", "
\n", "Exemplo:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# A classe String deriva de str\n", "class String(str):\n", "\n", " def __sub__(self, s):\n", "\n", " return self.replace(s, '')\n", "\n", "s1 = String('The Lamb Lies Down On Broadway')\n", "s2 = 'Down '\n", "\n", "print '\"%s\" - \"%s\" = \"%s\"' % (s1, s2, s1 - s2)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\"The Lamb Lies Down On Broadway\" - \"Down \" = \"The Lamb Lies On Broadway\"\n" ] } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Observa\u00e7\u00f5es:\n", "\n", "+ A subtra\u00e7\u00e3o definida no c\u00f3digo n\u00e3o \u00e9 comutativa (da mesma forma que a adi\u00e7\u00e3o em strings tamb\u00e9m n\u00e3o \u00e9)\n", "+ A classe *str* n\u00e3o \u00e9 aberta, portanto n\u00e3o \u00e9 poss\u00edvel alterar o comportamento da string padr\u00e3o do Python. Por\u00e9m a classe *String* \u00e9 aberta.\n", "+ A redefini\u00e7\u00e3o de operadores conhecidos pode dificultar a leitura do c\u00f3digo.\n", "\n", "Cole\u00e7\u00f5es\n", "--------\n", "Al\u00e9m de m\u00e9todos especiais para objetos escalares, existem tamb\u00e9m m\u00e9todos especiais para lidar com objetos que funcionam como cole\u00e7\u00f5es (da mesma forma que as listas e os dicion\u00e1rios), possibilitando o acesso aos itens que fazem parte da cole\u00e7\u00e3o.\n", "\n", "Exemplo:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "class Mat(object):\n", " \"\"\"\n", " Matriz esparsa\n", " \"\"\"\n", "\n", " def __init__(self):\n", " \"\"\"\n", " Inicia a matriz\n", " \"\"\"\n", "\n", " self.itens = []\n", " self.default = 0\n", "\n", " def __getitem__(self, xy):\n", " \"\"\"\n", " Retorna o item para X e Y ou default caso contr\u00e1rio\n", " \"\"\"\n", "\n", " i = self.index(xy)\n", " if i is None:\n", " return self.default\n", "\n", " return self.itens[i][-1]\n", "\n", "\n", " def __setitem__(self, xy, data=0):\n", " \"\"\"\n", " Cria novo item na matriz\n", " \"\"\"\n", "\n", " i = self.index(xy)\n", " if i is not None:\n", " self.itens.pop(i)\n", " self.itens.append((xy, data))\n", "\n", " def __delitem__(self, xy):\n", " \"\"\"\n", " Remove um item da matriz\n", " \"\"\"\n", "\n", " i = self.index(xy)\n", " if i is None:\n", " return self.default\n", " return self.itens.pop(i)\n", "\n", " def __getslice__(self, x1, x2):\n", " \"\"\"\n", " Seleciona linhas da matriz\n", "\n", " \"\"\"\n", "\n", " r = []\n", " for x in xrange(x1, x2 + 1):\n", " r.append(self.row(x))\n", "\n", " return r\n", "\n", " def index(self, xy):\n", "\n", " for i, item in enumerate(self.itens):\n", " if xy == item[0]:\n", " return i\n", " else:\n", " return None\n", "\n", " def dim(self):\n", " \"\"\"\n", " Retorna as dimens\u00f5es atuais da matriz\n", " \"\"\"\n", " x = y = 0\n", " for xy, data in self.itens:\n", " if xy[0] > x: x = xy[0]\n", " if xy[1] > y: y = xy[1]\n", "\n", " return x, y\n", "\n", " def keys(self):\n", " \"\"\"\n", " Retorna as coordenadas preenchidas\n", " \"\"\"\n", "\n", " return [xy for xy, data in self.itens]\n", "\n", " def values(self):\n", " \"\"\"\n", " Retorna os valores preenchidos\n", " \"\"\"\n", "\n", " return [data for xy, data in self.itens]\n", "\n", " def row(self, x):\n", " \"\"\"\n", " Retorna a linha especificada\n", " \"\"\"\n", "\n", " X, Y = self.dim()\n", " r = []\n", " for y in xrange(1, Y + 1):\n", " r.append(self[x,y])\n", "\n", " return r\n", "\n", " def col(self, y):\n", " \"\"\"\n", " Retorna a coluna especificada\n", " \"\"\"\n", "\n", " X, Y = self.dim()\n", " r = []\n", " for x in xrange(1, X + 1):\n", " r.append(self[x,y])\n", "\n", " return r\n", "\n", " def sum(self):\n", " \"\"\"\n", " Calcula o somat\u00f3rio\n", " \"\"\"\n", " return sum(self.values())\n", "\n", " def avg(self):\n", " \"\"\"\n", " Calcula a m\u00e9dia\n", " \"\"\"\n", "\n", " X, Y = self.dim()\n", " return self.sum() / (X * Y)\n", "\n", " def __repr__(self):\n", " \"\"\"\n", " Retorna uma representa\u00e7\u00e3o do objeto como texto\n", " \"\"\"\n", "\n", " r = 'Dim: %s\\n' % repr(self.dim())\n", " X, Y = self.dim()\n", "\n", " for x in xrange(1, X + 1):\n", " for y in xrange(1, Y + 1):\n", " r += ' %s = %3.1f' % (repr((x, y)),\n", " float(self.__getitem__((x, y))))\n", " r += '\\n'\n", " return r\n", "\n", "\n", "if __name__ == '__main__':\n", "\n", " mat = Mat()\n", " print '2 itens preenchidos:'\n", " mat[1, 2] = 3.14\n", " mat[3, 4] = 4.5\n", " print mat\n", "\n", " print 'Troca e remo\u00e7\u00e3o:'\n", " del mat[3, 4]\n", " mat[1, 2] = 5.4\n", " print mat\n", "\n", " print 'Preenchendo a 3\u00aa coluna:'\n", " for i in xrange(1, 4):\n", " mat[i + 1, 3] = i\n", " print mat\n", "\n", " print '3\u00aa coluna:', mat.col(3)\n", " print 'Fatia com 2\u00aa a 3\u00aa linha', mat[2:3]\n", " print 'Somat\u00f3rio:', mat.sum(), 'M\u00e9dia', mat.avg()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "2 itens preenchidos:\n", "Dim: (3, 4)\n", " (1, 1) = 0.0 (1, 2) = 3.1 (1, 3) = 0.0 (1, 4) = 0.0\n", " (2, 1) = 0.0 (2, 2) = 0.0 (2, 3) = 0.0 (2, 4) = 0.0\n", " (3, 1) = 0.0 (3, 2) = 0.0 (3, 3) = 0.0 (3, 4) = 4.5\n", "\n", "Troca e remo\u00e7\u00e3o:\n", "Dim: (1, 2)\n", " (1, 1) = 0.0 (1, 2) = 5.4\n", "\n", "Preenchendo a 3\u00aa coluna:\n", "Dim: (4, 3)\n", " (1, 1) = 0.0 (1, 2) = 5.4 (1, 3) = 0.0\n", " (2, 1) = 0.0 (2, 2) = 0.0 (2, 3) = 1.0\n", " (3, 1) = 0.0 (3, 2) = 0.0 (3, 3) = 2.0\n", " (4, 1) = 0.0 (4, 2) = 0.0 (4, 3) = 3.0\n", "\n", "3\u00aa coluna: [0, 1, 2, 3]\n", "Fatia com 2\u00aa a 3\u00aa linha [[0, 0, 1], [0, 0, 2]]\n", "Somat\u00f3rio: 11.4 M\u00e9dia 0.95\n" ] } ], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "" ], "output_type": "pyout", "prompt_number": 1, "text": [ "" ] } ], "prompt_number": 1 } ], "metadata": {} } ] }