{ "metadata": { "name": "Capitulo23_Metaclasses" }, "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 23: Metaclasses\n", "=============================\n", "_____________________________\n", "Em uma linguagem orientada a objeto aonde (quase) tudo s\u00e3o objetos e todo o objeto tem uma classe, \u00e9 natural que as classes tamb\u00e9m sejam tratadas como objetos.\n", "\n", "Metaclasse \u00e9 uma classe cujas as inst\u00e2ncias s\u00e3o classes, sendo assim, a metaclasse define o comportamento das classes derivadas a partir dela. Em Python, a classe *type* \u00e9 uma metaclasse e pode ser usada para criar novas metaclasses.\n", "\n", "Exemplo de metaclasse criada a partir de *type*:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "class Singleton(type):\n", " \"\"\"\n", " Metaclasse Singleton\n", " \"\"\"\n", "\n", " def __init__(cls, name, bases, dic):\n", "\n", " type.__init__(cls, name, bases, dic)\n", "\n", " # Retorna o pr\u00f3prio objeto na c\u00f3pia\n", " def __copy__(self):\n", " return self\n", "\n", " # Retorna o pr\u00f3prio objeto na c\u00f3pia recursiva\n", " def __deepcopy__(self, memo=None):\n", " return self\n", "\n", " cls.__copy__ = __copy__\n", " cls.__deepcopy__ = __deepcopy__\n", "\n", " def __call__(cls, *args, **kwargs):\n", "\n", " # Chamada que cria novos objetos,\n", " # aqui retorna sempre o mesmo\n", " try:\n", " return cls.__instance\n", "\n", " # Se __instance n\u00e3o existir, ent\u00e3o crie...\n", " except AttributeError:\n", "\n", " # A fun\u00e7\u00e3o super() pesquisa na MRO\n", " # a partir de Singleton\n", " cls.__instance = super(Singleton,\n", " cls).__call__(*args, **kwargs)\n", " return cls.__instance\n", "\n", "\n", "import MySQLdb\n", "\n", "\n", "class Con(object):\n", " \"\"\"\n", " Classe de conex\u00e3o \u00fanica\n", " \"\"\"\n", "\n", " # Define a metaclasse desta classe\n", " __metaclass__ = Singleton\n", "\n", " def __init__(self):\n", "\n", " # Cria uma conex\u00e3o e um cursor\n", " con = MySQLdb.connect(user='root', passwd='root123')\n", " self.db = con.cursor()\n", " # Sempre ser\u00e1 usado o mesmo\n", " # objeto de cursor\n", "\n", "\n", "class Log(object):\n", " \"\"\"\n", " Classe de log\n", " \"\"\"\n", "\n", " # Define a metaclasse desta classe\n", " __metaclass__ = Singleton\n", "\n", " def __init__(self):\n", "\n", " # Abre o arquivo de log para escrita\n", " self.log = file('msg.log', 'w')\n", " # Sempre ser\u00e1 usado o mesmo\n", " # objeto de arquivo\n", "\n", " def write(self, msg):\n", "\n", " print msg\n", " # Acrescenta as mensagens no arquivo\n", " self.log.write(str(msg) + '\\n')\n", "\n", "\n", "# Conex\u00e3o 1\n", "con1 = Con()\n", "Log().write('con1 id = %d' % id(con1))\n", "con1.db.execute('show processlist')\n", "Log().write(con1.db.fetchall())\n", "\n", "# Conex\u00e3o 2\n", "con2 = Con()\n", "Log().write('con2 id = %d' % id(con2))\n", "con2.db.execute('show processlist')\n", "Log().write(con2.db.fetchall())\n", "\n", "import copy\n", "\n", "# Conex\u00e3o 3\n", "con3 = copy.copy(con1)\n", "Log().write('con3 id = %d' % id(con3))\n", "con3.db.execute('show processlist')\n", "Log().write(con2.db.fetchall())" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "con1 id = 63759504\n", "((87L, 'root', 'localhost', None, 'Sleep', 68L, '', None), (88L, 'root', 'localhost', None, 'Query', 1L, None, 'show processlist'))" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "con2 id = 63759504\n", "((87L, 'root', 'localhost', None, 'Sleep', 68L, '', None), (88L, 'root', 'localhost', None, 'Query', 0L, None, 'show processlist'))\n", "con3 id = 63759504\n", "((87L, 'root', 'localhost', None, 'Sleep', 68L, '', None), (88L, 'root', 'localhost', None, 'Query', 0L, None, 'show processlist'))\n" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "A partir da vers\u00e3o 2.6, o Python passou a suportar *Abstract Base Classes*, que s\u00e3o metaclasses que permitem for\u00e7ar a implementa\u00e7\u00e3o de determinados m\u00e9todos e atributos das classes e subclasses derivadas.\n", "\n", "O m\u00f3dulo *abc* define a metaclasse *ABCMeta* e os decoradores *abstractmethod* e abstractproperty que identificam os m\u00e9todos e propriedades que devem ser implementadas." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from abc import ABCMeta, abstractmethod\n", "\n", "\n", "class Nave(object):\n", "\n", " __metaclass__ = ABCMeta\n", "\n", " @abstractmethod\n", " def mover(self, x0, x1, v):\n", "\n", " # Sem implementa\u00e7\u00e3o\n", " pass\n", "\n", "\n", "class Zeppelin(Nave):\n", "\n", " def mover(self, x0, x1, v):\n", " \"\"\"\n", " A partir da posi\u00e7\u00e3o inicial e final e da velocidade\n", " calcula o tempo da viagem\n", " \"\"\"\n", " d = x1 - x0\n", " t = v * d\n", " return t\n", "\n", "\n", "class Hovercraft(Nave):\n", "\n", " # Esta classe n\u00e3o implementa o m\u00e9todo mover()\n", " pass\n", "\n", "z = Zeppelin()\n", "\n", "# Objeto que n\u00e3o implementa o m\u00e9todo abstrato\n", "# Isso causa uma exce\u00e7\u00e3o TypeError\n", "h = Hovercraft()" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "Can't instantiate abstract class Hovercraft with abstract methods mover", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 34\u001b[0m \u001b[1;31m# Objeto que n\u00e3o implementa o m\u00e9todo abstrato\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 35\u001b[0m \u001b[1;31m# Isso causa uma exce\u00e7\u00e3o TypeError\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 36\u001b[1;33m \u001b[0mh\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mHovercraft\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: Can't instantiate abstract class Hovercraft with abstract methods mover" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "A avalia\u00e7\u00e3o da exist\u00eancia dos m\u00e9todos abstratos ocorre durante o processo de cria\u00e7\u00e3o de objetos a partir da classe, por\u00e9m esta n\u00e3o leva em conta os par\u00e2metros dos m\u00e9todos." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "" ], "output_type": "pyout", "prompt_number": 1, "text": [ "" ] } ], "prompt_number": 1 } ], "metadata": {} } ] }