{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Alguns tópicos adicionais sobre classes\n", "\n", "Uma classe, além de definir um novo tipo de dados, é também um objeto, criado quando se define a classe." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class A:\n", " def f(self):\n", " print('Oi')" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "__main__.A" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Se usamos esse objeto como se fosse uma função, um objeto da classe é criado e o método `__init__` é chamado para ele." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = A()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Todos os objetos tem um tipo, que é a classe usada para sua criação." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "__main__.A" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note que a classe inclui o nome do módulo onde ela foi declarada (neste caso, o módulo corrente `__main__`).\n", "\n", "Como a classe também é um objeto, ela também tem um tipo:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "type" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Por sua vez, o tipo de `type` é o próprio `type`:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "type" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(type)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Como classes são objetos, podemos criar atributos nela. Isso é o que ocorre quando definimos um método, que é um atributo da classe que guarda uma função. Mas também podemos colocar variáveis simples." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class B:\n", " def f(self):\n", " print('Olá')\n", " x = 1" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B.x" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B.f" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": true }, "outputs": [], "source": [ "B.x = 2" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B.x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Os atributos definidos na classe são também disponíveis nos objetos dessa classe (da mesma forma que os atributos que são métodos)." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": true }, "outputs": [], "source": [ "b = B()" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Olá\n" ] } ], "source": [ "b.f()" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b.x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Atributos da classe, acessados através de seus objetos, tem o mesmo valor para todos os objetos da classe, ao contrário de atributos do objeto (que são aquelas associados com `self` nos métodos da classe." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class C:\n", " x = 1\n", " def __init__(self):\n", " self.y = 2\n", " def f(self):\n", " print('Hello')" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C.x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O atributo `y` é associado a objetos da classe, e portanto não é acessível pela classe." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [ { "ename": "AttributeError", "evalue": "type object 'C' has no attribute 'y'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mC\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: type object 'C' has no attribute 'y'" ] } ], "source": [ "C.y" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": true }, "outputs": [], "source": [ "c = C()" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.x" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.y" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": true }, "outputs": [], "source": [ "c2 = C()" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c2.x" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c2.y" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": true }, "outputs": [], "source": [ "c2.y = 3" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.y" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": true }, "outputs": [], "source": [ "C.x = 5" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.x" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c2.x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cada objeto em Python tem o seu próprio escopo. Isso significa que podemos acrescentar atributos a qualquer momento em um objeto já existe. Esse novo atributo estará presente apenas nesse objeto, e não em outros objetos da classe." ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": true }, "outputs": [], "source": [ "c2.z = 4" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c2.z" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "collapsed": false }, "outputs": [ { "ename": "AttributeError", "evalue": "'C' object has no attribute 'z'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mz\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'C' object has no attribute 'z'" ] } ], "source": [ "c.z" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Por outro lado, como a classe é também um objeto, podemos acrescentar novos atributos à classe, e eles serão visíveis a todos os objetos da classe." ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "collapsed": true }, "outputs": [], "source": [ "C.t = 7" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "7" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.t" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "7" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c2.t" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "É possível também alterar a função associada com um método, apesar de isso não ser uma prática recomendada." ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello\n" ] } ], "source": [ "c.f()" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "collapsed": true }, "outputs": [], "source": [ "C.f = lambda self: print('Não!')" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Não!\n" ] } ], "source": [ "c.f()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Quando o Python tenta acessar um atributo em um objeto, ele busca primeiro no escopo do objeto; apenas vai procurar no escopo da classe se não for encontrado. Isso significa que um atributo do objeto com mesmo nome do atributo da classe vai esconder o atributo da classe quando acessado através do objeto (mas não ao acessar através da classe)." ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "collapsed": false }, "outputs": [], "source": [ "class D:\n", " x = 1\n", " def __init__(self):\n", " self.x = 2\n", " def getX(self):\n", " print (self.x)" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "collapsed": true }, "outputs": [], "source": [ "d = D()" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2\n" ] } ], "source": [ "d.getX()" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d.x" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "D.x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "No código abaixo, usamos um atributo de classe para contar o número de objetos dessa classe que já foram criados.\n", "\n", "Inicializamos o atributo em 0, e depois, como cada novo objeto criado irá executar o método `__init__`, então basta incrementar esse valor cada vez que o `__init__` for executado." ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class AutoConta:\n", " x = 0\n", " def __init__(self):\n", " AutoConta.x += 1" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "collapsed": false }, "outputs": [], "source": [ "x1 = AutoConta()" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "AutoConta.x" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "collapsed": true }, "outputs": [], "source": [ "lista = [AutoConta() for i in range(10)]" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "11" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "AutoConta.x" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "11" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1.x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Objetos de classes derivada também têm acesso aos atributos da classe base." ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class E(C):\n", " z = 2\n", " def g(self):\n", " print('Aqui')" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "collapsed": true }, "outputs": [], "source": [ "e = E()" ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e.z" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e.x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O atributo `__dict__` pode ser consultado para verificar os atributos de um objeto. Ele é um dicionário com a chave sendo o nome do atributo e o valor sendo o valor do atributo." ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "__main__.A" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(a)" ] }, { "cell_type": "code", "execution_count": 54, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "{}" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.__dict__" ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "mappingproxy({'__dict__': ,\n", " '__doc__': None,\n", " '__module__': '__main__',\n", " '__weakref__': ,\n", " 'f': })" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.__dict__" ] }, { "cell_type": "code", "execution_count": 56, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "{'y': 2}" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.__dict__" ] }, { "cell_type": "code", "execution_count": 57, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "mappingproxy({'__dict__': ,\n", " '__doc__': None,\n", " '__init__': ,\n", " '__module__': '__main__',\n", " '__weakref__': ,\n", " 'f': >,\n", " 't': 7,\n", " 'x': 5})" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C.__dict__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note como os atributos associados ao objeto estão no `__dict__` do objeto, enquanto aqueles associados com a classe (incluindo os métodos), estão no `__dict__` da classe.\n", "\n", "Da mesma forma que podemos criar novos atributos, podemos também apagar atributos existentes, usando o comando `del`." ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "collapsed": true }, "outputs": [], "source": [ "del C.t" ] }, { "cell_type": "code", "execution_count": 59, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "mappingproxy({'__dict__': ,\n", " '__doc__': None,\n", " '__init__': ,\n", " '__module__': '__main__',\n", " '__weakref__': ,\n", " 'f': >,\n", " 'x': 5})" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C.__dict__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Classes base abstratas e métodos abstratos\n", "\n", "Em algumas situações, queremos definir um método em uma classe base que não tem nenhuma implementação específica nessa classe, mas terá apenas implementação válida nas classes derivadas.\n", "\n", "Por exemplo, o código abaixo define um método `h` que faz uso de um método `m` que não foi definido." ] }, { "cell_type": "code", "execution_count": 60, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Base:\n", " def __init__(self):\n", " print('Criando base')\n", " def f(self):\n", " print('f de Base')\n", " def h(self):\n", " self.m()" ] }, { "cell_type": "code", "execution_count": 61, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Derivada1(Base):\n", " def g(self):\n", " print('g de Derivada1')" ] }, { "cell_type": "code", "execution_count": 62, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Derivada2(Base):\n", " def f(self):\n", " print('f de Derivada2')" ] }, { "cell_type": "code", "execution_count": 63, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Derivada3(Base):\n", " def f(self):\n", " Base.f(self)\n", " print('f de Derivada3')" ] }, { "cell_type": "code", "execution_count": 64, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Derivada4(Base):\n", " def m(self):\n", " print('m de Derivada4')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Das classes acima, apenas a `Derivada4` é completa, pois nenhuma das outras define `m`, e portanto não podemos executar `h` sobre objetos dessas classes." ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Criando base\n" ] } ], "source": [ "b = Base()" ] }, { "cell_type": "code", "execution_count": 66, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f de Base\n" ] } ], "source": [ "b.f()" ] }, { "cell_type": "code", "execution_count": 67, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Criando base\n" ] } ], "source": [ "d1 = Derivada1()" ] }, { "cell_type": "code", "execution_count": 68, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f de Base\n" ] } ], "source": [ "d1.f()" ] }, { "cell_type": "code", "execution_count": 69, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "g de Derivada1\n" ] } ], "source": [ "d1.g()" ] }, { "cell_type": "code", "execution_count": 70, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Criando base\n" ] } ], "source": [ "d2 = Derivada2()" ] }, { "cell_type": "code", "execution_count": 71, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f de Derivada2\n" ] } ], "source": [ "d2.f()" ] }, { "cell_type": "code", "execution_count": 72, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Criando base\n" ] } ], "source": [ "d3 = Derivada3()" ] }, { "cell_type": "code", "execution_count": 73, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f de Base\n", "f de Derivada3\n" ] } ], "source": [ "d3.f()" ] }, { "cell_type": "code", "execution_count": 74, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Criando base\n" ] } ], "source": [ "d4 = Derivada4()" ] }, { "cell_type": "code", "execution_count": 75, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f de Base\n" ] } ], "source": [ "d4.f()" ] }, { "cell_type": "code", "execution_count": 76, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "m de Derivada4\n" ] } ], "source": [ "d4.h()" ] }, { "cell_type": "code", "execution_count": 77, "metadata": { "collapsed": false }, "outputs": [ { "ename": "AttributeError", "evalue": "'Base' object has no attribute 'm'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m\u001b[0m in \u001b[0;36mh\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'f de Base'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mm\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'Base' object has no attribute 'm'" ] } ], "source": [ "b.h()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dizemos nesse caso que a classe base é *abstrata* e o método `m` é um *método abstrato*.\n", "\n", "O ideal é indicar isso claramente no código, pois dessa forma o Python pode impedir que criemos objetos incompletos. Isso é feito com auxílio do modulo `abc` (de *__a__bstract __b__ase __c__lass*)." ] }, { "cell_type": "code", "execution_count": 78, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from abc import ABCMeta, abstractmethod" ] }, { "cell_type": "code", "execution_count": 79, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Base(metaclass=ABCMeta):\n", " \"\"\"Esta é uma classe base usada para demonstração\n", " de classes base abstratas\"\"\"\n", " def __init__(self):\n", " \"Para criar objeto base, apenas mostramos mensagem\"\n", " print('Criando base')\n", " def f(self):\n", " \"A função f não é muito criativa\"\n", " print('f de Base')\n", " def h(self):\n", " \"A função h precisa de um método abstrato m()\"\n", " self.m()\n", " @abstractmethod\n", " def m(self):\n", " \"Nenhuma implementação para a classe base\"\n", " pass" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O uso de `metaclass=ABCMeta` na lista de classes base indica que a classe definida é uma classe base abstrata.\n", "\n", "O uso de `@abstractmethod` antes da definição do método `m` indica que esse é um método abstrato.\n", "\n", "Com essa definição, não é possível criar objetos da classe `Base`." ] }, { "cell_type": "code", "execution_count": 80, "metadata": { "collapsed": false }, "outputs": [ { "ename": "TypeError", "evalue": "Can't instantiate abstract class Base with abstract methods m", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mBase\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: Can't instantiate abstract class Base with abstract methods m" ] } ], "source": [ "b = Base()" ] }, { "cell_type": "code", "execution_count": 81, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Derivada1(Base):\n", " def g(self):\n", " print('g de Derivada1')" ] }, { "cell_type": "code", "execution_count": 82, "metadata": { "collapsed": false }, "outputs": [ { "ename": "TypeError", "evalue": "Can't instantiate abstract class Derivada1 with abstract methods m", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0md1\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mDerivada1\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: Can't instantiate abstract class Derivada1 with abstract methods m" ] } ], "source": [ "d1 = Derivada1()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Para criar objetos, precisamos definir uma classe derivada que implementa o método abstrato `m`." ] }, { "cell_type": "code", "execution_count": 83, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Derivada4(Base):\n", " def m(self):\n", " \"Este método é muito interessante\"\n", " print('m de Derivada4')" ] }, { "cell_type": "code", "execution_count": 84, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Criando base\n" ] } ], "source": [ "d4 = Derivada4()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Documentação\n", "\n", "Na declaração de `Base`, incluimos também, como primeiro elemento na classe, uma string. Neste caso, essa string é considerada documentação da classe, e pode ser acessada por programa que analisam automaticamente o código.\n", "\n", "O mesmo pode ser feito em módulos e definições de funções: Basta incluir uma string como primeiro elemento na definição.\n", "\n", "O nome técnico para essas string é *docstring*, e elas podem ser acessadas pelo atributo `__doc__`." ] }, { "cell_type": "code", "execution_count": 85, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Esta é uma classe base usada para demonstração\n", " de classes base abstratas\n" ] } ], "source": [ "print(Base.__doc__)" ] }, { "cell_type": "code", "execution_count": 86, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A função h precisa de um método abstrato m()\n" ] } ], "source": [ "print(Base.h.__doc__)" ] }, { "cell_type": "code", "execution_count": 87, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on function h in module __main__:\n", "\n", "h(self)\n", " A função h precisa de um método abstrato m()\n", "\n" ] } ], "source": [ "help(Base.h)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Sobrecarga de operadores\n", "\n", "O Python permite definir o que deve ser executado quando um operador for usado em conjunto com os objetos da classe.\n", "\n", "Por exemplo, ao encontrar o código `a + b` o Python tentará executar um código da seguinte forma `a.__add__(b)`. Portanto, se definirmos o método `__add__` para a classe do objeto `a`, podemos definir como esses tipos de objetos fazem somas.\n", "\n", "A classe abaixo define uma operação de soma que não é matematicamente correta." ] }, { "cell_type": "code", "execution_count": 88, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class NumerosEtilicos:\n", " def __init__(self, val):\n", " self.__val = val\n", " def getval(self):\n", " return self.__val\n", " def setval(self, val):\n", " self.__val = val\n", " def __add__(self, outro):\n", " return self.__val + outro.__val / 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Com essa definição, podemos executar o método pelos forma tradicional:" ] }, { "cell_type": "code", "execution_count": 89, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = NumerosEtilicos(2); b = NumerosEtilicos(8)" ] }, { "cell_type": "code", "execution_count": 90, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(2, 8)" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.getval(), b.getval()" ] }, { "cell_type": "code", "execution_count": 91, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "6.0" ] }, "execution_count": 91, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.__add__(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ou podemos simplesmente usar o operador `+`:" ] }, { "cell_type": "code", "execution_count": 92, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "6.0" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Operadores aritiméticos" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Diversos operadores podem ser sobrecarregados em Python.\n", "\n", "No caso de operadores aritméticos, podemos definir para cada um três operações. Para o exemplo do `+`, temos as seguintes possibilidades (sendo `obj` um objeto de classe e `x` o objeto que queremos somar com `obj`):\n", "\n", " obj + x\n", " x + obj\n", " obj += x\n", "\n", "Podemos definir as operações separadamente (se necessário) para cada um desses casos, com os métodos `__add__`, `__radd__` e `__iadd__`, respectivamente." ] }, { "cell_type": "code", "execution_count": 93, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Inutil:\n", " def __init__(self, ini):\n", " self.val = ini\n", " def value(self):\n", " return self.val\n", " def setvalue(self, newv):\n", " self.val = newv\n", " def __add__(self, other):\n", " print('Inutil.__add__')\n", " if isinstance(other, Inutil):\n", " return Inutil(self.val + other.val)\n", " else:\n", " return Inutil(self.val + other)\n", " def __radd__(self, other):\n", " print('Inutil.__radd__')\n", " return self.__add__(other)\n", " def __iadd__(self, other):\n", " print('Inutil.__iadd__')\n", " if isinstance(other, Inutil):\n", " self.val += other.val\n", " else:\n", " self.val += other\n", " return self\n", " def __sub__(self, other):\n", " if isinstance(other, Inutil):\n", " return Inutil(self.val - other.val)\n", " else:\n", " return Inutil(self.val - other)\n", " def __rsub__(self, other):\n", " if isinstance(other, Inutil):\n", " return Inutil(other.val - self.val)\n", " else:\n", " return Inutil(other - self.val)\n", " def __isub__(self, other):\n", " print('Inutil.__isub__')\n", " if isinstance(other, Inutil):\n", " self.val -= other.val\n", " else:\n", " self.val -= other\n", " return self" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Veja as mensagens nas execuções abaixo, para entender qual método é chamado em qual situação (veja o código acima)." ] }, { "cell_type": "code", "execution_count": 94, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = Inutil(5); b = Inutil(3)" ] }, { "cell_type": "code", "execution_count": 95, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Inutil.__add__\n" ] } ], "source": [ "c = a + b" ] }, { "cell_type": "code", "execution_count": 96, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "8" ] }, "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.value()" ] }, { "cell_type": "code", "execution_count": 97, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Inutil.__add__\n" ] } ], "source": [ "d = a + 3" ] }, { "cell_type": "code", "execution_count": 98, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "8" ] }, "execution_count": 98, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d.value()" ] }, { "cell_type": "code", "execution_count": 99, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Inutil.__radd__\n", "Inutil.__add__\n" ] } ], "source": [ "e = 3 + a" ] }, { "cell_type": "code", "execution_count": 100, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "8" ] }, "execution_count": 100, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e.value()" ] }, { "cell_type": "code", "execution_count": 101, "metadata": { "collapsed": true }, "outputs": [], "source": [ "c = a - b" ] }, { "cell_type": "code", "execution_count": 102, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 102, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.value()" ] }, { "cell_type": "code", "execution_count": 103, "metadata": { "collapsed": true }, "outputs": [], "source": [ "d = a - 2" ] }, { "cell_type": "code", "execution_count": 104, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 104, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d.value()" ] }, { "cell_type": "code", "execution_count": 105, "metadata": { "collapsed": true }, "outputs": [], "source": [ "e = 2 - b" ] }, { "cell_type": "code", "execution_count": 106, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "-1" ] }, "execution_count": 106, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e.value()" ] }, { "cell_type": "code", "execution_count": 107, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Inutil.__iadd__\n" ] } ], "source": [ "a += 4" ] }, { "cell_type": "code", "execution_count": 108, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 108, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.value()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Uma das características do `__iadd__` que o diferencia do `__add__` é que ele em geral não cria um novo objeto (a exceção é quando o objeto é de um tipo imutável, como string ou int, onde um novo objeto deve ser criado)." ] }, { "cell_type": "code", "execution_count": 109, "metadata": { "collapsed": true }, "outputs": [], "source": [ "b = a" ] }, { "cell_type": "code", "execution_count": 110, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 110, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b is a" ] }, { "cell_type": "code", "execution_count": 111, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Inutil.__iadd__\n" ] } ], "source": [ "a += 1" ] }, { "cell_type": "code", "execution_count": 112, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 112, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b is a" ] }, { "cell_type": "code", "execution_count": 113, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Inutil.__add__\n" ] } ], "source": [ "b = b + a" ] }, { "cell_type": "code", "execution_count": 114, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 114, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b is a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Indexação" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Um outro operador que pode ser definido para suas classes é o de indexação, chamado quando usamos o objeto da forma `obj[i]`. O método a ser implementado se chama `__getitem__` e deve receber o ítem a ser retornado.\n", "\n", "O caso mais simples é quando queremos apenas indexar com um valor, como no caso da classe abaixo, que representa uma lista com os quadrados dos valores de `0` a `maximo - 1`." ] }, { "cell_type": "code", "execution_count": 115, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Quadrados:\n", " def __init__(self, maximo):\n", " self.maximo = maximo\n", " def __getitem__(self, i):\n", " if i < 0 or i >= self.maximo: raise IndexError()\n", " return i ** 2" ] }, { "cell_type": "code", "execution_count": 116, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 1 4 9 16 25 36 49 64 81 " ] } ], "source": [ "q = Quadrados(10)\n", "for i in range(10): print(q[i],end=' ')" ] }, { "cell_type": "code", "execution_count": 117, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(1, 0, 81)" ] }, "execution_count": 117, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q[1], q[0], q[9]" ] }, { "cell_type": "code", "execution_count": 118, "metadata": { "collapsed": false }, "outputs": [ { "ename": "IndexError", "evalue": "", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mq\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, i)\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmaximo\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmaximo\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__getitem__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m>=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmaximo\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mIndexError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m**\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mIndexError\u001b[0m: " ] } ], "source": [ "q[10]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Por ter o método `__getitem__`, os objetos do tipo `Quadrados` podem ser usados como uma lista em operações `for`." ] }, { "cell_type": "code", "execution_count": 119, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "1\n", "4\n", "9\n", "16\n", "25\n", "36\n", "49\n", "64\n", "81\n" ] } ], "source": [ "for x in q:\n", " print(x)" ] }, { "cell_type": "code", "execution_count": 120, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "1\n", "4\n", "9\n", "16\n", "25\n", "36\n", "49\n", "64\n", "81\n" ] } ], "source": [ "for x in (i ** 2 for i in range(10)):\n", " print(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Se quisermos alterar o valor de um índice, devemos usar o `__setitem__`.\n", "\n", "Esse método não faz sentido para o objeto de quadrados, então não o definimos, o que faz com que atribuições sejam proibidas." ] }, { "cell_type": "code", "execution_count": 121, "metadata": { "collapsed": false }, "outputs": [ { "ename": "TypeError", "evalue": "'Quadrados' object does not support item assignment", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mq\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'Quadrados' object does not support item assignment" ] } ], "source": [ "q[2] = 5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vejamos um exemplo que possibilita alteração, na classe abaixo que guarda o valor absoluto dos elementos inseridos." ] }, { "cell_type": "code", "execution_count": 122, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class ValoresAbsolutos:\n", " def __init__(self, tamanho):\n", " self.__valores = [0 for i in range(tamanho)]\n", " def __getitem__(self, i):\n", " return self.__valores[i]\n", " def __setitem__(self, i, val):\n", " self.__valores[i] = abs(val)" ] }, { "cell_type": "code", "execution_count": 123, "metadata": { "collapsed": true }, "outputs": [], "source": [ "va = ValoresAbsolutos(5)" ] }, { "cell_type": "code", "execution_count": 124, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[0, 0, 0, 0, 0]" ] }, "execution_count": 124, "metadata": {}, "output_type": "execute_result" } ], "source": [ "va[0:5]" ] }, { "cell_type": "code", "execution_count": 125, "metadata": { "collapsed": true }, "outputs": [], "source": [ "va[3] = -4; va[1] = 10" ] }, { "cell_type": "code", "execution_count": 126, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[0, 10, 0, 4, 0]" ] }, "execution_count": 126, "metadata": {}, "output_type": "execute_result" } ], "source": [ "va[0:5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O código anterior nos lembra que as listas de Python aceitam indexação com faixas de índices (denominados *slices*).\n", "\n", "Para permitir indexação com *slices* na sua classe, o seu método `__getitem__` deve saber lidar com um objeto do tipo `slice` sendo passado como índice ao invés de um inteiro.\n", "\n", "Os objetos do tipo `slice` possuem atributos `start`, `stop` e `step` que definem os valores do slice (similares aos parâmetros de `range`). Os valores desses atributos serão `None` se não forem especificados (por exemplo, usando `[1:10:2]` teremos `start=1`, `stop=10` e `step=2`; com `[:10]` teremos `start=None`, `stop=10` e `step=None`.\n", "\n", "No exemplo abaixo, redefinimos `Quadrados` para aceitar slices." ] }, { "cell_type": "code", "execution_count": 127, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Quadrados:\n", " def __init__(self, maximo):\n", " self.maximo = maximo\n", " def __getitem__(self, i):\n", " if isinstance(i, slice): # Se recebi um slice, pega elementos\n", " # Cuida dos None\n", " inicio = i.start if i.start else 0\n", " final = i.stop if i.stop else self.maximo\n", " passo = i.step if i.step else 1\n", " # Cuida dos negativos\n", " if inicio < 0: inicio = self.maximo + inicio\n", " if final < 0: final = self.maximo + final\n", " # Retorna lista com valores pedidos\n", " return [x ** 2 for x in range(inicio, final, passo)]\n", " else:\n", " if i < 0 or i >= self.maximo: raise IndexError()\n", " return i ** 2" ] }, { "cell_type": "code", "execution_count": 128, "metadata": { "collapsed": true }, "outputs": [], "source": [ "q = Quadrados(10)" ] }, { "cell_type": "code", "execution_count": 129, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[0, 1, 4, 9, 16, 25, 36, 49, 64]" ] }, "execution_count": 129, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = list(i**2 for i in range(10))\n", "m[:-1]" ] }, { "cell_type": "code", "execution_count": 130, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]" ] }, "execution_count": 130, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[q[i] for i in range(10)]" ] }, { "cell_type": "code", "execution_count": 131, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[1, 4]" ] }, "execution_count": 131, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q[1:3]" ] }, { "cell_type": "code", "execution_count": 132, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[0, 1, 4, 9, 16, 25, 36, 49, 64]" ] }, "execution_count": 132, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q[:-1]" ] }, { "cell_type": "code", "execution_count": 133, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[0, 4, 16, 36, 64]" ] }, "execution_count": 133, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q[::2]" ] }, { "cell_type": "code", "execution_count": 134, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 134, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q[2]" ] }, { "cell_type": "code", "execution_count": 135, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[25, 36, 49, 64]" ] }, "execution_count": 135, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q[-5:-1]" ] }, { "cell_type": "code", "execution_count": 136, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[25, 16, 9, 4]" ] }, "execution_count": 136, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q[-5:1:-1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python [default]", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.2" } }, "nbformat": 4, "nbformat_minor": 0 }